@downcity/agent 1.1.277 → 1.1.278
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/agent/Agent.d.ts.map +1 -1
- package/bin/agent/Agent.js +0 -1
- package/bin/agent/Agent.js.map +1 -1
- package/bin/agent/AgentSessions.d.ts +0 -4
- package/bin/agent/AgentSessions.d.ts.map +1 -1
- package/bin/agent/AgentSessions.js +2 -17
- package/bin/agent/AgentSessions.js.map +1 -1
- package/bin/session/Session.d.ts +11 -1
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +61 -24
- package/bin/session/Session.js.map +1 -1
- package/bin/session/storage/Instruction.d.ts +14 -0
- package/bin/session/storage/Instruction.d.ts.map +1 -0
- package/bin/session/storage/Instruction.js +44 -0
- package/bin/session/storage/Instruction.js.map +1 -0
- package/bin/session/storage/Paths.d.ts +8 -0
- package/bin/session/storage/Paths.d.ts.map +1 -1
- package/bin/session/storage/Paths.js +10 -0
- package/bin/session/storage/Paths.js.map +1 -1
- package/bin/types/agent/SessionActor.d.ts +2 -0
- package/bin/types/agent/SessionActor.d.ts.map +1 -1
- package/bin/types/session/SessionInstruction.d.ts +22 -0
- package/bin/types/session/SessionInstruction.d.ts.map +1 -0
- package/bin/types/session/SessionInstruction.js +9 -0
- package/bin/types/session/SessionInstruction.js.map +1 -0
- package/bin/types/session/SessionOptions.d.ts +6 -2
- package/bin/types/session/SessionOptions.d.ts.map +1 -1
- package/bin/types/session/SessionQueue.d.ts +2 -18
- package/bin/types/session/SessionQueue.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/session-config-turn-boundary.test.mjs +156 -5
- package/src/agent/Agent.ts +0 -1
- package/src/agent/AgentSessions.ts +2 -21
- package/src/session/Session.ts +68 -26
- package/src/session/storage/Instruction.ts +59 -0
- package/src/session/storage/Paths.ts +18 -0
- package/src/types/agent/SessionActor.ts +3 -0
- package/src/types/session/SessionInstruction.ts +24 -0
- package/src/types/session/SessionOptions.ts +6 -2
- package/src/types/session/SessionQueue.ts +9 -29
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionActor.d.ts","sourceRoot":"","sources":["../../../src/types/agent/SessionActor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,EACvB,sBAAsB,EACtB,0BAA0B,EAC1B,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,0BAA0B,EAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACV,yBAAyB,EACzB,0BAA0B,EAC3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACV,2BAA2B,EAC3B,eAAe,EACf,2BAA2B,EAC3B,qBAAqB,EACrB,2BAA2B,EAC5B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,iBAAiB,GAAG,YAAY;IAC9E,oBAAoB;IACpB,MAAM,CAAC,KAAK,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3D,wBAAwB;IACxB,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3C,gCAAgC;IAChC,IAAI,CAAC,KAAK,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAEvE,oBAAoB;IACpB,OAAO,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAE7E,0BAA0B;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAEjF,uBAAuB;IACvB,aAAa,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,uBAAuB;IACvB,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEtC,qBAAqB;IACrB,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAExE,oCAAoC;IACpC,IAAI,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAExC;;;;;;OAMG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB,0BAA0B;IAC1B,SAAS,CACP,UAAU,EAAE,yBAAyB,GACpC,0BAA0B,CAAC;IAE9B,gCAAgC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExE,kCAAkC;IAClC,MAAM,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAE9C,mCAAmC;IACnC,SAAS,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAExC,4BAA4B;IAC5B,aAAa,IAAI,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAEtD,4BAA4B;IAC5B,iBAAiB,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAE5F,mCAAmC;IACnC,gBAAgB,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACtF;AAED;;GAEG;AACH,MAAM,WAAW,YAAa,SAAQ,iBAAiB;IACrD,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,uBAAuB;IACvB,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAE5C,yBAAyB;IACzB,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD,4BAA4B;IAC5B,IAAI,CAAC,KAAK,CAAC,EAAE,qBAAqB,GAAG,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,8BAA8B;IAC9B,IAAI,CAAC,KAAK,CAAC,EAAE,qBAAqB,GAAG,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC3E"}
|
|
1
|
+
{"version":3,"file":"SessionActor.d.ts","sourceRoot":"","sources":["../../../src/types/agent/SessionActor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session instruction 显式快照存储类型。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 这里只描述 instruction.md 的定位与写入输入。
|
|
6
|
+
* - 文件存在性本身用于表达 Session 是否启用显式 instruction 快照。
|
|
7
|
+
*/
|
|
8
|
+
/** Session instruction.md 的稳定定位信息。 */
|
|
9
|
+
export interface SessionInstructionStorageLocation {
|
|
10
|
+
/** 当前项目根目录。 */
|
|
11
|
+
project_root: string;
|
|
12
|
+
/** 当前 Agent 稳定标识。 */
|
|
13
|
+
agent_id: string;
|
|
14
|
+
/** 当前 Session 稳定标识。 */
|
|
15
|
+
session_id: string;
|
|
16
|
+
}
|
|
17
|
+
/** 原子写入 Session instruction.md 使用的完整输入。 */
|
|
18
|
+
export interface WriteSessionInstructionInput extends SessionInstructionStorageLocation {
|
|
19
|
+
/** 当前 Session 生效的自定义 instruction Markdown。 */
|
|
20
|
+
instruction: string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SessionInstruction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionInstruction.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionInstruction.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,sCAAsC;AACtC,MAAM,WAAW,iCAAiC;IAChD,eAAe;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,2CAA2C;AAC3C,MAAM,WAAW,4BACf,SAAQ,iCAAiC;IACzC,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionInstruction.js","sourceRoot":"","sources":["../../../src/types/session/SessionInstruction.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -61,9 +61,13 @@ export interface SessionOptions {
|
|
|
61
61
|
*/
|
|
62
62
|
logger: Logger;
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
64
|
+
* 当前 Session 创建时绑定的 instruction system blocks。
|
|
65
|
+
*
|
|
66
|
+
* 关键点(中文)
|
|
67
|
+
* - Session 创建后不再动态读取 Agent instruction。
|
|
68
|
+
* - `session.snapshot()` 只会把其中 `instruction` 来源的内容显式写入本地文件。
|
|
65
69
|
*/
|
|
66
|
-
|
|
70
|
+
instruction_system_blocks: AgentSessionSystemBlock[];
|
|
67
71
|
/**
|
|
68
72
|
* 读取当前 Agent configured env。
|
|
69
73
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionOptions.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionOptions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;OAEG;IACH,cAAc,IAAI,WAAW,CAAC;IAE9B;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC;IAEvB;;OAEG;IACH,qBAAqB,CACnB,OAAO,EAAE,mBAAmB,GAC3B,IAAI,CAAC;CACT;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE5B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf
|
|
1
|
+
{"version":3,"file":"SessionOptions.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionOptions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;OAEG;IACH,cAAc,IAAI,WAAW,CAAC;IAE9B;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC;IAEvB;;OAEG;IACH,qBAAqB,CACnB,OAAO,EAAE,mBAAmB,GAC3B,IAAI,CAAC;CACT;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE5B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;OAMG;IACH,yBAAyB,EAAE,uBAAuB,EAAE,CAAC;IAErD;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE1C,wDAAwD;IACxD,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;IAErD;;OAEG;IACH,4BAA4B,EAAE,MAAM,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAAC;IAEvE;;OAEG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnE,6BAA6B;IAC7B,aAAa,EAAE,MAAM,UAAU,GAAG,SAAS,CAAC;IAE5C,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 队列只保存明确的输入事实,不保存可执行闭包。SessionTurn 是这些输入的唯一解释者。
|
|
5
5
|
*/
|
|
6
|
-
import type { AgentSessionConfigSnapshot
|
|
6
|
+
import type { AgentSessionConfigSnapshot } from "../../types/agent/SessionTypes.js";
|
|
7
7
|
import type { AgentPluginExecutionRuntime } from "../../types/plugin/PluginRuntime.js";
|
|
8
8
|
import type { AgentSessionPromptInput } from "../../types/sdk/AgentSessionPrompt.js";
|
|
9
9
|
import type { AgentSessionTurnHandle } from "../../types/sdk/AgentSessionTurn.js";
|
|
@@ -20,15 +20,6 @@ export interface SessionModelQueueCommand {
|
|
|
20
20
|
/** 配置生效后需要写入的可选 Action 标题。 */
|
|
21
21
|
action_title?: string;
|
|
22
22
|
}
|
|
23
|
-
/** Agent instruction 在 Session Step 检查点生效的命令。 */
|
|
24
|
-
export interface SessionInstructionQueueCommand {
|
|
25
|
-
/** 命令种类固定为 Agent instruction 更新。 */
|
|
26
|
-
type: "agent_instruction";
|
|
27
|
-
/** 当前命令的稳定唯一标识。 */
|
|
28
|
-
command_id: string;
|
|
29
|
-
/** 下一 Step 使用的完整 instruction blocks。 */
|
|
30
|
-
instruction_blocks: AgentSessionSystemBlock[];
|
|
31
|
-
}
|
|
32
23
|
/** Agent env 在 Session Step 检查点生效的命令。 */
|
|
33
24
|
export interface SessionEnvQueueCommand {
|
|
34
25
|
/** 命令种类固定为 Agent env 更新。 */
|
|
@@ -57,16 +48,9 @@ export interface SessionCompactQueueCommand {
|
|
|
57
48
|
command_id: string;
|
|
58
49
|
}
|
|
59
50
|
/** Session FIFO 中允许出现的领域命令。 */
|
|
60
|
-
export type SessionQueueCommand = SessionModelQueueCommand |
|
|
51
|
+
export type SessionQueueCommand = SessionModelQueueCommand | SessionEnvQueueCommand | SessionPluginsQueueCommand | SessionCompactQueueCommand;
|
|
61
52
|
/** Agent configured state 广播给既有 Session 的输入。 */
|
|
62
53
|
export type AgentSessionCommand = {
|
|
63
|
-
/** 当前修改固定为 instruction。 */
|
|
64
|
-
type: "instruction";
|
|
65
|
-
/** 当前命令唯一标识。 */
|
|
66
|
-
command_id: string;
|
|
67
|
-
/** 下一 Session Step 使用的 instruction blocks。 */
|
|
68
|
-
instruction_blocks: AgentSessionSystemBlock[];
|
|
69
|
-
} | {
|
|
70
54
|
/** 当前修改固定为 env。 */
|
|
71
55
|
type: "env";
|
|
72
56
|
/** 当前命令唯一标识。 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionQueue.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionQueue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,
|
|
1
|
+
{"version":3,"file":"SessionQueue.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionQueue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,mCAAmC;AACnC,MAAM,WAAW,wBAAwB;IACvC,4BAA4B;IAC5B,IAAI,EAAE,eAAe,CAAC;IACtB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,MAAM,EAAE,0BAA0B,CAAC;IACnC,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,yCAAyC;AACzC,MAAM,WAAW,sBAAsB;IACrC,4BAA4B;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,8CAA8C;AAC9C,MAAM,WAAW,0BAA0B;IACzC,+BAA+B;IAC/B,IAAI,EAAE,eAAe,CAAC;IACtB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,OAAO,EAAE,2BAA2B,CAAC;CACtC;AAED,mBAAmB;AACnB,MAAM,WAAW,0BAA0B;IACzC,uBAAuB;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,+BAA+B;AAC/B,MAAM,MAAM,mBAAmB,GAC3B,wBAAwB,GACxB,sBAAsB,GACtB,0BAA0B,GAC1B,0BAA0B,CAAC;AAE/B,gDAAgD;AAChD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,mBAAmB;IACnB,IAAI,EAAE,KAAK,CAAC;IACZ,gBAAgB;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,GACC;IACE,uBAAuB;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,gBAAgB;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,OAAO,EAAE,2BAA2B,CAAC;CACtC,CAAC;AAEN,wBAAwB;AACxB,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,sBAAsB;IACtB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,oBAAoB;IACpB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAC7B;AAED,mCAAmC;AACnC,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,wBAAwB;IACxB,KAAK,EAAE,uBAAuB,CAAC;IAC/B,0CAA0C;IAC1C,eAAe,EAAE,oBAAoB,CAAC,sBAAsB,CAAC,CAAC;CAC/D;AAED,6BAA6B;AAC7B,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 第一次 provider 请求保持阻塞,用来制造真实的运行中配置修改窗口。
|
|
6
|
-
* - instruction
|
|
6
|
+
* - Agent instruction 修改不能改变已有 Session;env 与 plugin registry 修改在 step 检查点生效。
|
|
7
7
|
* - config 与 steer 在同一个 Session step 检查点提交,并继续使用同一个 turn id。
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -58,7 +58,7 @@ function create_stream_text_result(text) {
|
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
test("
|
|
61
|
+
test("Agent instruction changes only affect newly created Sessions", async () => {
|
|
62
62
|
const agent_path = await fs.mkdtemp(
|
|
63
63
|
path.join(os.tmpdir(), "downcity-agent-config-turn-boundary-"),
|
|
64
64
|
);
|
|
@@ -133,8 +133,8 @@ test("running Agent config changes and steer apply at the same Session step chec
|
|
|
133
133
|
assert.equal((await steer_turn.finished).success, true);
|
|
134
134
|
assert.equal(plugin_stop_count, 1);
|
|
135
135
|
assert.equal(provider_prompts.length, 2);
|
|
136
|
-
assert.match(provider_prompts[1], /instruction:
|
|
137
|
-
assert.doesNotMatch(provider_prompts[1], /instruction:
|
|
136
|
+
assert.match(provider_prompts[1], /instruction:old/);
|
|
137
|
+
assert.doesNotMatch(provider_prompts[1], /instruction:new/);
|
|
138
138
|
assert.doesNotMatch(provider_prompts[1], /plugin-env:old/);
|
|
139
139
|
|
|
140
140
|
const messages = await session.messages();
|
|
@@ -142,16 +142,167 @@ test("running Agent config changes and steer apply at the same Session step chec
|
|
|
142
142
|
.filter((message) => message.type === "action" && message.status === "completed")
|
|
143
143
|
.map((message) => message.title);
|
|
144
144
|
assert.deepEqual(completed_actions, [
|
|
145
|
-
"Agent instruction updated",
|
|
146
145
|
"Agent environment updated",
|
|
147
146
|
"Agent plugin runtime-config unregistered",
|
|
148
147
|
]);
|
|
148
|
+
|
|
149
|
+
// 未显式 snapshot 的 Session 重新装载时使用 Agent 当前 instruction。
|
|
150
|
+
await agent.sessions.clear_messages(session.id);
|
|
151
|
+
const restored_session = await agent.sessions.get(session.id);
|
|
152
|
+
const restored_system = await restored_session.system();
|
|
153
|
+
const restored_system_text = restored_system.blocks
|
|
154
|
+
.map((block) => block.content)
|
|
155
|
+
.join("\n");
|
|
156
|
+
assert.match(restored_system_text, /instruction:new/);
|
|
157
|
+
assert.doesNotMatch(restored_system_text, /instruction:old/);
|
|
158
|
+
|
|
159
|
+
const new_session = await agent.sessions.create({
|
|
160
|
+
sessionId: "config_turn_boundary_new_session",
|
|
161
|
+
});
|
|
162
|
+
const new_system = await new_session.system();
|
|
163
|
+
const new_system_text = new_system.blocks
|
|
164
|
+
.map((block) => block.content)
|
|
165
|
+
.join("\n");
|
|
166
|
+
assert.match(new_system_text, /instruction:new/);
|
|
167
|
+
assert.doesNotMatch(new_system_text, /instruction:old/);
|
|
149
168
|
} finally {
|
|
150
169
|
release_first_provider_request.resolve();
|
|
151
170
|
await agent.dispose();
|
|
152
171
|
}
|
|
153
172
|
});
|
|
154
173
|
|
|
174
|
+
test("Session snapshot explicitly persists instruction.md", async () => {
|
|
175
|
+
const agent_path = await fs.mkdtemp(
|
|
176
|
+
path.join(os.tmpdir(), "downcity-agent-instruction-restart-"),
|
|
177
|
+
);
|
|
178
|
+
const model = new MockLanguageModelV3({ modelId: "instruction-restart-model" });
|
|
179
|
+
const first_agent = new Agent({
|
|
180
|
+
id: "instruction_restart_agent",
|
|
181
|
+
path: agent_path,
|
|
182
|
+
model,
|
|
183
|
+
instruction: ["instruction:old"],
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const session = await first_agent.sessions.create({
|
|
188
|
+
sessionId: "instruction_restart_session",
|
|
189
|
+
});
|
|
190
|
+
const first_system = await session.system();
|
|
191
|
+
assert.match(
|
|
192
|
+
first_system.blocks.map((block) => block.content).join("\n"),
|
|
193
|
+
/instruction:old/,
|
|
194
|
+
);
|
|
195
|
+
await session.snapshot();
|
|
196
|
+
|
|
197
|
+
const instruction_path = path.join(
|
|
198
|
+
agent_path,
|
|
199
|
+
".downcity",
|
|
200
|
+
"agents",
|
|
201
|
+
"instruction_restart_agent",
|
|
202
|
+
"sessions",
|
|
203
|
+
"instruction_restart_session",
|
|
204
|
+
"instruction.md",
|
|
205
|
+
);
|
|
206
|
+
assert.equal(await fs.readFile(instruction_path, "utf8"), "instruction:old");
|
|
207
|
+
|
|
208
|
+
await fs.writeFile(instruction_path, "instruction:manual", "utf8");
|
|
209
|
+
await session.snapshot();
|
|
210
|
+
assert.equal(await fs.readFile(instruction_path, "utf8"), "instruction:old");
|
|
211
|
+
} finally {
|
|
212
|
+
await first_agent.dispose();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const restarted_agent = new Agent({
|
|
216
|
+
id: "instruction_restart_agent",
|
|
217
|
+
path: agent_path,
|
|
218
|
+
model,
|
|
219
|
+
instruction: ["instruction:new"],
|
|
220
|
+
});
|
|
221
|
+
try {
|
|
222
|
+
const restored_session = await restarted_agent.sessions.get(
|
|
223
|
+
"instruction_restart_session",
|
|
224
|
+
);
|
|
225
|
+
const restored_system = await restored_session.system();
|
|
226
|
+
const restored_system_text = restored_system.blocks
|
|
227
|
+
.map((block) => block.content)
|
|
228
|
+
.join("\n");
|
|
229
|
+
assert.match(restored_system_text, /instruction:old/);
|
|
230
|
+
assert.doesNotMatch(restored_system_text, /instruction:new/);
|
|
231
|
+
} finally {
|
|
232
|
+
await restarted_agent.dispose();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const instruction_path = path.join(
|
|
236
|
+
agent_path,
|
|
237
|
+
".downcity",
|
|
238
|
+
"agents",
|
|
239
|
+
"instruction_restart_agent",
|
|
240
|
+
"sessions",
|
|
241
|
+
"instruction_restart_session",
|
|
242
|
+
"instruction.md",
|
|
243
|
+
);
|
|
244
|
+
await fs.rm(instruction_path);
|
|
245
|
+
|
|
246
|
+
const fallback_agent = new Agent({
|
|
247
|
+
id: "instruction_restart_agent",
|
|
248
|
+
path: agent_path,
|
|
249
|
+
model,
|
|
250
|
+
instruction: ["instruction:new"],
|
|
251
|
+
});
|
|
252
|
+
try {
|
|
253
|
+
const fallback_session = await fallback_agent.sessions.get(
|
|
254
|
+
"instruction_restart_session",
|
|
255
|
+
);
|
|
256
|
+
const fallback_system = await fallback_session.system();
|
|
257
|
+
const fallback_system_text = fallback_system.blocks
|
|
258
|
+
.map((block) => block.content)
|
|
259
|
+
.join("\n");
|
|
260
|
+
assert.match(fallback_system_text, /instruction:new/);
|
|
261
|
+
assert.doesNotMatch(fallback_system_text, /instruction:old/);
|
|
262
|
+
} finally {
|
|
263
|
+
await fallback_agent.dispose();
|
|
264
|
+
await fs.rm(agent_path, { recursive: true, force: true });
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test("empty Session snapshot suppresses Agent instruction after restart", async () => {
|
|
269
|
+
const agent_path = await fs.mkdtemp(
|
|
270
|
+
path.join(os.tmpdir(), "downcity-agent-empty-instruction-snapshot-"),
|
|
271
|
+
);
|
|
272
|
+
const model = new MockLanguageModelV3({ modelId: "empty-snapshot-model" });
|
|
273
|
+
const first_agent = new Agent({
|
|
274
|
+
id: "empty_snapshot_agent",
|
|
275
|
+
path: agent_path,
|
|
276
|
+
model,
|
|
277
|
+
});
|
|
278
|
+
try {
|
|
279
|
+
const session = await first_agent.sessions.create({
|
|
280
|
+
sessionId: "empty_snapshot_session",
|
|
281
|
+
});
|
|
282
|
+
await session.snapshot();
|
|
283
|
+
} finally {
|
|
284
|
+
await first_agent.dispose();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const restarted_agent = new Agent({
|
|
288
|
+
id: "empty_snapshot_agent",
|
|
289
|
+
path: agent_path,
|
|
290
|
+
model,
|
|
291
|
+
instruction: ["instruction:must-not-appear"],
|
|
292
|
+
});
|
|
293
|
+
try {
|
|
294
|
+
const session = await restarted_agent.sessions.get("empty_snapshot_session");
|
|
295
|
+
const system = await session.system();
|
|
296
|
+
assert.doesNotMatch(
|
|
297
|
+
system.blocks.map((block) => block.content).join("\n"),
|
|
298
|
+
/instruction:must-not-appear/,
|
|
299
|
+
);
|
|
300
|
+
} finally {
|
|
301
|
+
await restarted_agent.dispose();
|
|
302
|
+
await fs.rm(agent_path, { recursive: true, force: true });
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
155
306
|
test("running session model changes apply with steer at the next Session step", async () => {
|
|
156
307
|
const agent_path = await fs.mkdtemp(
|
|
157
308
|
path.join(os.tmpdir(), "downcity-session-step-boundary-"),
|
package/src/agent/Agent.ts
CHANGED
|
@@ -159,7 +159,6 @@ export class Agent {
|
|
|
159
159
|
setInstruction(input: string | string[]): void {
|
|
160
160
|
const next_instruction = normalizeInstructionInput(input);
|
|
161
161
|
this.instruction.splice(0, this.instruction.length, ...next_instruction);
|
|
162
|
-
this.sessions.broadcast_instruction(this.instruction, generateId());
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
/**
|
|
@@ -146,23 +146,6 @@ export class AgentSessions implements AgentSessionsContract<AgentSession> {
|
|
|
146
146
|
return this.list_executing_session_ids().length;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
/**
|
|
150
|
-
* 把 Agent instruction 修改广播到已有 Session 的统一输入队列。
|
|
151
|
-
*/
|
|
152
|
-
broadcast_instruction(instruction: string[], command_id: string): void {
|
|
153
|
-
const instruction_blocks = createInstructionSystemBlocks(
|
|
154
|
-
instruction,
|
|
155
|
-
this.project_root,
|
|
156
|
-
);
|
|
157
|
-
for (const session of this.sessions_by_id.values()) {
|
|
158
|
-
session.enqueue_agent_command({
|
|
159
|
-
type: "instruction",
|
|
160
|
-
command_id,
|
|
161
|
-
instruction_blocks,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
149
|
/**
|
|
167
150
|
* 把 Agent env 修改广播到已有 Session 的统一输入队列。
|
|
168
151
|
*/
|
|
@@ -198,9 +181,7 @@ export class AgentSessions implements AgentSessionsContract<AgentSession> {
|
|
|
198
181
|
* 获取或创建一个 session runtime port。
|
|
199
182
|
*/
|
|
200
183
|
runtime(session_id: string): SessionPort {
|
|
201
|
-
return this.get_or_create_session({
|
|
202
|
-
session_id,
|
|
203
|
-
}).getRuntimePort();
|
|
184
|
+
return this.get_or_create_session({ session_id }).getRuntimePort();
|
|
204
185
|
}
|
|
205
186
|
|
|
206
187
|
/**
|
|
@@ -436,7 +417,7 @@ export class AgentSessions implements AgentSessionsContract<AgentSession> {
|
|
|
436
417
|
sessionId: resolved_session_id,
|
|
437
418
|
tools: this.tools,
|
|
438
419
|
logger: this.logger,
|
|
439
|
-
|
|
420
|
+
instruction_system_blocks: this.load_instruction_system_blocks(),
|
|
440
421
|
getAgentEnv: () => this.get_agent_env(),
|
|
441
422
|
getAgentModel: () => this.get_agent_model(),
|
|
442
423
|
get_agent_plugins: () => this.get_agent_plugins(),
|
package/src/session/Session.ts
CHANGED
|
@@ -74,6 +74,10 @@ import { nanoid } from "nanoid";
|
|
|
74
74
|
import { buildSessionInfo } from "@/session/browse/Browse.js";
|
|
75
75
|
import { ensureSessionTitle } from "@/session/SessionTitle.js";
|
|
76
76
|
import { readSessionMetadata } from "@/session/storage/Metadata.js";
|
|
77
|
+
import {
|
|
78
|
+
read_session_instruction,
|
|
79
|
+
write_session_instruction,
|
|
80
|
+
} from "@/session/storage/Instruction.js";
|
|
77
81
|
import { to_executor_history } from "@/session/messages/SessionMessageCodec.js";
|
|
78
82
|
import type { SessionMessage } from "@/types/session/SessionMessage.js";
|
|
79
83
|
import type {
|
|
@@ -91,7 +95,6 @@ export class Session implements AgentSession {
|
|
|
91
95
|
private readonly project_root: string;
|
|
92
96
|
private readonly tools: Record<string, Tool>;
|
|
93
97
|
private readonly logger: SessionOptions["logger"];
|
|
94
|
-
private readonly get_instruction_system_blocks: SessionOptions["getInstructionSystemBlocks"];
|
|
95
98
|
private readonly get_managed_plugin_system_blocks: SessionOptions["getManagedPluginSystemBlocks"];
|
|
96
99
|
private readonly ensure_configured_hook?: SessionOptions["ensureConfigured"];
|
|
97
100
|
private readonly composer: SessionComposer;
|
|
@@ -105,6 +108,7 @@ export class Session implements AgentSession {
|
|
|
105
108
|
private readonly get_agent_model: SessionOptions["getAgentModel"];
|
|
106
109
|
private readonly get_agent_plugins: SessionOptions["get_agent_plugins"];
|
|
107
110
|
private effective_instruction_system_blocks: AgentSessionSystemBlock[];
|
|
111
|
+
private instruction_initialize_promise: Promise<void> | null = null;
|
|
108
112
|
private effective_agent_env: Record<string, string>;
|
|
109
113
|
private effective_agent_plugins: AgentPluginExecutionRuntime;
|
|
110
114
|
private readonly state: SessionState;
|
|
@@ -117,12 +121,11 @@ export class Session implements AgentSession {
|
|
|
117
121
|
this.project_root = String(options.projectRoot || "").trim();
|
|
118
122
|
this.tools = options.tools;
|
|
119
123
|
this.logger = options.logger;
|
|
120
|
-
this.get_instruction_system_blocks = options.getInstructionSystemBlocks;
|
|
121
124
|
this.get_agent_env = options.getAgentEnv;
|
|
122
125
|
this.get_agent_model = options.getAgentModel;
|
|
123
126
|
this.get_agent_plugins = options.get_agent_plugins;
|
|
124
127
|
this.effective_instruction_system_blocks = options
|
|
125
|
-
.
|
|
128
|
+
.instruction_system_blocks
|
|
126
129
|
.map((block) => ({ ...block }));
|
|
127
130
|
this.effective_agent_env = { ...options.getAgentEnv() };
|
|
128
131
|
this.effective_agent_plugins = options.get_agent_plugins();
|
|
@@ -188,11 +191,35 @@ export class Session implements AgentSession {
|
|
|
188
191
|
* 初始化当前 session。
|
|
189
192
|
*/
|
|
190
193
|
async initialize(): Promise<this> {
|
|
191
|
-
await
|
|
192
|
-
|
|
194
|
+
await Promise.all([
|
|
195
|
+
this.initialize_instruction(),
|
|
196
|
+
this.session_messages.initialize(),
|
|
197
|
+
this.state.initialize(),
|
|
198
|
+
]);
|
|
193
199
|
return this;
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
/**
|
|
203
|
+
* 把当前 Session 生效的自定义 instruction 显式固化到 instruction.md。
|
|
204
|
+
*
|
|
205
|
+
* 关键点(中文)
|
|
206
|
+
* - 只写入 `instruction` 来源的 block,不包含 SDK core 与 plugin system。
|
|
207
|
+
* - 多个 instruction block 按原顺序合并为一个 Markdown 文档。
|
|
208
|
+
*/
|
|
209
|
+
async snapshot(): Promise<void> {
|
|
210
|
+
await this.initialize_instruction();
|
|
211
|
+
const instruction = this.effective_instruction_system_blocks
|
|
212
|
+
.filter((block) => block.source === "instruction")
|
|
213
|
+
.map((block) => block.content)
|
|
214
|
+
.join("\n\n");
|
|
215
|
+
await write_session_instruction({
|
|
216
|
+
project_root: this.project_root,
|
|
217
|
+
agent_id: this.agentId,
|
|
218
|
+
session_id: this.id,
|
|
219
|
+
instruction,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
196
223
|
/**
|
|
197
224
|
* 读取当前 session 配置快照。
|
|
198
225
|
*/
|
|
@@ -214,6 +241,7 @@ export class Session implements AgentSession {
|
|
|
214
241
|
* 追加一条新的 Session prompt。
|
|
215
242
|
*/
|
|
216
243
|
async prompt(input: AgentSessionPromptInput): Promise<AgentSessionTurnHandle> {
|
|
244
|
+
await this.initialize_instruction();
|
|
217
245
|
return await this.session_turn.prompt(input);
|
|
218
246
|
}
|
|
219
247
|
|
|
@@ -236,14 +264,6 @@ export class Session implements AgentSession {
|
|
|
236
264
|
* 把 Agent configured state command 加入当前 Session 的统一输入队列。
|
|
237
265
|
*/
|
|
238
266
|
enqueue_agent_command(command: AgentSessionCommand): void {
|
|
239
|
-
if (command.type === "instruction") {
|
|
240
|
-
this.session_turn.enqueue_command({
|
|
241
|
-
type: "agent_instruction",
|
|
242
|
-
command_id: command.command_id,
|
|
243
|
-
instruction_blocks: command.instruction_blocks,
|
|
244
|
-
});
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
267
|
if (command.type === "env") {
|
|
248
268
|
this.session_turn.enqueue_command({
|
|
249
269
|
type: "agent_env",
|
|
@@ -277,18 +297,6 @@ export class Session implements AgentSession {
|
|
|
277
297
|
}
|
|
278
298
|
return;
|
|
279
299
|
}
|
|
280
|
-
if (command.type === "agent_instruction") {
|
|
281
|
-
this.effective_instruction_system_blocks = command.instruction_blocks.map(
|
|
282
|
-
(block) => ({ ...block }),
|
|
283
|
-
);
|
|
284
|
-
await this.emit_config_action_event({
|
|
285
|
-
id: `agent-instruction:${this.id}:${command.command_id}`,
|
|
286
|
-
title: "Agent instruction updated",
|
|
287
|
-
state: "completed",
|
|
288
|
-
turnId: turn_id,
|
|
289
|
-
});
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
300
|
if (command.type === "agent_env") {
|
|
293
301
|
this.effective_agent_env = { ...command.env };
|
|
294
302
|
await this.emit_config_action_event({
|
|
@@ -406,6 +414,7 @@ export class Session implements AgentSession {
|
|
|
406
414
|
* 读取当前 session 生效的 system 快照。
|
|
407
415
|
*/
|
|
408
416
|
async system(): Promise<AgentSessionSystemSnapshot> {
|
|
417
|
+
await this.initialize_instruction();
|
|
409
418
|
const composed = await this.compose_for_view();
|
|
410
419
|
const blocks = resolve_composed_system_blocks(composed);
|
|
411
420
|
return {
|
|
@@ -533,6 +542,7 @@ export class Session implements AgentSession {
|
|
|
533
542
|
* 在执行前确保 session 已完成初始化与宿主装配。
|
|
534
543
|
*/
|
|
535
544
|
async ensureReadyForExecution(): Promise<void> {
|
|
545
|
+
await this.initialize_instruction();
|
|
536
546
|
await this.state.ensure_ready_for_execution();
|
|
537
547
|
}
|
|
538
548
|
|
|
@@ -543,7 +553,9 @@ export class Session implements AgentSession {
|
|
|
543
553
|
sessionId: session_id,
|
|
544
554
|
tools: this.tools,
|
|
545
555
|
logger: this.logger,
|
|
546
|
-
|
|
556
|
+
instruction_system_blocks: this.effective_instruction_system_blocks.map(
|
|
557
|
+
(block) => ({ ...block }),
|
|
558
|
+
),
|
|
547
559
|
getAgentEnv: this.get_agent_env,
|
|
548
560
|
get_agent_plugins: this.get_agent_plugins,
|
|
549
561
|
getManagedPluginSystemBlocks: this.get_managed_plugin_system_blocks,
|
|
@@ -567,6 +579,36 @@ export class Session implements AgentSession {
|
|
|
567
579
|
return new SessionClass(options) as this;
|
|
568
580
|
}
|
|
569
581
|
|
|
582
|
+
/** 恢复显式固化的 instruction.md;文件不存在时保留创建时 instruction。 */
|
|
583
|
+
private async initialize_instruction(): Promise<void> {
|
|
584
|
+
if (!this.instruction_initialize_promise) {
|
|
585
|
+
this.instruction_initialize_promise = (async () => {
|
|
586
|
+
const persisted_instruction = await read_session_instruction({
|
|
587
|
+
project_root: this.project_root,
|
|
588
|
+
agent_id: this.agentId,
|
|
589
|
+
session_id: this.id,
|
|
590
|
+
});
|
|
591
|
+
if (persisted_instruction === null) return;
|
|
592
|
+
|
|
593
|
+
const instruction = persisted_instruction.trim();
|
|
594
|
+
const stable_system_blocks = this.effective_instruction_system_blocks
|
|
595
|
+
.filter((block) => block.source !== "instruction")
|
|
596
|
+
.map((block) => ({ ...block }));
|
|
597
|
+
this.effective_instruction_system_blocks = [
|
|
598
|
+
...(instruction
|
|
599
|
+
? [{
|
|
600
|
+
source: "instruction" as const,
|
|
601
|
+
name: "agent",
|
|
602
|
+
content: instruction,
|
|
603
|
+
}]
|
|
604
|
+
: []),
|
|
605
|
+
...stable_system_blocks,
|
|
606
|
+
];
|
|
607
|
+
})();
|
|
608
|
+
}
|
|
609
|
+
await this.instruction_initialize_promise;
|
|
610
|
+
}
|
|
611
|
+
|
|
570
612
|
private create_message_store(): JsonlSessionMessageStore {
|
|
571
613
|
const session_dir_path = getSdkAgentSessionDirPath(
|
|
572
614
|
this.project_root,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session instruction 显式快照存储。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - instruction.md 是可选文件,不存在时由 Session 使用 Agent 当前 instruction。
|
|
6
|
+
* - 空文件也是有效快照,用于显式固化没有自定义 instruction 的状态。
|
|
7
|
+
* - 写入使用同目录临时文件替换,避免进程中断留下半份内容。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import fs from "fs-extra";
|
|
13
|
+
import { getSdkAgentSessionInstructionPath } from "@/session/storage/Paths.js";
|
|
14
|
+
import type {
|
|
15
|
+
SessionInstructionStorageLocation,
|
|
16
|
+
WriteSessionInstructionInput,
|
|
17
|
+
} from "@/types/session/SessionInstruction.js";
|
|
18
|
+
|
|
19
|
+
/** 读取 Session 显式固化的 instruction;文件不存在时返回 null。 */
|
|
20
|
+
export async function read_session_instruction(
|
|
21
|
+
input: SessionInstructionStorageLocation,
|
|
22
|
+
): Promise<string | null> {
|
|
23
|
+
const instruction_path = getSdkAgentSessionInstructionPath(
|
|
24
|
+
input.project_root,
|
|
25
|
+
input.agent_id,
|
|
26
|
+
input.session_id,
|
|
27
|
+
);
|
|
28
|
+
try {
|
|
29
|
+
return await fs.readFile(instruction_path, "utf8");
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 原子覆盖当前 Session 的 instruction.md。 */
|
|
37
|
+
export async function write_session_instruction(
|
|
38
|
+
input: WriteSessionInstructionInput,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
const instruction_path = getSdkAgentSessionInstructionPath(
|
|
41
|
+
input.project_root,
|
|
42
|
+
input.agent_id,
|
|
43
|
+
input.session_id,
|
|
44
|
+
);
|
|
45
|
+
const temporary_path = [
|
|
46
|
+
instruction_path,
|
|
47
|
+
process.pid,
|
|
48
|
+
Date.now(),
|
|
49
|
+
randomUUID(),
|
|
50
|
+
"tmp",
|
|
51
|
+
].join(".");
|
|
52
|
+
await fs.ensureDir(path.dirname(instruction_path));
|
|
53
|
+
try {
|
|
54
|
+
await fs.writeFile(temporary_path, input.instruction, "utf8");
|
|
55
|
+
await fs.move(temporary_path, instruction_path, { overwrite: true });
|
|
56
|
+
} finally {
|
|
57
|
+
await fs.remove(temporary_path);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -129,6 +129,24 @@ export function getSdkAgentSessionDirPath(
|
|
|
129
129
|
);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
/**
|
|
133
|
+
* 单个 session 显式固化的 instruction.md 路径。
|
|
134
|
+
*
|
|
135
|
+
* 关键点(中文)
|
|
136
|
+
* - 文件不存在表示 Session 恢复时继续采用 Agent 当前 instruction。
|
|
137
|
+
* - 空文件表示调用方显式固化了空 instruction。
|
|
138
|
+
*/
|
|
139
|
+
export function getSdkAgentSessionInstructionPath(
|
|
140
|
+
projectRoot: string,
|
|
141
|
+
agentId: string,
|
|
142
|
+
sessionId: string,
|
|
143
|
+
): string {
|
|
144
|
+
return path.join(
|
|
145
|
+
getSdkAgentSessionDirPath(projectRoot, agentId, sessionId),
|
|
146
|
+
"instruction.md",
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
132
150
|
/**
|
|
133
151
|
* 单个 session 的消息目录路径。
|
|
134
152
|
*/
|