@downcity/agent 1.1.326 → 1.1.328
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineRunner.js +66 -3
- package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineSignals.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineSignals.js +9 -4
- package/bin/executor/core-engine/CoreEngineSignals.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts +2 -0
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.js +1 -1
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.js.map +1 -1
- package/bin/index.d.ts +1 -1
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js.map +1 -1
- package/bin/session/messages/SessionAssistantMessageWriter.d.ts.map +1 -1
- package/bin/session/messages/SessionAssistantMessageWriter.js +6 -1
- package/bin/session/messages/SessionAssistantMessageWriter.js.map +1 -1
- package/bin/session/messages/SessionMessageInteractionWriter.d.ts.map +1 -1
- package/bin/session/messages/SessionMessageInteractionWriter.js +9 -4
- package/bin/session/messages/SessionMessageInteractionWriter.js.map +1 -1
- package/bin/types/session/SessionInteraction.d.ts +17 -1
- package/bin/types/session/SessionInteraction.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/session-tool-approval.test.mjs +171 -0
- package/src/executor/core-engine/CoreEngineRunner.ts +83 -5
- package/src/executor/core-engine/CoreEngineSignals.ts +10 -4
- package/src/executor/core-engine/CoreEngineUiStreamCollector.ts +3 -1
- package/src/index.ts +2 -0
- package/src/session/messages/SessionAssistantMessageWriter.ts +8 -1
- package/src/session/messages/SessionMessageInteractionWriter.ts +12 -6
- package/src/types/session/SessionInteraction.ts +27 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionMessageInteractionWriter.js","sourceRoot":"","sources":["../../../src/session/messages/SessionMessageInteractionWriter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkCH,0DAA0D;AAC1D,MAAM,OAAO,+BAA+B;IACzB,OAAO,CAAyC;IAEjE,YAAY,OAA+C;QACzD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,qDAAqD;IACrD,YAAY;QACV,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAC3D,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW;YAC5D,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAC7B,IAAI,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBACtD,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;gBACzB,CAAC,CAAC,EAAE,CACP;YACH,CAAC,CAAC,EAAE,CACP,CAAC;IACJ,CAAC;IAED,kDAAkD;IAClD,KAAK,CAAC,OAAO,CACX,OAAkC;QAElC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM;YAC/C,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,UAAU;YACrE,CAAC,CAAC,IAAI,CAAC,2BAA2B,EAAE,CAAC,UAAU,CAAC;QAClD,MAAM,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,OAAO,GAAG,IAAI,CAAC,2BAA2B,CAAC,UAAU,CAAC,CAAC;YAC7D,IACE,OAAO,CAAC,KAAK,CAAC,IAAI,CAChB,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,IAAI,KAAK,aAAa;gBAC3B,IAAI,CAAC,cAAc,KAAK,OAAO,CAAC,cAAc,CACjD,EACD,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;YACnF,CAAC;YAED,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YAC1B,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACnC,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;gBACtE,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;oBACnC,MAAM,IAAI,KAAK,CACb,mCAAmC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,CACjE,CAAC;gBACJ,CAAC;gBACD,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"SessionMessageInteractionWriter.js","sourceRoot":"","sources":["../../../src/session/messages/SessionMessageInteractionWriter.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Interaction 表示当前 Turn 在执行过程中需要用户参与。执行方发起请求后等待,
|
|
5
5
|
* Session 先持久化请求并通知客户端;客户端响应完成持久化后,原执行才会恢复。
|
|
6
6
|
*/
|
|
7
|
+
import type { JsonValue } from "../../types/common/Json.js";
|
|
7
8
|
/** Interaction 当前生命周期状态。 */
|
|
8
9
|
export type SessionInteractionStatus = "pending" | "resolved" | "expired" | "cancelled";
|
|
9
10
|
/** 高风险操作请求是否需要用户逐次确认。 */
|
|
@@ -34,7 +35,7 @@ export interface SessionInteractionRequestBase {
|
|
|
34
35
|
expires_at?: number;
|
|
35
36
|
}
|
|
36
37
|
/** 高风险操作审批请求。 */
|
|
37
|
-
export interface
|
|
38
|
+
export interface SessionShellApprovalInteractionRequest extends SessionInteractionRequestBase {
|
|
38
39
|
/** Interaction 类型固定为 approval。 */
|
|
39
40
|
kind: "approval";
|
|
40
41
|
/** 审批界面展示标题。 */
|
|
@@ -50,6 +51,21 @@ export interface SessionApprovalInteractionRequest extends SessionInteractionReq
|
|
|
50
51
|
/** 当前审批对应的操作类别。 */
|
|
51
52
|
operation: "exec" | "start" | "write";
|
|
52
53
|
}
|
|
54
|
+
/** 普通 Tool 在执行前等待用户决定的审批请求。 */
|
|
55
|
+
export interface SessionToolApprovalInteractionRequest extends SessionInteractionRequestBase {
|
|
56
|
+
/** Interaction 类型固定为 approval。 */
|
|
57
|
+
kind: "approval";
|
|
58
|
+
/** 审批操作类型固定为普通 Tool。 */
|
|
59
|
+
operation: "tool";
|
|
60
|
+
/** Tool schema 校验通过后的真实调用输入。 */
|
|
61
|
+
validated_input: JsonValue;
|
|
62
|
+
/** Tool 定义提供的稳定能力说明。 */
|
|
63
|
+
tool_description?: string;
|
|
64
|
+
/** 模型为当前调用给出的可选解释;该字段不构成安全依据。 */
|
|
65
|
+
model_explanation?: string;
|
|
66
|
+
}
|
|
67
|
+
/** Session 支持的全部审批请求。 */
|
|
68
|
+
export type SessionApprovalInteractionRequest = SessionShellApprovalInteractionRequest | SessionToolApprovalInteractionRequest;
|
|
53
69
|
/** Question 支持的回答形式。 */
|
|
54
70
|
export type SessionInteractionQuestionResponseType = "text" | "single_select" | "multi_select";
|
|
55
71
|
/** Question 选择项。 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInteraction.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionInteraction.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4BAA4B;AAC5B,MAAM,MAAM,wBAAwB,GAChC,SAAS,GACT,UAAU,GACV,SAAS,GACT,WAAW,CAAC;AAEhB,yBAAyB;AACzB,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,cAAc,CAAC;AAEzD,yBAAyB;AACzB,MAAM,MAAM,wBAAwB,GAChC;IACE,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,oCAAoC;IACpC,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAEN,0BAA0B;AAC1B,MAAM,WAAW,6BAA6B;IAC5C,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,MAAM,EAAE,wBAAwB,CAAC;IACjC,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,iBAAiB;AACjB,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"SessionInteraction.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionInteraction.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 验证 AI SDK Tool needsApproval 接入 Session Interaction。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - Tool 自己声明审批意图,Agent 不持有审批配置。
|
|
6
|
+
* - Runtime 展示真实 Tool Call,用户响应后继续原 Turn。
|
|
7
|
+
* - 拒绝时 Tool execute 不能产生副作用。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import test from "node:test";
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import fs from "node:fs/promises";
|
|
13
|
+
import os from "node:os";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { MockLanguageModelV3 } from "ai/test";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { Agent, Workspace } from "@downcity/agent";
|
|
18
|
+
|
|
19
|
+
function create_usage() {
|
|
20
|
+
return {
|
|
21
|
+
inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
|
|
22
|
+
outputTokens: { total: 0, text: 0, reasoning: 0 },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function create_tool_call_stream() {
|
|
27
|
+
const input = { value: "approval-value" };
|
|
28
|
+
return {
|
|
29
|
+
stream: new ReadableStream({
|
|
30
|
+
start(controller) {
|
|
31
|
+
controller.enqueue({ type: "stream-start", warnings: [] });
|
|
32
|
+
controller.enqueue({
|
|
33
|
+
type: "tool-input-start",
|
|
34
|
+
id: "call_custom_approval",
|
|
35
|
+
toolName: "custom_approval",
|
|
36
|
+
});
|
|
37
|
+
controller.enqueue({
|
|
38
|
+
type: "tool-input-delta",
|
|
39
|
+
id: "call_custom_approval",
|
|
40
|
+
delta: JSON.stringify(input),
|
|
41
|
+
});
|
|
42
|
+
controller.enqueue({ type: "tool-input-end", id: "call_custom_approval" });
|
|
43
|
+
controller.enqueue({
|
|
44
|
+
type: "tool-call",
|
|
45
|
+
toolCallId: "call_custom_approval",
|
|
46
|
+
toolName: "custom_approval",
|
|
47
|
+
input: JSON.stringify(input),
|
|
48
|
+
});
|
|
49
|
+
controller.enqueue({
|
|
50
|
+
type: "finish",
|
|
51
|
+
finishReason: { unified: "tool-calls", raw: "tool-calls" },
|
|
52
|
+
usage: create_usage(),
|
|
53
|
+
});
|
|
54
|
+
controller.close();
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function create_final_text_stream() {
|
|
61
|
+
return {
|
|
62
|
+
stream: new ReadableStream({
|
|
63
|
+
start(controller) {
|
|
64
|
+
controller.enqueue({ type: "stream-start", warnings: [] });
|
|
65
|
+
controller.enqueue({ type: "text-start", id: "text_1" });
|
|
66
|
+
controller.enqueue({ type: "text-delta", id: "text_1", delta: "finished" });
|
|
67
|
+
controller.enqueue({ type: "text-end", id: "text_1" });
|
|
68
|
+
controller.enqueue({
|
|
69
|
+
type: "finish",
|
|
70
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
71
|
+
usage: create_usage(),
|
|
72
|
+
});
|
|
73
|
+
controller.close();
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function run_approval_case(decision) {
|
|
80
|
+
const project_root = await fs.mkdtemp(
|
|
81
|
+
path.join(os.tmpdir(), "downcity-native-tool-approval-"),
|
|
82
|
+
);
|
|
83
|
+
let execution_count = 0;
|
|
84
|
+
let tool_stream_count = 0;
|
|
85
|
+
const model = new MockLanguageModelV3({
|
|
86
|
+
modelId: "native-tool-approval-model",
|
|
87
|
+
doStream: async (options) => {
|
|
88
|
+
if (!Array.isArray(options.tools) || options.tools.length === 0) {
|
|
89
|
+
return create_final_text_stream();
|
|
90
|
+
}
|
|
91
|
+
tool_stream_count += 1;
|
|
92
|
+
return tool_stream_count === 1
|
|
93
|
+
? create_tool_call_stream()
|
|
94
|
+
: create_final_text_stream();
|
|
95
|
+
},
|
|
96
|
+
doGenerate: async () => ({
|
|
97
|
+
content: [{ type: "text", text: "Approval test" }],
|
|
98
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
99
|
+
usage: create_usage(),
|
|
100
|
+
warnings: [],
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
const agent = new Agent({
|
|
104
|
+
id: `native_tool_approval_${decision}`,
|
|
105
|
+
workspace: new Workspace({ path: project_root }),
|
|
106
|
+
model,
|
|
107
|
+
tools: {
|
|
108
|
+
custom_approval: {
|
|
109
|
+
description: "Execute a custom operation after approval.",
|
|
110
|
+
inputSchema: z.object({ value: z.string() }),
|
|
111
|
+
needsApproval: true,
|
|
112
|
+
execute: async () => {
|
|
113
|
+
execution_count += 1;
|
|
114
|
+
return "tool-result";
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const session = await agent.sessions.create({ session_id: "tool_approval" });
|
|
122
|
+
let pending_request;
|
|
123
|
+
let response_promise;
|
|
124
|
+
const unsubscribe = session.subscribe((mutation) => {
|
|
125
|
+
if (
|
|
126
|
+
mutation.variant !== "part" ||
|
|
127
|
+
mutation.type !== "interaction" ||
|
|
128
|
+
mutation.part.status !== "pending" ||
|
|
129
|
+
mutation.part.request.kind !== "approval" ||
|
|
130
|
+
mutation.part.request.operation !== "tool"
|
|
131
|
+
) return;
|
|
132
|
+
pending_request = mutation.part.request;
|
|
133
|
+
response_promise = session.respond({
|
|
134
|
+
interaction_id: mutation.part.interaction_id,
|
|
135
|
+
response: { kind: "approval", decision },
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const turn = await session.prompt({ query: "run custom approval tool" });
|
|
140
|
+
const result = await turn.finished;
|
|
141
|
+
unsubscribe();
|
|
142
|
+
|
|
143
|
+
assert.equal(result.success, true, result.error);
|
|
144
|
+
assert.equal(result.text, "finished");
|
|
145
|
+
assert.equal(execution_count, decision === "approved" ? 1 : 0);
|
|
146
|
+
assert.ok(pending_request);
|
|
147
|
+
assert.equal(pending_request.source.tool_name, "custom_approval");
|
|
148
|
+
assert.deepEqual(pending_request.validated_input, {
|
|
149
|
+
value: "approval-value",
|
|
150
|
+
});
|
|
151
|
+
assert.equal(
|
|
152
|
+
pending_request.tool_description,
|
|
153
|
+
"Execute a custom operation after approval.",
|
|
154
|
+
);
|
|
155
|
+
assert.equal("title" in pending_request, false);
|
|
156
|
+
assert.equal("reason" in pending_request, false);
|
|
157
|
+
assert.ok(response_promise);
|
|
158
|
+
await response_promise;
|
|
159
|
+
} finally {
|
|
160
|
+
await agent.dispose();
|
|
161
|
+
await fs.rm(project_root, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
test("needsApproval 批准后执行 Tool 并恢复原 Turn", async () => {
|
|
166
|
+
await run_approval_case("approved");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("needsApproval 拒绝后不执行 Tool 副作用", async () => {
|
|
170
|
+
await run_approval_case("denied");
|
|
171
|
+
});
|
|
@@ -11,8 +11,11 @@ import {
|
|
|
11
11
|
streamText,
|
|
12
12
|
type FileUIPart,
|
|
13
13
|
type LanguageModel,
|
|
14
|
+
type ModelMessage,
|
|
14
15
|
type StepResult,
|
|
15
16
|
type Tool,
|
|
17
|
+
type ToolApprovalRequestOutput,
|
|
18
|
+
type ToolApprovalResponse,
|
|
16
19
|
type UIMessage,
|
|
17
20
|
} from "ai";
|
|
18
21
|
import { log_assistant_message_now } from "@executor/messages/SessionMessageLog.js";
|
|
@@ -48,6 +51,7 @@ import {
|
|
|
48
51
|
import type { Logger } from "@/utils/logger/Logger.js";
|
|
49
52
|
import type { JsonObject } from "@/types/common/Json.js";
|
|
50
53
|
import type { SessionTurnContext } from "@/types/executor/SessionTurnContext.js";
|
|
54
|
+
import { to_session_json_value } from "@/session/messages/SessionJsonValue.js";
|
|
51
55
|
import type {
|
|
52
56
|
SessionStepExecutionInput,
|
|
53
57
|
SessionTurnExecutionResult,
|
|
@@ -183,7 +187,8 @@ export class CoreEngineRunner {
|
|
|
183
187
|
: [];
|
|
184
188
|
let tools = input.execute_input.tools;
|
|
185
189
|
let last_observed_stream_error: unknown = undefined;
|
|
186
|
-
|
|
190
|
+
let final_assistant_ui_message: SessionMessageRecordV1 | null = null;
|
|
191
|
+
let ui_stream_continuation_message: SessionMessageRecordV1 | null = null;
|
|
187
192
|
let compact_required = false;
|
|
188
193
|
|
|
189
194
|
try {
|
|
@@ -202,7 +207,9 @@ export class CoreEngineRunner {
|
|
|
202
207
|
let step_count = 0;
|
|
203
208
|
let total_tool_call_count = 0;
|
|
204
209
|
let total_tool_result_count = 0;
|
|
205
|
-
const on_step_finish = async (
|
|
210
|
+
const on_step_finish = async (
|
|
211
|
+
step_result: StepResult<Record<string, Tool>>,
|
|
212
|
+
): Promise<void> => {
|
|
206
213
|
step_count += 1;
|
|
207
214
|
const summary = summarize_step_for_debug(step_result);
|
|
208
215
|
total_tool_call_count +=
|
|
@@ -279,6 +286,7 @@ export class CoreEngineRunner {
|
|
|
279
286
|
last_observed_stream_error = undefined;
|
|
280
287
|
let step_assistant_ui_message: SessionMessageRecordV1;
|
|
281
288
|
let executed_steps: StepResult<Record<string, Tool>>[];
|
|
289
|
+
const observed_steps: StepResult<Record<string, Tool>>[] = [];
|
|
282
290
|
let canonical_step_started = false;
|
|
283
291
|
let canonical_step_finished = false;
|
|
284
292
|
try {
|
|
@@ -289,7 +297,10 @@ export class CoreEngineRunner {
|
|
|
289
297
|
const result = streamText({
|
|
290
298
|
model: step_inputs.model,
|
|
291
299
|
system,
|
|
292
|
-
onStepFinish:
|
|
300
|
+
onStepFinish: async (step_result) => {
|
|
301
|
+
observed_steps.push(step_result);
|
|
302
|
+
await on_step_finish(step_result);
|
|
303
|
+
},
|
|
293
304
|
messages: message_state.modelMessages,
|
|
294
305
|
tools,
|
|
295
306
|
abortSignal: input.turn_context.lifecycle.abort_signal,
|
|
@@ -306,6 +317,9 @@ export class CoreEngineRunner {
|
|
|
306
317
|
await collect_final_assistant_message_from_ui_stream({
|
|
307
318
|
result,
|
|
308
319
|
session_id: session_id,
|
|
320
|
+
original_messages: ui_stream_continuation_message
|
|
321
|
+
? [ui_stream_continuation_message]
|
|
322
|
+
: undefined,
|
|
309
323
|
logger: this.logger,
|
|
310
324
|
buildFallbackAssistantMessage: (text) =>
|
|
311
325
|
build_fallback_assistant_message(session_id, text),
|
|
@@ -340,10 +354,11 @@ export class CoreEngineRunner {
|
|
|
340
354
|
step_assistant_ui_message,
|
|
341
355
|
);
|
|
342
356
|
|
|
343
|
-
// 关键点(中文):先保存本 step 已收敛的 assistant 消息,再等待
|
|
344
|
-
// stop/
|
|
357
|
+
// 关键点(中文):先保存本 step 已收敛的 assistant 消息,再等待 Provider 终态。
|
|
358
|
+
// stop / error 时已经生成的部分内容仍会保留,但 `result.steps` 必须作为错误传播边界。
|
|
345
359
|
message_state.appendRuntimeSessionMessage(step_assistant_ui_message);
|
|
346
360
|
executed_steps = await result.steps;
|
|
361
|
+
ui_stream_continuation_message = null;
|
|
347
362
|
} catch (error) {
|
|
348
363
|
if (
|
|
349
364
|
canonical_step_started &&
|
|
@@ -494,7 +509,19 @@ export class CoreEngineRunner {
|
|
|
494
509
|
const response_messages = Array.isArray(last_step.response?.messages)
|
|
495
510
|
? last_step.response.messages
|
|
496
511
|
: [];
|
|
512
|
+
const approval_responses = await resolve_tool_approval_responses({
|
|
513
|
+
step: last_step,
|
|
514
|
+
tools,
|
|
515
|
+
turn_context: input.turn_context,
|
|
516
|
+
});
|
|
497
517
|
message_state.appendModelMessages(response_messages);
|
|
518
|
+
if (approval_responses.length > 0) {
|
|
519
|
+
message_state.appendModelMessages([
|
|
520
|
+
{ role: "tool", content: approval_responses } as ModelMessage,
|
|
521
|
+
]);
|
|
522
|
+
// 原生审批的下一次 streamText 会先恢复上一条 Tool Part,再继续模型输出。
|
|
523
|
+
ui_stream_continuation_message = final_assistant_ui_message;
|
|
524
|
+
}
|
|
498
525
|
|
|
499
526
|
if (loop_decision.continueForToolCalls) {
|
|
500
527
|
text_only_continuation_count = 0;
|
|
@@ -623,6 +650,57 @@ export class CoreEngineRunner {
|
|
|
623
650
|
}
|
|
624
651
|
}
|
|
625
652
|
|
|
653
|
+
/** 把 AI SDK Tool Approval 接入 Session 的 canonical Interaction 生命周期。 */
|
|
654
|
+
async function resolve_tool_approval_responses(input: {
|
|
655
|
+
step: StepResult<Record<string, Tool>>;
|
|
656
|
+
tools: Record<string, Tool>;
|
|
657
|
+
turn_context: SessionTurnContext;
|
|
658
|
+
}): Promise<ToolApprovalResponse[]> {
|
|
659
|
+
const requests = input.step.content.filter(
|
|
660
|
+
(part): part is ToolApprovalRequestOutput<Record<string, Tool>> =>
|
|
661
|
+
part.type === "tool-approval-request",
|
|
662
|
+
);
|
|
663
|
+
if (requests.length === 0) return [];
|
|
664
|
+
const interactions = input.turn_context.interactions;
|
|
665
|
+
if (!interactions) {
|
|
666
|
+
throw new Error("Tool approval requires a Session Interaction port");
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return await Promise.all(
|
|
670
|
+
requests.map(async (request) => {
|
|
671
|
+
const tool_name = request.toolCall.toolName;
|
|
672
|
+
const tool_definition = input.tools[tool_name];
|
|
673
|
+
const model_explanation = String(input.step.text || "").trim();
|
|
674
|
+
const handle = await interactions.request({
|
|
675
|
+
interaction_id: `interaction:tool-approval:${request.approvalId}`,
|
|
676
|
+
turn_id: input.turn_context.session.turn_id,
|
|
677
|
+
kind: "approval",
|
|
678
|
+
operation: "tool",
|
|
679
|
+
source: {
|
|
680
|
+
type: "tool",
|
|
681
|
+
tool_call_id: request.toolCall.toolCallId,
|
|
682
|
+
tool_name,
|
|
683
|
+
},
|
|
684
|
+
validated_input: to_session_json_value(request.toolCall.input),
|
|
685
|
+
...(tool_definition?.description
|
|
686
|
+
? { tool_description: tool_definition.description }
|
|
687
|
+
: {}),
|
|
688
|
+
...(model_explanation ? { model_explanation } : {}),
|
|
689
|
+
created_at: Date.now(),
|
|
690
|
+
});
|
|
691
|
+
const result = await handle.result;
|
|
692
|
+
const approved = result.status === "resolved" &&
|
|
693
|
+
result.response.kind === "approval" &&
|
|
694
|
+
result.response.decision === "approved";
|
|
695
|
+
return {
|
|
696
|
+
type: "tool-approval-response",
|
|
697
|
+
approvalId: request.approvalId,
|
|
698
|
+
approved,
|
|
699
|
+
};
|
|
700
|
+
}),
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
|
|
626
704
|
/** 构造仅在当前 Turn 内使用的内部 User Message。 */
|
|
627
705
|
function build_internal_user_message(input: {
|
|
628
706
|
session_id: string;
|
|
@@ -236,6 +236,15 @@ export function merge_assistant_ui_messages(
|
|
|
236
236
|
if (!base) return incoming;
|
|
237
237
|
const baseMetadata = base.metadata;
|
|
238
238
|
const incomingMetadata = incoming.metadata;
|
|
239
|
+
// 原生审批恢复会把上一条 assistant message 作为 originalMessages 传入,
|
|
240
|
+
// SDK 返回的是同一条消息的完整快照,此时应整体替换而不是重复拼接。
|
|
241
|
+
const merged_parts =
|
|
242
|
+
base.id === incoming.id
|
|
243
|
+
? incoming.parts
|
|
244
|
+
: [
|
|
245
|
+
...(Array.isArray(base.parts) ? base.parts : []),
|
|
246
|
+
...(Array.isArray(incoming.parts) ? incoming.parts : []),
|
|
247
|
+
];
|
|
239
248
|
return {
|
|
240
249
|
...base,
|
|
241
250
|
metadata: {
|
|
@@ -246,10 +255,7 @@ export function merge_assistant_ui_messages(
|
|
|
246
255
|
...(baseMetadata || {}),
|
|
247
256
|
...(incomingMetadata || {}),
|
|
248
257
|
},
|
|
249
|
-
parts:
|
|
250
|
-
...(Array.isArray(base.parts) ? base.parts : []),
|
|
251
|
-
...(Array.isArray(incoming.parts) ? incoming.parts : []),
|
|
252
|
-
],
|
|
258
|
+
parts: merged_parts,
|
|
253
259
|
};
|
|
254
260
|
}
|
|
255
261
|
|
|
@@ -38,6 +38,8 @@ export async function collect_final_assistant_message_from_ui_stream(params: {
|
|
|
38
38
|
* 构造 fallback assistant 消息的工厂函数。
|
|
39
39
|
*/
|
|
40
40
|
buildFallbackAssistantMessage: (text: string) => SessionMessageRecordV1;
|
|
41
|
+
/** 当前 Turn 已收敛的 Assistant 消息;原生审批恢复时用于重建已有 Tool Part。 */
|
|
42
|
+
original_messages?: SessionMessageRecordV1[];
|
|
41
43
|
/**
|
|
42
44
|
* UI stream chunk 回调。
|
|
43
45
|
*/
|
|
@@ -58,7 +60,7 @@ export async function collect_final_assistant_message_from_ui_stream(params: {
|
|
|
58
60
|
|
|
59
61
|
const uiStream = params.result.toUIMessageStream<SessionMessageRecordV1>({
|
|
60
62
|
// 关键点(中文):SDK stream 需要 reasoning 旁路事件时可直接消费;最终落盘仍由 responseMessage 收敛。
|
|
61
|
-
originalMessages:
|
|
63
|
+
originalMessages: params.original_messages,
|
|
62
64
|
generateMessageId: () => `a:${params.session_id}:${generate_id()}`,
|
|
63
65
|
messageMetadata: ({ part }) => {
|
|
64
66
|
if (part.type !== "start" && part.type !== "finish") return undefined;
|
package/src/index.ts
CHANGED
|
@@ -134,6 +134,8 @@ export type {
|
|
|
134
134
|
SessionQuestionInteractionRequest,
|
|
135
135
|
SessionQuestionInteractionResponse,
|
|
136
136
|
SessionResolvedInteractionResult,
|
|
137
|
+
SessionShellApprovalInteractionRequest,
|
|
138
|
+
SessionToolApprovalInteractionRequest,
|
|
137
139
|
} from "./types/session/SessionInteraction.js";
|
|
138
140
|
export type {
|
|
139
141
|
AgentOptions,
|
|
@@ -465,7 +465,14 @@ export class SessionAssistantMessageWriter {
|
|
|
465
465
|
`Assistant canonical Tool Part not found: ${input.tool_call_id}`,
|
|
466
466
|
);
|
|
467
467
|
}
|
|
468
|
-
|
|
468
|
+
// 原生 needsApproval 恢复时,AI SDK 不会重新发送 Tool 输入;沿用已审批并
|
|
469
|
+
// 已转为 running 的 Part,仅补齐执行前的 canonical 输入屏障。
|
|
470
|
+
if (
|
|
471
|
+
current.state !== "input-streaming" &&
|
|
472
|
+
current.state !== "ready" &&
|
|
473
|
+
current.state !== "waiting-user" &&
|
|
474
|
+
current.state !== "running"
|
|
475
|
+
) {
|
|
469
476
|
throw new Error(
|
|
470
477
|
`Tool input cannot be prepared from ${current.state}: ${input.tool_call_id}`,
|
|
471
478
|
);
|
|
@@ -86,16 +86,22 @@ export class SessionMessageInteractionWriter {
|
|
|
86
86
|
`Tool Assistant Message changed: ${request.source.tool_call_id}`,
|
|
87
87
|
);
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
const native_tool_approval =
|
|
90
|
+
request.kind === "approval" &&
|
|
91
|
+
request.operation === "tool" &&
|
|
92
|
+
tool.part.state === "waiting-user";
|
|
93
|
+
if (tool.part.state !== "ready" && !native_tool_approval) {
|
|
90
94
|
throw new Error(
|
|
91
95
|
`Tool Interaction requires ready input: ${request.source.tool_call_id} (${tool.part.state})`,
|
|
92
96
|
);
|
|
93
97
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
if (!native_tool_approval) {
|
|
99
|
+
parts = parts.map((part) =>
|
|
100
|
+
part.part_id === tool.part.part_id
|
|
101
|
+
? { ...tool.part, state: "waiting-user" as const }
|
|
102
|
+
: part,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
const interaction: SessionAssistantInteractionPart = {
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* Session 先持久化请求并通知客户端;客户端响应完成持久化后,原执行才会恢复。
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { JsonValue } from "@/types/common/Json.js";
|
|
9
|
+
|
|
8
10
|
/** Interaction 当前生命周期状态。 */
|
|
9
11
|
export type SessionInteractionStatus =
|
|
10
12
|
| "pending"
|
|
@@ -45,7 +47,7 @@ export interface SessionInteractionRequestBase {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
/** 高风险操作审批请求。 */
|
|
48
|
-
export interface
|
|
50
|
+
export interface SessionShellApprovalInteractionRequest
|
|
49
51
|
extends SessionInteractionRequestBase {
|
|
50
52
|
/** Interaction 类型固定为 approval。 */
|
|
51
53
|
kind: "approval";
|
|
@@ -63,6 +65,30 @@ export interface SessionApprovalInteractionRequest
|
|
|
63
65
|
operation: "exec" | "start" | "write";
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
/** 普通 Tool 在执行前等待用户决定的审批请求。 */
|
|
69
|
+
export interface SessionToolApprovalInteractionRequest
|
|
70
|
+
extends SessionInteractionRequestBase {
|
|
71
|
+
/** Interaction 类型固定为 approval。 */
|
|
72
|
+
kind: "approval";
|
|
73
|
+
|
|
74
|
+
/** 审批操作类型固定为普通 Tool。 */
|
|
75
|
+
operation: "tool";
|
|
76
|
+
|
|
77
|
+
/** Tool schema 校验通过后的真实调用输入。 */
|
|
78
|
+
validated_input: JsonValue;
|
|
79
|
+
|
|
80
|
+
/** Tool 定义提供的稳定能力说明。 */
|
|
81
|
+
tool_description?: string;
|
|
82
|
+
|
|
83
|
+
/** 模型为当前调用给出的可选解释;该字段不构成安全依据。 */
|
|
84
|
+
model_explanation?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Session 支持的全部审批请求。 */
|
|
88
|
+
export type SessionApprovalInteractionRequest =
|
|
89
|
+
| SessionShellApprovalInteractionRequest
|
|
90
|
+
| SessionToolApprovalInteractionRequest;
|
|
91
|
+
|
|
66
92
|
/** Question 支持的回答形式。 */
|
|
67
93
|
export type SessionInteractionQuestionResponseType =
|
|
68
94
|
| "text"
|