@downcity/agent 1.1.335 → 1.1.338

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.
Files changed (32) hide show
  1. package/bin/executor/core-engine/CoreEngineContextCompaction.d.ts.map +1 -1
  2. package/bin/executor/core-engine/CoreEngineContextCompaction.js +14 -64
  3. package/bin/executor/core-engine/CoreEngineContextCompaction.js.map +1 -1
  4. package/bin/executor/messages/SessionMessageCodec.js +1 -62
  5. package/bin/executor/messages/SessionMessageCodec.js.map +1 -1
  6. package/bin/index.d.ts +1 -1
  7. package/bin/index.d.ts.map +1 -1
  8. package/bin/index.js.map +1 -1
  9. package/bin/session/Session.d.ts.map +1 -1
  10. package/bin/session/Session.js +23 -2
  11. package/bin/session/Session.js.map +1 -1
  12. package/bin/types/agent/SessionTypes.d.ts +9 -1
  13. package/bin/types/agent/SessionTypes.d.ts.map +1 -1
  14. package/bin/types/session/SessionMutation.d.ts +15 -2
  15. package/bin/types/session/SessionMutation.d.ts.map +1 -1
  16. package/bin/types/session/SessionMutation.js.map +1 -1
  17. package/bin/workspace/WorkspacePaths.d.ts +0 -22
  18. package/bin/workspace/WorkspacePaths.d.ts.map +1 -1
  19. package/bin/workspace/WorkspacePaths.js +2 -30
  20. package/bin/workspace/WorkspacePaths.js.map +1 -1
  21. package/package.json +6 -6
  22. package/scripts/core-engine-context-compaction.test.mjs +4 -4
  23. package/scripts/session-config-turn-boundary.test.mjs +9 -0
  24. package/scripts/session-messages.test.mjs +0 -38
  25. package/src/executor/core-engine/CoreEngineContextCompaction.ts +19 -75
  26. package/src/executor/messages/SessionMessageCodec.ts +1 -68
  27. package/src/index.ts +2 -0
  28. package/src/session/Session.ts +25 -1
  29. package/src/types/agent/SessionTypes.ts +10 -1
  30. package/src/types/session/SessionMutation.ts +17 -2
  31. package/src/workspace/WorkspacePaths.ts +2 -33
  32. package/tsconfig.tsbuildinfo +1 -1
@@ -117,8 +117,8 @@ export type SessionCompactMutation = SessionMutationBase & {
117
117
  /** 压缩失败时的错误文本。 */
118
118
  error?: string;
119
119
  };
120
- /** Session 自身属性变化 Mutation。 */
121
- export type SessionStateMutation = SessionMutationBase & {
120
+ /** Session 标题变化 Mutation。 */
121
+ export type SessionTitleMutation = SessionMutationBase & {
122
122
  /** Mutation 层级固定为 session。 */
123
123
  variant: "session";
124
124
  /** 当前 Session 属性变化类型。 */
@@ -126,6 +126,19 @@ export type SessionStateMutation = SessionMutationBase & {
126
126
  /** 当前 Session 最新标题。 */
127
127
  title: string;
128
128
  };
129
+ /** Session 模型配置变化 Mutation。 */
130
+ export type SessionConfigMutation = SessionMutationBase & {
131
+ /** Mutation 层级固定为 session。 */
132
+ variant: "session";
133
+ /** 当前 Session 属性变化类型。 */
134
+ type: "config";
135
+ /** 当前 Session 已接受的模型可读标签。 */
136
+ model_label?: string;
137
+ /** 当前模型支持的总上下文窗口长度,单位为 token。 */
138
+ model_context_window?: number;
139
+ };
140
+ /** Session 自身属性变化 Mutation。 */
141
+ export type SessionStateMutation = SessionTitleMutation | SessionConfigMutation;
129
142
  /** Session 对外唯一实时 Mutation 联合类型。 */
130
143
  export type SessionMutation = SessionMessageMutation | SessionPartMutation | SessionDeltaMutation | SessionTurnMutation | SessionCompactMutation | SessionStateMutation;
131
144
  /** Session Mutation 订阅回调。 */
@@ -1 +1 @@
1
- {"version":3,"file":"SessionMutation.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionMutation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionMutation.d.ts","sourceRoot":"","sources":["../../../src/types/session/SessionMutation.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SessionMutation.js","sourceRoot":"","sources":["../../../src/types/session/SessionMutation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsJH,kCAAkC;AAClC,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,SAAS,GAAG,KAAqE,CAAC;IACxF,IAAI,OAAO,SAAS,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClG,OAAO,CACL,SAAS,CAAC,OAAO,KAAK,SAAS;QAC/B,SAAS,CAAC,OAAO,KAAK,MAAM;QAC5B,SAAS,CAAC,OAAO,KAAK,OAAO;QAC7B,SAAS,CAAC,OAAO,KAAK,MAAM;QAC5B,SAAS,CAAC,OAAO,KAAK,SAAS;QAC/B,SAAS,CAAC,OAAO,KAAK,SAAS,CAChC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"SessionMutation.js","sourceRoot":"","sources":["../../../src/types/session/SessionMutation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqKH,kCAAkC;AAClC,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,SAAS,GAAG,KAAqE,CAAC;IACxF,IAAI,OAAO,SAAS,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClG,OAAO,CACL,SAAS,CAAC,OAAO,KAAK,SAAS;QAC/B,SAAS,CAAC,OAAO,KAAK,MAAM;QAC5B,SAAS,CAAC,OAAO,KAAK,OAAO;QAC7B,SAAS,CAAC,OAAO,KAAK,MAAM;QAC5B,SAAS,CAAC,OAAO,KAAK,SAAS;QAC/B,SAAS,CAAC,OAAO,KAAK,SAAS,CAChC,CAAC;AACJ,CAAC"}
@@ -13,28 +13,6 @@ export declare function get_logs_dir_path(cwd: string): string;
13
13
  * - 当前使用隐藏命名 `.cache`,避免与用户业务目录混淆。
14
14
  */
15
15
  export declare function get_cache_dir_path(cwd: string): string;
16
- /**
17
- * 返回 profile 运行态目录路径。
18
- *
19
- * 关键点(中文)
20
- * - 初始化流程会统一创建该目录,并在其中写入 profile 相关文件。
21
- * - 单独保留目录级 API,避免调用方散落 `path.join(..., "profile")`。
22
- */
23
- export declare function get_downcity_profile_dir_path(cwd: string): string;
24
- /**
25
- * 返回 profile 主记忆文件路径。
26
- *
27
- * 关键点(中文)
28
- * - 该文件通常承载主画像或核心长期 profile 信息。
29
- */
30
- export declare function get_downcity_profile_primary_path(cwd: string): string;
31
- /**
32
- * 返回 profile 补充记忆文件路径。
33
- *
34
- * 关键点(中文)
35
- * - 该文件用于存放不适合进入主 profile 的补充材料。
36
- */
37
- export declare function get_downcity_profile_other_path(cwd: string): string;
38
16
  /**
39
17
  * Plugin Schedule JSONL 路径。
40
18
  *
@@ -1 +1 @@
1
- {"version":3,"file":"WorkspacePaths.d.ts","sourceRoot":"","sources":["../../src/workspace/WorkspacePaths.ts"],"names":[],"mappings":"AAcA;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/D"}
1
+ {"version":3,"file":"WorkspacePaths.d.ts","sourceRoot":"","sources":["../../src/workspace/WorkspacePaths.ts"],"names":[],"mappings":"AAcA;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/D"}
@@ -2,13 +2,13 @@
2
2
  * Workspace 项目路径规则模块。
3
3
  *
4
4
  * 职责说明(中文)
5
- * - 统一管理单个 agent 项目根目录下的静态文件、`.downcity` 目录与运行时状态文件路径。
5
+ * - 统一管理 Workspace 根目录下的 `.downcity` 运行时状态路径。
6
6
  * - 负责把“路径协议”集中到一个模块,避免各领域模块自行拼接字符串。
7
7
  * - 为初始化、日志、任务与调试文件等非 Store 子系统提供一致的路径入口。
8
8
  *
9
9
  * 边界说明(中文)
10
10
  * - 这里只负责路径计算,不负责目录创建、文件读写或存在性校验。
11
- * - 这里描述的是单项目约定,不涉及平台级全局目录布局。
11
+ * - 这里描述的是 Workspace 约定,不涉及 Agent Memory 或平台级全局目录布局。
12
12
  */
13
13
  import path from "path";
14
14
  /**
@@ -32,34 +32,6 @@ export function get_logs_dir_path(cwd) {
32
32
  export function get_cache_dir_path(cwd) {
33
33
  return path.join(get_downcity_dir_path(cwd), ".cache");
34
34
  }
35
- /**
36
- * 返回 profile 运行态目录路径。
37
- *
38
- * 关键点(中文)
39
- * - 初始化流程会统一创建该目录,并在其中写入 profile 相关文件。
40
- * - 单独保留目录级 API,避免调用方散落 `path.join(..., "profile")`。
41
- */
42
- export function get_downcity_profile_dir_path(cwd) {
43
- return path.join(get_downcity_dir_path(cwd), "profile");
44
- }
45
- /**
46
- * 返回 profile 主记忆文件路径。
47
- *
48
- * 关键点(中文)
49
- * - 该文件通常承载主画像或核心长期 profile 信息。
50
- */
51
- export function get_downcity_profile_primary_path(cwd) {
52
- return path.join(get_downcity_profile_dir_path(cwd), "Primary.md");
53
- }
54
- /**
55
- * 返回 profile 补充记忆文件路径。
56
- *
57
- * 关键点(中文)
58
- * - 该文件用于存放不适合进入主 profile 的补充材料。
59
- */
60
- export function get_downcity_profile_other_path(cwd) {
61
- return path.join(get_downcity_profile_dir_path(cwd), "other.md");
62
- }
63
35
  /**
64
36
  * Plugin Schedule JSONL 路径。
65
37
  *
@@ -1 +1 @@
1
- {"version":3,"file":"WorkspacePaths.js","sourceRoot":"","sources":["../../src/workspace/WorkspacePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAAW;IACvD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iCAAiC,CAAC,GAAW;IAC3D,OAAO,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;AACrE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAAC,GAAW;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAAW;IACvD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,GAAW;IACpD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,4BAA4B,CAAC,GAAW;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC"}
1
+ {"version":3,"file":"WorkspacePaths.js","sourceRoot":"","sources":["../../src/workspace/WorkspacePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAAW;IACvD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,GAAW;IACpD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,4BAA4B,CAAC,GAAW;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downcity/agent",
3
- "version": "1.1.335",
3
+ "version": "1.1.338",
4
4
  "type": "module",
5
5
  "description": "Downcity Agent 运行时 — 单 Agent 执行壳与本机 RPC 能力",
6
6
  "main": "./bin/index.js",
@@ -16,8 +16,8 @@
16
16
  }
17
17
  },
18
18
  "dependencies": {
19
- "@downcity/shell": "^0.1.170",
20
- "@downcity/type": "0.1.196",
19
+ "@downcity/shell": "^0.1.172",
20
+ "@downcity/type": "0.1.197",
21
21
  "ai": "^6.0.193",
22
22
  "commander": "^15.0.0",
23
23
  "dotenv": "^17.4.2",
@@ -32,9 +32,9 @@
32
32
  "zod": "^4.4.3"
33
33
  },
34
34
  "devDependencies": {
35
- "@downcity/sandbox-linux": "^0.1.34",
36
- "@downcity/sandbox-macos": "^0.1.34",
37
- "@downcity/sandbox-windows-mxc": "^0.1.34",
35
+ "@downcity/sandbox-linux": "^0.1.35",
36
+ "@downcity/sandbox-macos": "^0.1.35",
37
+ "@downcity/sandbox-windows-mxc": "^0.1.35",
38
38
  "@ai-sdk/openai": "^3.0.67",
39
39
  "@types/fs-extra": "^11.0.4",
40
40
  "@types/js-yaml": "^4.0.9",
@@ -335,9 +335,9 @@ test("deep compact 删除 reasoning,并完整保留最新并行 tool transacti
335
335
  const serialized = JSON.stringify(compacted);
336
336
  assert.equal(serialized.includes("old reasoning"), false);
337
337
  assert.equal(serialized.includes("latest reasoning"), false);
338
- assert.equal(serialized.includes('"itemId":"rs_latest"'), true);
338
+ assert.equal(serialized.includes('"itemId":"rs_latest"'), false);
339
339
  assert.equal(serialized.includes('"itemId":"msg_latest"'), false);
340
- assert.equal(serialized.includes('"phase":"final_answer"'), true);
340
+ assert.equal(serialized.includes('"phase":"final_answer"'), false);
341
341
  assert.equal(serialized.includes("latest request"), true);
342
342
  assert.equal(serialized.includes("call-a"), true);
343
343
  assert.equal(serialized.includes("call-b"), true);
@@ -359,8 +359,8 @@ test("deep compact 删除 reasoning,并完整保留最新并行 tool transacti
359
359
  assert.equal(active_tool_text.join("\n").includes("old-call"), false);
360
360
  assert.deepEqual([...tool_call_ids].sort(), ["call-a", "call-b"]);
361
361
  assert.deepEqual([...tool_result_ids].sort(), ["call-a", "call-b"]);
362
- assert.equal(serialized.includes('"itemId":"fc_a"'), true);
363
- assert.equal(serialized.includes('"resultId":"result_a"'), true);
362
+ assert.equal(serialized.includes('"itemId":"fc_a"'), false);
363
+ assert.equal(serialized.includes('"resultId":"result_a"'), false);
364
364
  });
365
365
 
366
366
  test("单条 assistant 含大量 parts 时也会在消息内部折叠", () => {
@@ -525,6 +525,15 @@ test("running session model changes apply with steer at the next Session step",
525
525
  );
526
526
  assert.equal(model_actions.length, 1);
527
527
  assert.equal(model_actions[0].status, "completed");
528
+ assert.equal(
529
+ mutations.some(
530
+ (mutation) =>
531
+ mutation.variant === "session" &&
532
+ mutation.type === "config" &&
533
+ mutation.model_label === "new-model",
534
+ ),
535
+ true,
536
+ );
528
537
  assert.equal(
529
538
  mutations.some(
530
539
  (mutation) =>
@@ -20,7 +20,6 @@ import {
20
20
  to_executor_history,
21
21
  to_executor_ui_message,
22
22
  } from "../bin/session/messages/SessionMessageCodec.js";
23
- import { to_model_messages } from "../bin/executor/messages/SessionMessageCodec.js";
24
23
  import { convertToModelMessages } from "ai";
25
24
  import { MockLanguageModelV3 } from "ai/test";
26
25
 
@@ -1258,43 +1257,6 @@ test("空 Reasoning 携带 Provider metadata 时作为跨轮重放协议 Part
1258
1257
  assert.deepEqual(assistant.parts[0].provider_metadata, reasoning_metadata);
1259
1258
  assert.deepEqual(assistant.parts[1].provider_metadata, message_metadata);
1260
1259
 
1261
- const restored = to_executor_ui_message(assistant);
1262
- const model_messages = await to_model_messages([restored], {});
1263
- const model_parts = model_messages.flatMap((message) =>
1264
- Array.isArray(message.content) ? message.content : []
1265
- );
1266
- assert.deepEqual(model_parts.map((part) => part.type), ["reasoning", "text"]);
1267
- assert.deepEqual(model_parts[0].providerOptions, reasoning_metadata);
1268
- assert.deepEqual(model_parts[1].providerOptions, message_metadata);
1269
- });
1270
-
1271
- test("旧 Session 缺少 Reasoning 协议 Part 时移除孤立 msg_* 引用", async () => {
1272
- const model_messages = await to_model_messages([{
1273
- id: "assistant-legacy",
1274
- role: "assistant",
1275
- metadata: {
1276
- v: 1,
1277
- ts: 1,
1278
- session_id: "legacy-session",
1279
- source: "egress",
1280
- kind: "normal",
1281
- },
1282
- parts: [{
1283
- type: "text",
1284
- text: "已持久化的回复",
1285
- state: "done",
1286
- providerMetadata: {
1287
- openai: { itemId: "msg_orphaned", phase: "final_answer" },
1288
- },
1289
- }],
1290
- }], {});
1291
- const text_part = model_messages
1292
- .flatMap((message) => Array.isArray(message.content) ? message.content : [])
1293
- .find((part) => part.type === "text");
1294
- assert.equal(text_part.text, "已持久化的回复");
1295
- assert.deepEqual(text_part.providerOptions, {
1296
- openai: { phase: "final_answer" },
1297
- });
1298
1260
  });
1299
1261
 
1300
1262
  test("空 Text Start 不会抢占后续 Tool 的真实顺序", async () => {
@@ -84,9 +84,8 @@ export function deep_compact_model_messages(
84
84
  const depth = Math.max(0, Math.min(8, Math.floor(compact_depth)));
85
85
  const pruned_messages = pruneMessages({
86
86
  messages,
87
- // Reasoning 由本模块在确定最新 Tool 事务后再清理,避免先丢失
88
- // OpenAI Responses API 中与 Tool item 原子关联的协议 Part。
89
- reasoning: "none",
87
+ // 压缩后只保留语义内容;Provider replay 状态由 Federation 在最终路由后按作用域决定。
88
+ reasoning: "all",
90
89
  // 工具事务由本模块按 toolCallId/approvalId 选择;先让 SDK 保留完整关联,
91
90
  // 避免 approval response 作为最后一条消息时 SDK 丢掉更早的 tool-call。
92
91
  toolCalls: "none",
@@ -345,8 +344,7 @@ function compact_retained_message(
345
344
  content: fold_compacted_text(message.content, message_limit),
346
345
  } as ModelMessage;
347
346
  }
348
- const retained_non_reasoning_parts = message.content.filter((part) => {
349
- if (part.type === "reasoning") return false;
347
+ const relevant_parts = message.content.filter((part) => {
350
348
  if (part.type === "tool-call" || part.type === "tool-result") {
351
349
  return selected_tool_call_ids.has(part.toolCallId);
352
350
  }
@@ -357,26 +355,13 @@ function compact_retained_message(
357
355
  const tool_call_id = approval_to_tool_call.get(part.approvalId);
358
356
  return Boolean(tool_call_id && selected_tool_call_ids.has(tool_call_id));
359
357
  }
360
- return true;
358
+ return part.type !== "reasoning";
361
359
  });
362
- const requires_provider_reasoning = retained_non_reasoning_parts.some(
363
- (part) =>
364
- (part.type === "tool-call" || part.type === "tool-result") &&
365
- has_openai_item_reference(part as unknown as Record<string, unknown>),
366
- );
367
- const relevant_parts = message.content.filter((part) =>
368
- part.type !== "reasoning" ||
369
- (requires_provider_reasoning &&
370
- has_openai_reasoning_replay_data(part as unknown as Record<string, unknown>))
371
- );
372
360
  const part_limit = Math.max(
373
361
  MIN_FOLDED_PART_CHARS,
374
362
  Math.floor(message_limit / Math.max(1, relevant_parts.length)),
375
363
  );
376
364
  const content = relevant_parts
377
- .filter((part) =>
378
- part.type === "reasoning" || retained_non_reasoning_parts.includes(part)
379
- )
380
365
  .map((part) =>
381
366
  compact_model_part(
382
367
  part as unknown as Record<string, unknown>,
@@ -391,29 +376,24 @@ function compact_model_part(
391
376
  part: Record<string, unknown>,
392
377
  part_limit: number,
393
378
  ): Record<string, unknown> {
379
+ const semantic_part = strip_provider_replay_state(part);
394
380
  if (part.type === "text") {
395
381
  return {
396
- ...part,
382
+ ...semantic_part,
397
383
  text: fold_compacted_text(String(part.text || ""), part_limit),
398
- ...without_openai_item_reference(part),
399
384
  };
400
385
  }
401
- if (part.type === "reasoning") {
402
- // 压缩不保留可见思维文本,但必须保留与最新 Tool 事务关联的
403
- // Responses API itemId / encrypted content,否则 Provider 会拒绝孤立的 Tool item。
404
- return { ...part, text: "" };
405
- }
406
386
  if (part.type === "tool-call") {
407
387
  return {
408
- ...part,
388
+ ...semantic_part,
409
389
  input: fold_compacted_value(part.input, part_limit),
410
390
  };
411
391
  }
412
392
  if (part.type === "tool-result") {
413
393
  const serialized_output = safe_stringify(part.output);
414
- if (serialized_output.length <= part_limit) return part;
394
+ if (serialized_output.length <= part_limit) return semantic_part;
415
395
  return {
416
- ...part,
396
+ ...semantic_part,
417
397
  output: {
418
398
  type: "text",
419
399
  value: fold_compacted_text(serialized_output, part_limit),
@@ -438,55 +418,19 @@ function compact_model_part(
438
418
  };
439
419
  }
440
420
  }
441
- return part;
442
- }
443
-
444
- /** 判断 Part 是否引用 OpenAI Responses API 中已存储的 item。 */
445
- function has_openai_item_reference(part: Record<string, unknown>): boolean {
446
- const provider_options = read_record(part.providerOptions);
447
- const openai_options = read_record(provider_options?.openai);
448
- return typeof openai_options?.itemId === "string" && openai_options.itemId.length > 0;
449
- }
450
-
451
- /** 判断空 Reasoning 是否仍携带可用于跨轮重放的 Provider 协议数据。 */
452
- function has_openai_reasoning_replay_data(part: Record<string, unknown>): boolean {
453
- const provider_options = read_record(part.providerOptions);
454
- const openai_options = read_record(provider_options?.openai);
455
- return (
456
- (typeof openai_options?.itemId === "string" && openai_options.itemId.length > 0) ||
457
- (typeof openai_options?.reasoningEncryptedContent === "string" &&
458
- openai_options.reasoningEncryptedContent.length > 0)
459
- );
421
+ return semantic_part;
460
422
  }
461
423
 
462
- /**
463
- * 压缩后的 Text 已经是新的语义投影,不能继续引用 Provider 中的原始 msg_* item。
464
- */
465
- function without_openai_item_reference(
424
+ /** 压缩后的模型 Part 只作为语义历史传递,不继续携带任何 Provider replay state。 */
425
+ function strip_provider_replay_state(
466
426
  part: Record<string, unknown>,
467
- ): Pick<Record<string, unknown>, "providerOptions"> | Record<string, never> {
468
- const provider_options = read_record(part.providerOptions);
469
- const openai_options = read_record(provider_options?.openai);
470
- if (!provider_options || !openai_options || !("itemId" in openai_options)) {
471
- return {};
472
- }
473
- const { itemId: _item_id, ...remaining_openai_options } = openai_options;
474
- const next_provider_options = { ...provider_options };
475
- if (Object.keys(remaining_openai_options).length > 0) {
476
- next_provider_options.openai = remaining_openai_options;
477
- } else {
478
- delete next_provider_options.openai;
479
- }
480
- return Object.keys(next_provider_options).length > 0
481
- ? { providerOptions: next_provider_options }
482
- : { providerOptions: undefined };
483
- }
484
-
485
- /** 安全读取普通 JSON object。 */
486
- function read_record(value: unknown): Record<string, unknown> | undefined {
487
- return value && typeof value === "object" && !Array.isArray(value)
488
- ? value as Record<string, unknown>
489
- : undefined;
427
+ ): Record<string, unknown> {
428
+ const {
429
+ providerOptions: _provider_options,
430
+ providerMetadata: _provider_metadata,
431
+ ...semantic_part
432
+ } = part;
433
+ return semantic_part;
490
434
  }
491
435
 
492
436
  function fold_compacted_value(value: unknown, max_chars: number): unknown {
@@ -102,72 +102,5 @@ export async function to_model_messages(
102
102
  // 忽略历史里的不完整工具调用,提升容错性。
103
103
  ignoreIncompleteToolCalls: true,
104
104
  });
105
- return repair_orphaned_openai_text_references(converted_messages);
106
- }
107
-
108
- /**
109
- * 修复旧版 Session 中“只保存 msg_*、未保存必需 rs_*”的孤立 Responses API 引用。
110
- *
111
- * 关键点(中文)
112
- * - reasoning itemId / encrypted content 与 message itemId 存在时,保留 Provider 原子重放。
113
- * - 只有 message itemId 时,删除该引用并发送已持久化的普通文本,避免 400。
114
- * - 不修改 Session canonical source,该修复是可重建的 Provider 投影。
115
- */
116
- function repair_orphaned_openai_text_references(
117
- messages: ModelMessage[],
118
- ): ModelMessage[] {
119
- return messages.map((message) => {
120
- if (message.role !== "assistant" || !Array.isArray(message.content)) {
121
- return message;
122
- }
123
- const has_reasoning_replay_data = message.content.some((part) => {
124
- if (part.type !== "reasoning") return false;
125
- const openai_options = read_openai_provider_options(part.providerOptions);
126
- return Boolean(
127
- (typeof openai_options?.itemId === "string" && openai_options.itemId) ||
128
- (typeof openai_options?.reasoningEncryptedContent === "string" &&
129
- openai_options.reasoningEncryptedContent),
130
- );
131
- });
132
- if (has_reasoning_replay_data) return message;
133
-
134
- let changed = false;
135
- const content = message.content.map((part) => {
136
- if (part.type !== "text") return part;
137
- const provider_options = read_json_record(part.providerOptions);
138
- const openai_options = read_openai_provider_options(part.providerOptions);
139
- if (!provider_options || !openai_options || !("itemId" in openai_options)) {
140
- return part;
141
- }
142
- changed = true;
143
- const { itemId: _item_id, ...remaining_openai_options } = openai_options;
144
- const next_provider_options = { ...provider_options };
145
- if (Object.keys(remaining_openai_options).length > 0) {
146
- next_provider_options.openai = remaining_openai_options;
147
- } else {
148
- delete next_provider_options.openai;
149
- }
150
- return {
151
- ...part,
152
- providerOptions: Object.keys(next_provider_options).length > 0
153
- ? next_provider_options
154
- : undefined,
155
- };
156
- });
157
- return changed ? { ...message, content } as ModelMessage : message;
158
- });
159
- }
160
-
161
- /** 读取 Provider options 中的 OpenAI 协议字段。 */
162
- function read_openai_provider_options(
163
- value: unknown,
164
- ): Record<string, unknown> | undefined {
165
- return read_json_record(read_json_record(value)?.openai);
166
- }
167
-
168
- /** 安全读取普通 JSON object。 */
169
- function read_json_record(value: unknown): Record<string, unknown> | undefined {
170
- return value && typeof value === "object" && !Array.isArray(value)
171
- ? value as Record<string, unknown>
172
- : undefined;
105
+ return converted_messages;
173
106
  }
package/src/index.ts CHANGED
@@ -111,6 +111,7 @@ export {
111
111
  } from "./types/session/SessionMutation.js";
112
112
  export type {
113
113
  SessionCompactMutation,
114
+ SessionConfigMutation,
114
115
  SessionDeltaMutation,
115
116
  SessionMessageMutation,
116
117
  SessionMutation,
@@ -118,6 +119,7 @@ export type {
118
119
  SessionMutationUnsubscribe,
119
120
  SessionPartMutation,
120
121
  SessionStateMutation,
122
+ SessionTitleMutation,
121
123
  SessionTurnMutation,
122
124
  } from "./types/session/SessionMutation.js";
123
125
  export type {
@@ -10,6 +10,7 @@
10
10
  import { Executor } from "@executor/Executor.js";
11
11
  import type { LanguageModel, Tool } from "ai";
12
12
  import {
13
+ infer_agent_model_label,
13
14
  normalize_agent_model,
14
15
  read_agent_model_context_window,
15
16
  type AgentModel,
@@ -300,6 +301,21 @@ export class Session implements AgentSession {
300
301
  ? await this.state.set_approval_mode(next_approval_mode)
301
302
  : false;
302
303
  if (!model_result && !security_changed) return;
304
+ if (model_result?.changed && publish_mutation) {
305
+ this.events.publish({
306
+ mutation_id: generate_id(),
307
+ variant: "session",
308
+ type: "config",
309
+ session_id: this.id,
310
+ created_at: Date.now(),
311
+ ...(model_result.config.model_label
312
+ ? { model_label: model_result.config.model_label }
313
+ : {}),
314
+ ...(typeof model_result.config.model_context_window === "number"
315
+ ? { model_context_window: model_result.config.model_context_window }
316
+ : {}),
317
+ });
318
+ }
303
319
  const changed_fields = [
304
320
  ...(model_result?.changed
305
321
  ? [`model: ${String(model_result.config.model_label || "configured")}`]
@@ -510,11 +526,19 @@ export class Session implements AgentSession {
510
526
  messages: records,
511
527
  logger: this.logger,
512
528
  });
529
+ const model_label = String(
530
+ metadata_with_title.model_label ||
531
+ infer_agent_model_label(this.get_selected_model()) ||
532
+ "",
533
+ ).trim();
513
534
  return build_session_info({
514
535
  project_root: this.workspace_path,
515
536
  agent_id: this.agent_id,
516
537
  session_id: this.id,
517
- metadata: metadata_with_title,
538
+ metadata: {
539
+ ...metadata_with_title,
540
+ ...(model_label ? { model_label } : {}),
541
+ },
518
542
  messages: records,
519
543
  executing: this.is_executing(),
520
544
  });
@@ -110,8 +110,17 @@ export interface AgentSessionSecurityConfig {
110
110
 
111
111
  /** 远程 Session 可序列化的动态配置输入。 */
112
112
  export interface RemoteSessionSetInput {
113
+ /**
114
+ * 当前远程 Session 使用的宿主模型 ID。
115
+ *
116
+ * 关键点(中文)
117
+ * - 远程边界只传递稳定、可序列化的模型 ID。
118
+ * - 服务端宿主负责把模型 ID 解析为运行时 AgentModel。
119
+ */
120
+ model_id?: string;
121
+
113
122
  /** 当前远程 Session 的安全策略。 */
114
- security: AgentSessionSecurityConfig;
123
+ security?: AgentSessionSecurityConfig;
115
124
  }
116
125
 
117
126
  /** Session 当前安全状态。 */
@@ -125,8 +125,8 @@ export type SessionCompactMutation = SessionMutationBase & {
125
125
  error?: string;
126
126
  };
127
127
 
128
- /** Session 自身属性变化 Mutation。 */
129
- export type SessionStateMutation = SessionMutationBase & {
128
+ /** Session 标题变化 Mutation。 */
129
+ export type SessionTitleMutation = SessionMutationBase & {
130
130
  /** Mutation 层级固定为 session。 */
131
131
  variant: "session";
132
132
  /** 当前 Session 属性变化类型。 */
@@ -135,6 +135,21 @@ export type SessionStateMutation = SessionMutationBase & {
135
135
  title: string;
136
136
  };
137
137
 
138
+ /** Session 模型配置变化 Mutation。 */
139
+ export type SessionConfigMutation = SessionMutationBase & {
140
+ /** Mutation 层级固定为 session。 */
141
+ variant: "session";
142
+ /** 当前 Session 属性变化类型。 */
143
+ type: "config";
144
+ /** 当前 Session 已接受的模型可读标签。 */
145
+ model_label?: string;
146
+ /** 当前模型支持的总上下文窗口长度,单位为 token。 */
147
+ model_context_window?: number;
148
+ };
149
+
150
+ /** Session 自身属性变化 Mutation。 */
151
+ export type SessionStateMutation = SessionTitleMutation | SessionConfigMutation;
152
+
138
153
  /** Session 对外唯一实时 Mutation 联合类型。 */
139
154
  export type SessionMutation =
140
155
  | SessionMessageMutation