@downcity/agent 1.1.320 → 1.1.324

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 (97) hide show
  1. package/bin/agent/Agent.d.ts.map +1 -1
  2. package/bin/agent/Agent.js +1 -0
  3. package/bin/agent/Agent.js.map +1 -1
  4. package/bin/agent/AgentSessions.d.ts +2 -0
  5. package/bin/agent/AgentSessions.d.ts.map +1 -1
  6. package/bin/agent/AgentSessions.js +9 -0
  7. package/bin/agent/AgentSessions.js.map +1 -1
  8. package/bin/executor/messages/SessionAttachmentMapper.d.ts +15 -7
  9. package/bin/executor/messages/SessionAttachmentMapper.d.ts.map +1 -1
  10. package/bin/executor/messages/SessionAttachmentMapper.js +22 -32
  11. package/bin/executor/messages/SessionAttachmentMapper.js.map +1 -1
  12. package/bin/index.d.ts +1 -0
  13. package/bin/index.d.ts.map +1 -1
  14. package/bin/index.js.map +1 -1
  15. package/bin/session/Session.d.ts +2 -0
  16. package/bin/session/Session.d.ts.map +1 -1
  17. package/bin/session/Session.js +9 -4
  18. package/bin/session/Session.js.map +1 -1
  19. package/bin/session/SessionLoop.js +2 -2
  20. package/bin/session/SessionLoop.js.map +1 -1
  21. package/bin/session/SessionMessages.d.ts +2 -1
  22. package/bin/session/SessionMessages.d.ts.map +1 -1
  23. package/bin/session/SessionMessages.js +14 -8
  24. package/bin/session/SessionMessages.js.map +1 -1
  25. package/bin/session/SessionState.d.ts +10 -9
  26. package/bin/session/SessionState.d.ts.map +1 -1
  27. package/bin/session/SessionState.js +108 -54
  28. package/bin/session/SessionState.js.map +1 -1
  29. package/bin/session/SessionTitle.d.ts +4 -0
  30. package/bin/session/SessionTitle.d.ts.map +1 -1
  31. package/bin/session/SessionTitle.js +5 -1
  32. package/bin/session/SessionTitle.js.map +1 -1
  33. package/bin/session/messages/SessionAssistantMessageWriter.d.ts +1 -1
  34. package/bin/session/messages/SessionAssistantMessageWriter.d.ts.map +1 -1
  35. package/bin/session/messages/SessionAssistantMessageWriter.js +4 -4
  36. package/bin/session/messages/SessionAssistantMessageWriter.js.map +1 -1
  37. package/bin/session/runtime/SessionTitleTask.d.ts +35 -0
  38. package/bin/session/runtime/SessionTitleTask.d.ts.map +1 -0
  39. package/bin/session/runtime/SessionTitleTask.js +72 -0
  40. package/bin/session/runtime/SessionTitleTask.js.map +1 -0
  41. package/bin/tools/ask/AskQuestionsTool.js +1 -1
  42. package/bin/tools/ask/AskQuestionsTool.js.map +1 -1
  43. package/bin/tools/ask/AskQuestionsToolSchemas.d.ts.map +1 -1
  44. package/bin/tools/ask/AskQuestionsToolSchemas.js +4 -3
  45. package/bin/tools/ask/AskQuestionsToolSchemas.js.map +1 -1
  46. package/bin/types/sdk/AgentSessionPrompt.d.ts +22 -0
  47. package/bin/types/sdk/AgentSessionPrompt.d.ts.map +1 -1
  48. package/bin/types/sdk/AgentSessionPrompt.js.map +1 -1
  49. package/bin/types/session/SessionMessages.d.ts +3 -0
  50. package/bin/types/session/SessionMessages.d.ts.map +1 -1
  51. package/bin/types/session/SessionOptions.d.ts +2 -0
  52. package/bin/types/session/SessionOptions.d.ts.map +1 -1
  53. package/bin/types/store/SessionAttachmentStore.d.ts +29 -0
  54. package/bin/types/store/SessionAttachmentStore.d.ts.map +1 -0
  55. package/bin/types/store/SessionAttachmentStore.js +15 -0
  56. package/bin/types/store/SessionAttachmentStore.js.map +1 -0
  57. package/bin/types/store/SessionStore.d.ts +3 -0
  58. package/bin/types/store/SessionStore.d.ts.map +1 -1
  59. package/bin/workspace/store/LocalSessionAttachmentStore.d.ts +25 -0
  60. package/bin/workspace/store/LocalSessionAttachmentStore.d.ts.map +1 -0
  61. package/bin/workspace/store/LocalSessionAttachmentStore.js +72 -0
  62. package/bin/workspace/store/LocalSessionAttachmentStore.js.map +1 -0
  63. package/bin/workspace/store/LocalSessionStore.d.ts +3 -0
  64. package/bin/workspace/store/LocalSessionStore.d.ts.map +1 -1
  65. package/bin/workspace/store/LocalSessionStore.js +8 -1
  66. package/bin/workspace/store/LocalSessionStore.js.map +1 -1
  67. package/bin/workspace/store/LocalStorePaths.d.ts +6 -0
  68. package/bin/workspace/store/LocalStorePaths.d.ts.map +1 -1
  69. package/bin/workspace/store/LocalStorePaths.js +8 -0
  70. package/bin/workspace/store/LocalStorePaths.js.map +1 -1
  71. package/package.json +1 -1
  72. package/scripts/session-attachments.test.mjs +101 -0
  73. package/scripts/session-list-title.test.mjs +6 -0
  74. package/scripts/session-title-event.test.mjs +67 -3
  75. package/scripts/session-turn-failure.test.mjs +34 -1
  76. package/src/agent/Agent.ts +1 -0
  77. package/src/agent/AgentSessions.ts +10 -0
  78. package/src/executor/messages/SessionAttachmentMapper.ts +24 -37
  79. package/src/index.ts +1 -0
  80. package/src/session/Session.ts +10 -4
  81. package/src/session/SessionLoop.ts +2 -2
  82. package/src/session/SessionMessages.ts +17 -7
  83. package/src/session/SessionState.ts +118 -61
  84. package/src/session/SessionTitle.ts +13 -1
  85. package/src/session/messages/SessionAssistantMessageWriter.ts +7 -3
  86. package/src/session/runtime/SessionTitleTask.ts +86 -0
  87. package/src/tools/ask/AskQuestionsTool.ts +1 -1
  88. package/src/tools/ask/AskQuestionsToolSchemas.ts +8 -3
  89. package/src/types/sdk/AgentSessionPrompt.ts +22 -0
  90. package/src/types/session/SessionMessages.ts +3 -0
  91. package/src/types/session/SessionOptions.ts +3 -0
  92. package/src/types/store/SessionAttachmentStore.ts +29 -0
  93. package/src/types/store/SessionStore.ts +4 -0
  94. package/src/workspace/store/LocalSessionAttachmentStore.ts +96 -0
  95. package/src/workspace/store/LocalSessionStore.ts +13 -0
  96. package/src/workspace/store/LocalStorePaths.ts +16 -0
  97. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Session 附件持久化能力。
3
+ *
4
+ * Session Message 只保存附件引用,附件内容由该 Store 在 Session 生命周期内持有。
5
+ *
6
+ * 数据边界(中文):
7
+ * - 输入边界:`session.prompt()` 接收 `type: "file"`、`mediaType` 和 Data URL。
8
+ * - 存储边界:Store 解码 Data URL,写入 `.downcity/.../attachments/att_<id>.<ext>`。
9
+ * - Message 边界:Session Message 只记录相对 Workspace 根目录的附件路径。
10
+ * - 模型边界:模型转换器读取该路径,在内存中恢复成模型需要的文件内容。
11
+ *
12
+ * 因此,Data URL 不会直接进入 JSONL Message;Session Message 是附件路径的唯一引用。
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=SessionAttachmentStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionAttachmentStore.js","sourceRoot":"","sources":["../../../src/types/store/SessionAttachmentStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -8,6 +8,7 @@
8
8
  import type { SessionHistoryMetaV1 } from "../../executor/types/SessionHistoryMeta.js";
9
9
  import type { SessionAssistantMessage, SessionMessage } from "../../types/session/SessionMessage.js";
10
10
  import type { SessionMessageStorageStats, SessionSegmentRange, SessionSegmentSnapshot, SessionSegmentSummary } from "../../types/session/SessionSegment.js";
11
+ import type { SessionAttachmentStore } from "../../types/store/SessionAttachmentStore.js";
11
12
  /** 在 Message Store 写事务中创建新消息所需的稳定状态。 */
12
13
  export interface SessionMessageCommitState {
13
14
  /** 下一条真实 Message 应使用的全局线性顺序。 */
@@ -68,6 +69,8 @@ export interface SessionStore {
68
69
  readonly session_id: string;
69
70
  /** 当前 Session 的 Message 持久化能力。 */
70
71
  readonly messages: SessionMessageStore;
72
+ /** 当前 Session 的附件持久化能力。 */
73
+ readonly attachments: SessionAttachmentStore;
71
74
  /** 读取 Session Metadata;不存在时返回规范化的初始值。 */
72
75
  read_metadata(): Promise<SessionHistoryMetaV1>;
73
76
  /** 原子写入完整 Session Metadata。 */
@@ -1 +1 @@
1
- {"version":3,"file":"SessionStore.d.ts","sourceRoot":"","sources":["../../../src/types/store/SessionStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EACV,uBAAuB,EACvB,cAAc,EACf,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,mCAAmC,CAAC;AAE3C,wCAAwC;AACxC,MAAM,WAAW,yBAAyB;IACxC,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,6BAA6B;AAC7B,MAAM,WAAW,0BAA0B;IACzC,4CAA4C;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,OAAO,EAAE,qBAAqB,CAAC;CAChC;AAED,6BAA6B;AAC7B,MAAM,WAAW,2BAA2B;IAC1C,oBAAoB;IACpB,OAAO,EAAE,sBAAsB,CAAC;IAChC,mCAAmC;IACnC,eAAe,EAAE,cAAc,EAAE,CAAC;CACnC;AAED,6BAA6B;AAC7B,MAAM,WAAW,mBAAmB;IAClC,2BAA2B;IAC3B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,8CAA8C;IAC9C,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC3C,iCAAiC;IACjC,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IACrF,qBAAqB;IACrB,mBAAmB,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IAC7D,8BAA8B;IAC9B,qBAAqB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACnD,0BAA0B;IAC1B,KAAK,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC7C,gCAAgC;IAChC,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9D,mCAAmC;IACnC,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAChF,6BAA6B;IAC7B,sBAAsB,IAAI,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;IAClE,+BAA+B;IAC/B,uBAAuB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,+BAA+B;IAC/B,wBAAwB,CACtB,aAAa,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,uBAAuB,GAC3E,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACpC,0BAA0B;IAC1B,cAAc,CACZ,aAAa,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,cAAc,GAClE,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3B,uCAAuC;IACvC,0BAA0B,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,6BAA6B;IAC7B,cAAc,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACxF,6BAA6B;IAC7B,mBAAmB,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;CACvD;AAED,2BAA2B;AAC3B,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IAEvC,yCAAyC;IACzC,aAAa,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAE/C,+BAA+B;IAC/B,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D,qCAAqC;IACrC,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpC,oCAAoC;IACpC,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE3C,0BAA0B;IAC1B,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD"}
1
+ {"version":3,"file":"SessionStore.d.ts","sourceRoot":"","sources":["../../../src/types/store/SessionStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Workspace 内 Session 附件的本地实现。
3
+ *
4
+ * Data URL 在这里解码为文件;Message 层只接收相对 Workspace 根目录的文件引用。
5
+ */
6
+ import type { FileSystem } from "../../types/workspace/FileSystem.js";
7
+ import type { SessionAttachmentStore } from "../../types/store/SessionAttachmentStore.js";
8
+ export interface LocalSessionAttachmentStoreOptions {
9
+ /** Workspace 文件能力。 */
10
+ files: FileSystem;
11
+ /** 当前 Session 附件目录的绝对路径。 */
12
+ attachments_dir_path: string;
13
+ }
14
+ /** Session 附件本地持久化实现。 */
15
+ export declare class LocalSessionAttachmentStore implements SessionAttachmentStore {
16
+ private readonly files;
17
+ private readonly attachments_dir_path;
18
+ constructor(options: LocalSessionAttachmentStoreOptions);
19
+ persist_data_url(input: {
20
+ data_url: string;
21
+ media_type: string;
22
+ filename?: string;
23
+ }): Promise<string>;
24
+ }
25
+ //# sourceMappingURL=LocalSessionAttachmentStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalSessionAttachmentStore.d.ts","sourceRoot":"","sources":["../../../src/workspace/store/LocalSessionAttachmentStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAetF,MAAM,WAAW,kCAAkC;IACjD,sBAAsB;IACtB,KAAK,EAAE,UAAU,CAAC;IAClB,4BAA4B;IAC5B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,yBAAyB;AACzB,qBAAa,2BAA4B,YAAW,sBAAsB;IACxE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;gBAElC,OAAO,EAAE,kCAAkC;IAKjD,gBAAgB,CAAC,KAAK,EAAE;QAC5B,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,MAAM,CAAC;CASpB"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Workspace 内 Session 附件的本地实现。
3
+ *
4
+ * Data URL 在这里解码为文件;Message 层只接收相对 Workspace 根目录的文件引用。
5
+ */
6
+ import path from "node:path";
7
+ import { generate_id } from "../../utils/Id.js";
8
+ const DATA_URL_PATTERN = /^data:([^;,]+)?((?:;[^;,]+)*),(.*)$/s;
9
+ const MEDIA_TYPE_EXTENSIONS = {
10
+ "image/png": ".png",
11
+ "image/jpeg": ".jpg",
12
+ "image/webp": ".webp",
13
+ "image/gif": ".gif",
14
+ "video/mp4": ".mp4",
15
+ "video/quicktime": ".mov",
16
+ "video/webm": ".webm",
17
+ "application/pdf": ".pdf",
18
+ };
19
+ /** Session 附件本地持久化实现。 */
20
+ export class LocalSessionAttachmentStore {
21
+ files;
22
+ attachments_dir_path;
23
+ constructor(options) {
24
+ this.files = options.files;
25
+ this.attachments_dir_path = path.resolve(options.attachments_dir_path);
26
+ }
27
+ async persist_data_url(input) {
28
+ const parsed = parse_data_url(input.data_url, input.media_type);
29
+ const extension = resolve_extension(parsed.media_type, input.filename);
30
+ const attachment_name = `att_${generate_id()}${extension}`;
31
+ const absolute_path = path.join(this.attachments_dir_path, attachment_name);
32
+ await this.files.ensure_directory(this.attachments_dir_path);
33
+ await this.files.write_file_atomically(absolute_path, parsed.bytes);
34
+ return path.relative(this.files.root_path, absolute_path);
35
+ }
36
+ }
37
+ function parse_data_url(data_url, fallback_media_type) {
38
+ const match = DATA_URL_PATTERN.exec(String(data_url || "").trim());
39
+ if (!match)
40
+ throw new Error("Invalid data URL");
41
+ const media_type = String(match[1] || fallback_media_type || "").trim();
42
+ if (!media_type || !media_type.includes("/")) {
43
+ throw new Error("Data URL requires a valid media type");
44
+ }
45
+ const metadata = String(match[2] || "");
46
+ const payload = String(match[3] || "");
47
+ try {
48
+ const normalized_payload = payload.replace(/\s/g, "");
49
+ if (metadata.includes(";base64") &&
50
+ (!/^[A-Za-z0-9+/]*={0,2}$/.test(normalized_payload) ||
51
+ normalized_payload.length % 4 === 1)) {
52
+ throw new Error("invalid base64 payload");
53
+ }
54
+ return {
55
+ media_type,
56
+ bytes: metadata.includes(";base64")
57
+ ? Buffer.from(normalized_payload, "base64")
58
+ : Buffer.from(decodeURIComponent(payload), "utf8"),
59
+ };
60
+ }
61
+ catch (error) {
62
+ throw new Error(`Invalid data URL payload: ${error instanceof Error ? error.message : String(error)}`);
63
+ }
64
+ }
65
+ function resolve_extension(media_type, filename) {
66
+ const known = MEDIA_TYPE_EXTENSIONS[media_type.toLowerCase()];
67
+ if (known)
68
+ return known;
69
+ const filename_extension = path.extname(String(filename || "")).toLowerCase();
70
+ return /^[.][a-z0-9]{1,10}$/.test(filename_extension) ? filename_extension : ".bin";
71
+ }
72
+ //# sourceMappingURL=LocalSessionAttachmentStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalSessionAttachmentStore.js","sourceRoot":"","sources":["../../../src/workspace/store/LocalSessionAttachmentStore.ts"],"names":[],"mappings":"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"}
@@ -9,12 +9,15 @@ import { JsonlSessionMessageStore } from "../../workspace/store/JsonlSessionMess
9
9
  import type { SessionHistoryMetaV1 } from "../../executor/types/SessionHistoryMeta.js";
10
10
  import type { SessionStore } from "../../types/store/SessionStore.js";
11
11
  import type { LocalSessionStoreOptions } from "../../types/store/LocalStore.js";
12
+ import { LocalSessionAttachmentStore } from "../../workspace/store/LocalSessionAttachmentStore.js";
12
13
  /** 本地 Session Store。 */
13
14
  export declare class LocalSessionStore implements SessionStore {
14
15
  /** 当前 Session 的稳定标识。 */
15
16
  readonly session_id: string;
16
17
  /** 当前 Session 的 JSONL Message Store。 */
17
18
  readonly messages: JsonlSessionMessageStore;
19
+ /** 当前 Session 的附件持久化能力。 */
20
+ readonly attachments: LocalSessionAttachmentStore;
18
21
  /** 当前 Store 与 WorkspaceTools 共用的 Workspace 文件能力。 */
19
22
  private readonly files;
20
23
  /** 当前 Agent 的稳定标识。 */
@@ -1 +1 @@
1
- {"version":3,"file":"LocalSessionStore.d.ts","sourceRoot":"","sources":["../../../src/workspace/store/LocalSessionStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAQzF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAE5E,wBAAwB;AACxB,qBAAa,iBAAkB,YAAW,YAAY;IACpD,wBAAwB;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;IAE5C,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,sBAAsB;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,EAAE,wBAAwB;IAoB7C,8BAA8B;IACxB,aAAa,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAWpD,6BAA6B;IACvB,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnE,0BAA0B;IACpB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAIzC,sBAAsB;IAChB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKhD,sBAAsB;IAChB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS3D,kDAAkD;IAClD,OAAO,CAAC,gBAAgB;IAQxB,6CAA6C;IAC7C,OAAO,CAAC,aAAa;CAOtB"}
1
+ {"version":3,"file":"LocalSessionStore.d.ts","sourceRoot":"","sources":["../../../src/workspace/store/LocalSessionStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AASzF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAE/F,wBAAwB;AACxB,qBAAa,iBAAkB,YAAW,YAAY;IACpD,wBAAwB;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;IAE5C,2BAA2B;IAC3B,QAAQ,CAAC,WAAW,EAAE,2BAA2B,CAAC;IAElD,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,sBAAsB;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,EAAE,wBAAwB;IA4B7C,8BAA8B;IACxB,aAAa,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAWpD,6BAA6B;IACvB,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnE,0BAA0B;IACpB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAIzC,sBAAsB;IAChB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKhD,sBAAsB;IAChB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS3D,kDAAkD;IAClD,OAAO,CAAC,gBAAgB;IAQxB,6CAA6C;IAC7C,OAAO,CAAC,aAAa;CAOtB"}
@@ -6,14 +6,17 @@
6
6
  * - Session 领域只持有本对象,不再自行拼接任何存储路径。
7
7
  */
8
8
  import { JsonlSessionMessageStore } from "../../workspace/store/JsonlSessionMessageStore.js";
9
- import { get_sdk_agent_session_instruction_path, get_sdk_agent_session_meta_path, get_sdk_agent_session_assistant_message_path, get_sdk_agent_session_messages_path, } from "../../workspace/store/LocalStorePaths.js";
9
+ import { get_sdk_agent_session_instruction_path, get_sdk_agent_session_meta_path, get_sdk_agent_session_assistant_message_path, get_sdk_agent_session_messages_path, get_sdk_agent_session_attachments_dir_path, } from "../../workspace/store/LocalStorePaths.js";
10
10
  import { normalize_session_metadata } from "../../session/storage/Metadata.js";
11
+ import { LocalSessionAttachmentStore } from "../../workspace/store/LocalSessionAttachmentStore.js";
11
12
  /** 本地 Session Store。 */
12
13
  export class LocalSessionStore {
13
14
  /** 当前 Session 的稳定标识。 */
14
15
  session_id;
15
16
  /** 当前 Session 的 JSONL Message Store。 */
16
17
  messages;
18
+ /** 当前 Session 的附件持久化能力。 */
19
+ attachments;
17
20
  /** 当前 Store 与 WorkspaceTools 共用的 Workspace 文件能力。 */
18
21
  files;
19
22
  /** 当前 Agent 的稳定标识。 */
@@ -28,6 +31,10 @@ export class LocalSessionStore {
28
31
  file_path: get_sdk_agent_session_messages_path(this.files.root_path, this.agent_id, this.session_id),
29
32
  assistant_message_file_path: get_sdk_agent_session_assistant_message_path(this.files.root_path, this.agent_id, this.session_id),
30
33
  });
34
+ this.attachments = new LocalSessionAttachmentStore({
35
+ files: this.files,
36
+ attachments_dir_path: get_sdk_agent_session_attachments_dir_path(this.files.root_path, this.agent_id, this.session_id),
37
+ });
31
38
  }
32
39
  /** 读取规范化 Session Metadata。 */
33
40
  async read_metadata() {
@@ -1 +1 @@
1
- {"version":3,"file":"LocalSessionStore.js","sourceRoot":"","sources":["../../../src/workspace/store/LocalSessionStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LocalSessionStore.js","sourceRoot":"","sources":["../../../src/workspace/store/LocalSessionStore.ts"],"names":[],"mappings":"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"}
@@ -61,6 +61,12 @@ export declare function get_sdk_agent_session_instruction_path(workspace_path: s
61
61
  * 单个 session 的消息目录路径。
62
62
  */
63
63
  export declare function get_sdk_agent_session_messages_dir_path(workspace_path: string, agent_id: string, session_id: string): string;
64
+ /**
65
+ * 单个 Session 的附件目录路径。
66
+ *
67
+ * 附件与 Session 目录同生命周期,归档或删除 Session 时随目录一起迁移或清理。
68
+ */
69
+ export declare function get_sdk_agent_session_attachments_dir_path(workspace_path: string, agent_id: string, session_id: string): string;
64
70
  /**
65
71
  * 单个 session 的 Active JSONL 文件路径。
66
72
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LocalStorePaths.d.ts","sourceRoot":"","sources":["../../../src/workspace/store/LocalStorePaths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,oCAAoC,CAClD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,wCAAwC,CACtD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED;;GAEG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,gDAAgD,CAC9D,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,4CAA4C,CAC1D,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,wCAAwC,CACtD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,sCAAsC,CACpD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,mCAAmC,CACjD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;;;;;;GAOG;AACH,wBAAgB,4CAA4C,CAC1D,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR"}
1
+ {"version":3,"file":"LocalStorePaths.d.ts","sourceRoot":"","sources":["../../../src/workspace/store/LocalStorePaths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,oCAAoC,CAClD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,wCAAwC,CACtD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED;;GAEG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,gDAAgD,CAC9D,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,4CAA4C,CAC1D,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,wCAAwC,CACtD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,sCAAsC,CACpD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;;;GAIG;AACH,wBAAgB,0CAA0C,CACxD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,mCAAmC,CACjD,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;;;;;;GAOG;AACH,wBAAgB,4CAA4C,CAC1D,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR"}
@@ -86,6 +86,14 @@ export function get_sdk_agent_session_instruction_path(workspace_path, agent_id,
86
86
  export function get_sdk_agent_session_messages_dir_path(workspace_path, agent_id, session_id) {
87
87
  return path.join(get_sdk_agent_session_dir_path(workspace_path, agent_id, session_id), "messages");
88
88
  }
89
+ /**
90
+ * 单个 Session 的附件目录路径。
91
+ *
92
+ * 附件与 Session 目录同生命周期,归档或删除 Session 时随目录一起迁移或清理。
93
+ */
94
+ export function get_sdk_agent_session_attachments_dir_path(workspace_path, agent_id, session_id) {
95
+ return path.join(get_sdk_agent_session_dir_path(workspace_path, agent_id, session_id), "attachments");
96
+ }
89
97
  /**
90
98
  * 单个 session 的 Active JSONL 文件路径。
91
99
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LocalStorePaths.js","sourceRoot":"","sources":["../../../src/workspace/store/LocalStorePaths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LocalStorePaths.js","sourceRoot":"","sources":["../../../src/workspace/store/LocalStorePaths.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downcity/agent",
3
- "version": "1.1.320",
3
+ "version": "1.1.324",
4
4
  "type": "module",
5
5
  "description": "Downcity Agent 运行时 — 单 Agent 执行壳与本机 RPC 能力",
6
6
  "main": "./bin/index.js",
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @file 验证 Session prompt 的 Data URL 附件会先落盘,再以路径持久化。
3
+ */
4
+
5
+ import assert from "node:assert/strict";
6
+ import fs from "node:fs/promises";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+ import test from "node:test";
10
+ import { LocalFileSystem } from "../bin/workspace/LocalFileSystem.js";
11
+ import { LocalSessionStore } from "../bin/workspace/store/LocalSessionStore.js";
12
+ import { SessionMessages } from "../bin/session/SessionMessages.js";
13
+
14
+ async function create_harness() {
15
+ const root_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-session-attachment-"));
16
+ const files = new LocalFileSystem(root_path);
17
+ const store = new LocalSessionStore({
18
+ files,
19
+ agent_id: "attachment-test-agent",
20
+ session_id: "attachment-test-session",
21
+ });
22
+ const messages = new SessionMessages({
23
+ session_id: "attachment-test-session",
24
+ store: store.messages,
25
+ attachment_store: store.attachments,
26
+ publish: () => {},
27
+ });
28
+ await messages.initialize();
29
+ return { root_path, store, messages };
30
+ }
31
+
32
+ test("Data URL 先保存为 Session 附件,Message 只保存相对路径", async () => {
33
+ const harness = await create_harness();
34
+ const result = await harness.messages.append_prompt_message({
35
+ turn_id: "turn-1",
36
+ input_type: "prompt",
37
+ prompt: {
38
+ query: [{
39
+ type: "file",
40
+ mediaType: "image/png",
41
+ url: "data:image/png;base64,aGVsbG8=",
42
+ filename: "diagram.png",
43
+ }],
44
+ },
45
+ project_root: harness.root_path,
46
+ });
47
+
48
+ const part = result.parts[0];
49
+ assert.equal(part.type, "file");
50
+ assert.match(part.url, /^\.downcity\/agents\/attachment-test-agent\/sessions\/attachment-test-session\/attachments\/att_/);
51
+ assert.equal(part.url.endsWith(".png"), true);
52
+ assert.equal(
53
+ (await fs.readFile(path.join(harness.root_path, part.url))).toString(),
54
+ "hello",
55
+ );
56
+ assert.equal(part.url.includes("base64"), false);
57
+ });
58
+
59
+ test("视频 Data URL 使用 MIME 类型和扩展名落盘", async () => {
60
+ const harness = await create_harness();
61
+ const result = await harness.messages.append_prompt_message({
62
+ turn_id: "turn-1",
63
+ input_type: "prompt",
64
+ prompt: {
65
+ query: [{
66
+ type: "file",
67
+ mediaType: "video/mp4",
68
+ url: "data:video/mp4;base64,AQID",
69
+ filename: "demo.mp4",
70
+ }],
71
+ },
72
+ project_root: harness.root_path,
73
+ });
74
+
75
+ const part = result.parts[0];
76
+ assert.equal(part.url.endsWith(".mp4"), true);
77
+ assert.deepEqual(
78
+ [...await fs.readFile(path.join(harness.root_path, part.url))],
79
+ [1, 2, 3],
80
+ );
81
+ });
82
+
83
+ test("无效 Data URL 不会写入 Session Message", async () => {
84
+ const harness = await create_harness();
85
+ await assert.rejects(
86
+ harness.messages.append_prompt_message({
87
+ turn_id: "turn-1",
88
+ input_type: "prompt",
89
+ prompt: {
90
+ query: [{
91
+ type: "file",
92
+ mediaType: "image/png",
93
+ url: "data:image/png;base64",
94
+ }],
95
+ },
96
+ project_root: harness.root_path,
97
+ }),
98
+ /Invalid data URL/,
99
+ );
100
+ assert.deepEqual(await harness.store.messages.list_messages(), []);
101
+ });
@@ -72,6 +72,12 @@ async function create_agent_with_titled_session(input) {
72
72
  await session.append_user_message({
73
73
  text: input.first_user_text,
74
74
  });
75
+ const title_deadline = Date.now() + 1000;
76
+ while (Date.now() < title_deadline) {
77
+ if ((await session.get_info()).title === input.title) break;
78
+ await new Promise((resolve) => setTimeout(resolve, 10));
79
+ }
80
+ assert.equal((await session.get_info()).title, input.title);
75
81
 
76
82
  return {
77
83
  agent,
@@ -79,6 +79,30 @@ function create_failing_title_model() {
79
79
  });
80
80
  }
81
81
 
82
+ function create_delayed_title_model(title_text) {
83
+ let resolve_started;
84
+ let resolve_release;
85
+ const started = new Promise((resolve) => {
86
+ resolve_started = resolve;
87
+ });
88
+ const released = new Promise((resolve) => {
89
+ resolve_release = resolve;
90
+ });
91
+ const model = new MockLanguageModelV3({
92
+ modelId: "mock-session-title-delayed-model",
93
+ doStream: async () => {
94
+ resolve_started();
95
+ await released;
96
+ return create_stream_text_result(title_text);
97
+ },
98
+ });
99
+ return {
100
+ model,
101
+ started,
102
+ release: () => resolve_release(),
103
+ };
104
+ }
105
+
82
106
  async function read_log_lines(agent_path) {
83
107
  const logs_path = path.join(agent_path, ".downcity", "logs");
84
108
  const entries = await fs.readdir(logs_path);
@@ -91,6 +115,15 @@ async function read_log_lines(agent_path) {
91
115
  return lines;
92
116
  }
93
117
 
118
+ async function wait_for_title(session, expected_title) {
119
+ const deadline = Date.now() + 1000;
120
+ while (Date.now() < deadline) {
121
+ if ((await session.get_info()).title === expected_title) return;
122
+ await new Promise((resolve) => setTimeout(resolve, 10));
123
+ }
124
+ assert.equal((await session.get_info()).title, expected_title);
125
+ }
126
+
94
127
  test("Session keeps title empty when no model is available", async () => {
95
128
  const agent_path = await fs.mkdtemp(
96
129
  path.join(os.tmpdir(), "downcity-agent-session-title-"),
@@ -123,6 +156,29 @@ test("Session keeps title empty when no model is available", async () => {
123
156
  }
124
157
  });
125
158
 
159
+ test("Session title generation does not block user message append", async () => {
160
+ const agent_path = await fs.mkdtemp(
161
+ path.join(os.tmpdir(), "downcity-agent-session-title-async-"),
162
+ );
163
+ const delayed = create_delayed_title_model("异步标题");
164
+ const agent = new Agent({
165
+ id: "title_async_agent",
166
+ workspace: new Workspace({ path: agent_path }),
167
+ model: delayed.model,
168
+ });
169
+ const session = await agent.sessions.create();
170
+
171
+ try {
172
+ await session.append_user_message({ text: "标题生成不应阻塞消息写入" });
173
+ await delayed.started;
174
+ assert.equal((await session.get_info()).title, undefined);
175
+ delayed.release();
176
+ await wait_for_title(session, "异步标题");
177
+ } finally {
178
+ await agent.dispose();
179
+ }
180
+ });
181
+
126
182
  test("Session logs title generation failure without blocking the session", async () => {
127
183
  const agent_path = await fs.mkdtemp(
128
184
  path.join(os.tmpdir(), "downcity-agent-session-title-log-"),
@@ -142,8 +198,16 @@ test("Session logs title generation failure without blocking the session", async
142
198
 
143
199
  assert.equal((await session.get_info()).title, undefined);
144
200
 
145
- await agent.get_logger().save_all_logs();
146
- const log_lines = await read_log_lines(agent_path);
201
+ let log_lines = [];
202
+ const log_deadline = Date.now() + 1000;
203
+ while (Date.now() < log_deadline) {
204
+ await agent.get_logger().save_all_logs();
205
+ log_lines = await read_log_lines(agent_path);
206
+ if (log_lines.some((line) => line.includes("session_title.generate_failed"))) {
207
+ break;
208
+ }
209
+ await new Promise((resolve) => setTimeout(resolve, 10));
210
+ }
147
211
  const title_failure_log = log_lines
148
212
  .map((line) => JSON.parse(line))
149
213
  .find((entry) => entry.message.includes("session_title.generate_failed"));
@@ -196,7 +260,7 @@ test("Session retries title generation after model becomes available", async ()
196
260
  text: "Need another prompt to trigger the retry path",
197
261
  });
198
262
 
199
- assert.equal((await session.get_info()).title, "排查 session 标题");
263
+ await wait_for_title(session, "排查 session 标题");
200
264
  } finally {
201
265
  unsubscribe();
202
266
  await agent.dispose();
@@ -45,8 +45,9 @@ async function create_turn_harness(execute_turn) {
45
45
  compact_history: async () => ({ compacted: false, reason: "nothing_to_compact" }),
46
46
  state: {
47
47
  ensure_runnable: async () => {},
48
- ensure_title_from_history: async () => {},
48
+ schedule_title_generation: () => {},
49
49
  touch_metadata: async () => {},
50
+ touch_metadata_in_background: () => {},
50
51
  },
51
52
  messages,
52
53
  events: new SessionEventHub(),
@@ -137,6 +138,38 @@ test("Provider 在部分输出后失败时保留 failed Assistant 并追加 Erro
137
138
  assert.equal(page.items[2].message, "stream interrupted");
138
139
  });
139
140
 
141
+ test("Assistant 失败收口时不会遗留 input-streaming Tool Part", async () => {
142
+ const { messages, turn } = await create_turn_harness(async (turn_context) => {
143
+ await turn_context.output.assistant.begin_step();
144
+ await turn_context.output.assistant.write_chunk({
145
+ type: "tool-input-start",
146
+ toolCallId: "call-1",
147
+ toolName: "shell_exec",
148
+ });
149
+ await turn_context.output.assistant.write_chunk({
150
+ type: "tool-input-delta",
151
+ toolCallId: "call-1",
152
+ inputTextDelta: '{"cmd":"pwd"}',
153
+ });
154
+ return {
155
+ success: false,
156
+ text: "",
157
+ error: "stream interrupted",
158
+ deferred_persisted_user_messages: [],
159
+ };
160
+ });
161
+
162
+ const handle = await turn.prompt({ query: "hello" });
163
+ await handle.finished;
164
+ const page = await messages.list_messages();
165
+ const assistant = page.items.find((message) => message.type === "assistant");
166
+
167
+ assert.equal(assistant?.status, "failed");
168
+ assert.equal(assistant?.parts[0]?.type, "tool");
169
+ assert.equal(assistant?.parts[0]?.state, "failed");
170
+ assert.equal(assistant?.parts[0]?.error, "stream interrupted");
171
+ });
172
+
140
173
  test("Turn 使用 step canonical chunks 保持 Tool 与最终正文顺序", async () => {
141
174
  const { messages, turn } = await create_turn_harness(async (turn_context) => {
142
175
  await turn_context.output.assistant.begin_step();
@@ -206,6 +206,7 @@ export class Agent {
206
206
  async dispose(): Promise<void> {
207
207
  this.unsubscribe_workspace_env();
208
208
  this.unsubscribe_plugin_change();
209
+ this.sessions.dispose_title_generation();
209
210
  try {
210
211
  await this.state.dispose();
211
212
  } finally {
@@ -133,6 +133,13 @@ export class AgentSessions implements AgentSessionsContract<AgentSession> {
133
133
  return this.list_executing_session_ids().length;
134
134
  }
135
135
 
136
+ /** 释放全部缓存 Session 的标题后台任务。 */
137
+ dispose_title_generation(): void {
138
+ for (const session of this.sessions_by_id.values()) {
139
+ session.dispose_title_generation?.();
140
+ }
141
+ }
142
+
136
143
  /**
137
144
  * 把 Agent env 修改广播到已有 Session 的统一输入队列。
138
145
  */
@@ -228,6 +235,7 @@ export class AgentSessions implements AgentSessionsContract<AgentSession> {
228
235
  if (cached?.is_executing()) {
229
236
  await cached.stop();
230
237
  }
238
+ cached?.dispose_title_generation?.();
231
239
  const existed = await this.store.remove_session(resolved_session_id);
232
240
  this.sessions_by_id.delete(resolved_session_id);
233
241
  return existed;
@@ -245,6 +253,7 @@ export class AgentSessions implements AgentSessionsContract<AgentSession> {
245
253
  if (cached?.is_executing()) {
246
254
  throw new Error(`Session "${resolved_session_id}" is currently executing`);
247
255
  }
256
+ cached?.dispose_title_generation?.();
248
257
  const existed = await this.store.clear_session_messages(resolved_session_id);
249
258
  this.sessions_by_id.delete(resolved_session_id);
250
259
  return existed;
@@ -279,6 +288,7 @@ export class AgentSessions implements AgentSessionsContract<AgentSession> {
279
288
  }
280
289
 
281
290
  const result = await this.store.archive_session(session_id);
291
+ this.sessions_by_id.get(session_id)?.dispose_title_generation?.();
282
292
  this.sessions_by_id.delete(session_id);
283
293
  return result;
284
294
  }