fix(coding-agent): preserve run prompt during tool refresh
closes #6162
This commit is contained in:
@@ -2,6 +2,14 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added `prepareNextTurnWithContext` for `Agent` users that need the next-turn loop context.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `Agent.prepareNextTurn` to keep receiving the run abort signal instead of the next-turn context.
|
||||
|
||||
## [0.80.2] - 2026-06-23
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -105,6 +105,9 @@ export interface AgentOptions {
|
||||
beforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;
|
||||
afterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;
|
||||
prepareNextTurn?: (
|
||||
signal?: AbortSignal,
|
||||
) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;
|
||||
prepareNextTurnWithContext?: (
|
||||
context: PrepareNextTurnContext,
|
||||
signal?: AbortSignal,
|
||||
) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;
|
||||
@@ -186,6 +189,9 @@ export class Agent {
|
||||
signal?: AbortSignal,
|
||||
) => Promise<AfterToolCallResult | undefined>;
|
||||
public prepareNextTurn?: (
|
||||
signal?: AbortSignal,
|
||||
) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;
|
||||
public prepareNextTurnWithContext?: (
|
||||
context: PrepareNextTurnContext,
|
||||
signal?: AbortSignal,
|
||||
) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;
|
||||
@@ -212,6 +218,7 @@ export class Agent {
|
||||
this.beforeToolCall = options.beforeToolCall;
|
||||
this.afterToolCall = options.afterToolCall;
|
||||
this.prepareNextTurn = options.prepareNextTurn;
|
||||
this.prepareNextTurnWithContext = options.prepareNextTurnWithContext;
|
||||
this.steeringQueue = new PendingMessageQueue(options.steeringMode ?? "one-at-a-time");
|
||||
this.followUpQueue = new PendingMessageQueue(options.followUpMode ?? "one-at-a-time");
|
||||
this.sessionId = options.sessionId;
|
||||
@@ -436,9 +443,15 @@ export class Agent {
|
||||
toolExecution: this.toolExecution,
|
||||
beforeToolCall: this.beforeToolCall,
|
||||
afterToolCall: this.afterToolCall,
|
||||
prepareNextTurn: this.prepareNextTurn
|
||||
? async (context) => await this.prepareNextTurn?.(context, this.signal)
|
||||
: undefined,
|
||||
prepareNextTurn:
|
||||
this.prepareNextTurnWithContext || this.prepareNextTurn
|
||||
? async (context) => {
|
||||
if (this.prepareNextTurnWithContext) {
|
||||
return await this.prepareNextTurnWithContext(context, this.signal);
|
||||
}
|
||||
return await this.prepareNextTurn?.(this.signal);
|
||||
}
|
||||
: undefined,
|
||||
convertToLlm: this.convertToLlm,
|
||||
transformContext: this.transformContext,
|
||||
getApiKey: this.getApiKey,
|
||||
|
||||
@@ -630,6 +630,47 @@ describe("Agent", () => {
|
||||
expect(responseCount).toBe(2);
|
||||
});
|
||||
|
||||
it("keeps legacy prepareNextTurn signal callback behavior", async () => {
|
||||
const schema = Type.Object({});
|
||||
const tool: AgentTool<typeof schema> = {
|
||||
name: "noop",
|
||||
label: "Noop",
|
||||
description: "Noop tool",
|
||||
parameters: schema,
|
||||
execute: async () => ({ content: [{ type: "text", text: "ok" }], details: {} }),
|
||||
};
|
||||
let requestCount = 0;
|
||||
let sawAbortSignal = false;
|
||||
const agent = new Agent({
|
||||
initialState: { tools: [tool] },
|
||||
prepareNextTurn: async (signal) => {
|
||||
sawAbortSignal = signal instanceof AbortSignal;
|
||||
return undefined;
|
||||
},
|
||||
streamFn: () => {
|
||||
requestCount++;
|
||||
const stream = new MockAssistantStream();
|
||||
queueMicrotask(() => {
|
||||
if (requestCount === 1) {
|
||||
const message = createAssistantToolUseMessage([
|
||||
{ type: "toolCall", id: "tool-1", name: "noop", arguments: {} },
|
||||
]);
|
||||
stream.push({ type: "done", reason: "toolUse", message });
|
||||
return;
|
||||
}
|
||||
const message = createAssistantMessage("done");
|
||||
stream.push({ type: "done", reason: "stop", message });
|
||||
});
|
||||
return stream;
|
||||
},
|
||||
});
|
||||
|
||||
await agent.prompt("start");
|
||||
|
||||
expect(requestCount).toBe(2);
|
||||
expect(sawAbortSignal).toBe(true);
|
||||
});
|
||||
|
||||
it("forwards sessionId to streamFn options", async () => {
|
||||
let receivedSessionId: string | undefined;
|
||||
const agent = new Agent({
|
||||
|
||||
Reference in New Issue
Block a user