Skip to content

coding-agents (Pi): beforeAgentStart replaces the whole system prompt, so other extensions' prompt sections are dropped #4841

Description

@tahabakhit

Bug Description

In Pi, createPiHooks().beforeAgentStart returns { systemPrompt: event.systemPrompt + injection }. Pi treats a returned systemPrompt as a full replacement of the prompt for that run, and from then on it ignores event.systemPromptOptions.sections. So a section added by any extension whose before_agent_start handler runs after Hindsight's is dropped, on every turn where Hindsight injects memory.

I hit this with two mode extensions that add a prompt section while the mode is on. With Hindsight loaded, the modes showed as on, but their text never reached the model. With HINDSIGHT_DISABLE_HOOKS=1 it came back.

Code:

return { systemPrompt: `${event.systemPrompt}\n\n${injection}` };

Steps to Reproduce

No Hindsight server needed. Two stub extensions:

// force.ts: what the Hindsight Pi hook does
export default function (pi) {
  pi.on("before_agent_start", (event) => ({ systemPrompt: `${event.systemPrompt}\n\n<memory>turn 1</memory>` }));
}
// section.ts: any extension that adds a prompt section
export default function (pi) {
  pi.on("before_agent_start", (event) => {
    event.systemPromptOptions.sections.other_ext = "SECTION-MARKER";
  });
}
  1. pi --no-extensions -e ./force.ts -e ./section.ts -p "Reply OK", with a third extension that writes the before_provider_request payload to a file.
  2. Look for SECTION-MARKER in the system message.
  3. Run again with the order swapped: -e ./section.ts -e ./force.ts.

Expected Behavior

Memory and SECTION-MARKER both reach the model, whatever the load order.

Actual Behavior

  • force.ts first: memory present, SECTION-MARKER missing.
  • section.ts first: both present.

Suggested fix

Add the injection as a section and keep the old path for hosts without systemPromptOptions:

if (event.systemPromptOptions?.sections) {
  event.systemPromptOptions.sections.hindsight = injection;
  return undefined;
}
return { systemPrompt: `${event.systemPrompt}\n\n${injection}` };

I checked this with the same stubs: memory and SECTION-MARKER both arrive, in either order. Pi's extension docs say the same: "Returning systemPrompt, or setting forceSystemPrompt, replaces the whole prompt for that run."

Version

@vectorize-io/hindsight-coding-agents 0.7.0 (same code on main at ccfe85b), Pi 0.87.1, macOS.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions