@xopcai/xopc 0.0.168 → 0.0.170

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 (148) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-DjEDu38T.js → activity-store-CkUp1qvf.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DVuLzaJi.js → agent-avatar-dicebear-DDuem4HM.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agents-tF_QTWxn.js → agents-BiaQhiQp.js} +2 -2
  6. package/dist/gateway/static/root/assets/{api-DwVCuPOb.js → api-BnuPQhJW.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-spzVBvAu.js → app-management-settings-panel-DdZw8Hi1.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-CetimI47.js → appearance-settings-BN8Vk2bX.js} +1 -1
  9. package/dist/gateway/static/root/assets/{apps-page-HDyN6Fjx.js → apps-page-CuL8Q4yF.js} +1 -1
  10. package/dist/gateway/static/root/assets/{archive-plugin-TOmQ2XKc.js → archive-plugin-C82MaDQj.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-NFNEWVLJ.js → attachment-load-uilrwSdW.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automation-suggestion-card-B0FnLpSl.js → automation-suggestion-card-CkDZjAmy.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-DVevVD6A.js → automations-page-TZOluRNp.js} +1 -1
  14. package/dist/gateway/static/root/assets/{binary-plugins-Csc4xkR9.js → binary-plugins-B7NTL0_T.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-C6Xgrbse.js → block-editor-D_LDNlB-.js} +1 -1
  16. package/dist/gateway/static/root/assets/{browser-settings-page-CyDDEKxB.js → browser-settings-page-C-l6O68Z.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-DaxyAai1.js → browser-workflow-inputs-UFVUzn4v.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-CaX6iIJA.js → browser-workflows-page-CGgC0N92.js} +1 -1
  19. package/dist/gateway/static/root/assets/{capabilities-settings-panel-EXZv96j1.js → capabilities-settings-panel-BW8c0xPp.js} +6 -6
  20. package/dist/gateway/static/root/assets/{capability-presets-api-DdCHSzcA.js → capability-presets-api-DUIorGUd.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-PTz00nR4.js +1 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-BOkLI89e.js → channel-recipient-api-BYwSB8c6.js} +1 -1
  23. package/dist/gateway/static/root/assets/{channels-settings-aCN05KdJ.js → channels-settings-h9CsE0GT.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-status-swr-C058Mcfr.js +1 -0
  25. package/dist/gateway/static/root/assets/{chunk-KS7C4IRE-uQ0fehio.js → chunk-KS7C4IRE-BMhrPKJC.js} +2 -2
  26. package/dist/gateway/static/root/assets/{connector-logo-Mp40HWsb.js → connector-logo-CsbegNqi.js} +1 -1
  27. package/dist/gateway/static/root/assets/{connectors-page-i0cu5rg5.js → connectors-page-BWALafGW.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-BtzUJ0d7.js → desktop-pet-CkT98fPT.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-Dg0Duj8B.js → desktop-pet-settings-DkbIzdA3.js} +1 -1
  30. package/dist/gateway/static/root/assets/{directory-picker-path-field-9f0k1wZq.js → directory-picker-path-field-dBQvj1sG.js} +1 -1
  31. package/dist/gateway/static/root/assets/{dreaming-settings-rdW7dsGP.js → dreaming-settings-DkdnKMZx.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-debug-page-C9zUnn-z.js → extension-debug-page-BfxoIiNo.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-page-Cy5rfU0h.js → extension-page-EIJ3wIb7.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-settings-page-BjIquAw6.js → extension-settings-page-DBBec51N.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-config-api-AQQmI6SW.js → gateway-config-api-4_u53Ufq.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-settings-CYNmbqHj.js → gateway-settings-v9kJM59H.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-startup-retry-qnEmj-vL.js → gateway-startup-retry-CXITih5d.js} +1 -1
  38. package/dist/gateway/static/root/assets/{goal-create-dialog-CkXaDfN3.js → goal-create-dialog-y2Y3p7_k.js} +1 -1
  39. package/dist/gateway/static/root/assets/{goal-detail-page-FqDa5bfO.js → goal-detail-page-DuzL-alv.js} +3 -3
  40. package/dist/gateway/static/root/assets/{goals-config-api-CaVGtM6n.js → goals-config-api-D54YQPon.js} +1 -1
  41. package/dist/gateway/static/root/assets/{goals-page-B-uBRGN6.js → goals-page-OeLtfKI2.js} +1 -1
  42. package/dist/gateway/static/root/assets/{goals-settings-C9J3MX0F.js → goals-settings-DDezXaVi.js} +1 -1
  43. package/dist/gateway/static/root/assets/{heartbeat-settings-C0qFLyew.js → heartbeat-settings-CRsIUeZN.js} +1 -1
  44. package/dist/gateway/static/root/assets/image-generation-api-CY6cQUHL.js +1 -0
  45. package/dist/gateway/static/root/assets/index-Dfq2laZe.js +212 -0
  46. package/dist/gateway/static/root/assets/index-o4uaOGKT.css +1 -0
  47. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BAZlRZMd.js → keyboard-shortcuts-settings-D9k7EDdY.js} +1 -1
  48. package/dist/gateway/static/root/assets/{local-app-workbench-page-DkJUQRyC.js → local-app-workbench-page-3ssYIEK6.js} +1 -1
  49. package/dist/gateway/static/root/assets/{local-apps-page-PcQABi7F.js → local-apps-page-DbaiBolh.js} +1 -1
  50. package/dist/gateway/static/root/assets/{locale-store-tnRLWdx2.js → locale-store-Dqp9H2Uf.js} +1 -1
  51. package/dist/gateway/static/root/assets/{logs-page-B-nXM29t.js → logs-page-DoCY0Mm9.js} +1 -1
  52. package/dist/gateway/static/root/assets/{markdown-split-B6W1H0Fj.js → markdown-split-BGlQR-Be.js} +1 -1
  53. package/dist/gateway/static/root/assets/{media-plugins-B-r9Tj74.js → media-plugins-BpaeV6f_.js} +1 -1
  54. package/dist/gateway/static/root/assets/{messages-B1EG4gdu.js → messages-KEk-hTFt.js} +2 -2
  55. package/dist/gateway/static/root/assets/notes-page-Cd2HpciM.js +1 -0
  56. package/dist/gateway/static/root/assets/{notes-workbench-Be97S0Im.js → notes-workbench-CatZNAPc.js} +2 -2
  57. package/dist/gateway/static/root/assets/{page-tabs-BmUWVWO9.js → page-tabs-DyimBUp_.js} +1 -1
  58. package/dist/gateway/static/root/assets/{preview-open-alternatives-a76A8p5R.js → preview-open-alternatives-BKZulEYr.js} +1 -1
  59. package/dist/gateway/static/root/assets/{product-open-page-BWhYrt-U.js → product-open-page-Bjz9BxBY.js} +1 -1
  60. package/dist/gateway/static/root/assets/project-detail-page-DJUOgqm4.js +1 -0
  61. package/dist/gateway/static/root/assets/{projects-page-D1MNrLcy.js → projects-page-BQQAD_nu.js} +1 -1
  62. package/dist/gateway/static/root/assets/{remote-access-hub-GTuiqlJO.js → remote-access-hub-fIGXTTnA.js} +1 -1
  63. package/dist/gateway/static/root/assets/{save-bar-controls-_ZMLDSUw.js → save-bar-controls-BPTqb2_r.js} +1 -1
  64. package/dist/gateway/static/root/assets/{schedule-field-D4ErObRc.js → schedule-field-YN0D81Dk.js} +1 -1
  65. package/dist/gateway/static/root/assets/{schema-form-PqNSGlcH.js → schema-form-BmY5PSS2.js} +1 -1
  66. package/dist/gateway/static/root/assets/{sessions-page-Ct0MVjNv.js → sessions-page-BuU-8FCe.js} +1 -1
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-DlKoeZm3.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-BCKaoLhJ.js → settings-form-section-B-RhgD_p.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-loading-skeleton-Dn95fked.js → settings-loading-skeleton-DkPupX2B.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-C8MPUl2Q.js → settings-page-2QBMvaxj.js} +1 -1
  71. package/dist/gateway/static/root/assets/{settings-page-layout-Bigc8-GR.js → settings-page-layout-CtrW-LD6.js} +1 -1
  72. package/dist/gateway/static/root/assets/{setup-status-panel-DFTcAHsd.js → setup-status-panel-BSUcDFnb.js} +1 -1
  73. package/dist/gateway/static/root/assets/{share-preview-page-xAjqaV4y.js → share-preview-page-BezIW1n9.js} +1 -1
  74. package/dist/gateway/static/root/assets/{shares-settings-D2uvC_aM.js → shares-settings-Bk2-SwGJ.js} +1 -1
  75. package/dist/gateway/static/root/assets/skill-reload-api-e_Fx1kVC.js +1 -0
  76. package/dist/gateway/static/root/assets/{skills-page-6dr3RRVW.js → skills-page-D_cCADfj.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-BJJQulg9.js → system-settings-panel-WAFhKyAu.js} +1 -1
  78. package/dist/gateway/static/root/assets/{theme-store-H9T49Iar.js → theme-store-BiC0gIBa.js} +1 -1
  79. package/dist/gateway/static/root/assets/{time-picker-DsuPUbRE.js → time-picker-fqRXpNJV.js} +1 -1
  80. package/dist/gateway/static/root/assets/{typed-models-lib-Djk3F3EL.js → typed-models-lib-WAQO3F_8.js} +1 -1
  81. package/dist/gateway/static/root/assets/{use-channel-catalog-UACJTyH0.js → use-channel-catalog-CKlfsSeU.js} +1 -1
  82. package/dist/gateway/static/root/assets/{user-context-page-BC585kHK.js → user-context-page-9Ov4htPW.js} +1 -1
  83. package/dist/gateway/static/root/assets/{voice-api-key-field-CvocOFat.js → voice-api-key-field-BAFHF0_v.js} +1 -1
  84. package/dist/gateway/static/root/assets/{work-discovery-page-DiMn6nrT.js → work-discovery-page-DGN2FxWv.js} +1 -1
  85. package/dist/gateway/static/root/assets/{work-item-detail-page-CFBlQbPy.js → work-item-detail-page-HmyWSgUo.js} +1 -1
  86. package/dist/gateway/static/root/assets/work-page-D3iKVjFq.js +1 -0
  87. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DbQwWPjv.js → workflow-run-setup-panel-1OP4HyvS.js} +1 -1
  88. package/dist/gateway/static/root/assets/workflows-page-B5L4SFw4.js +11 -0
  89. package/dist/gateway/static/root/index.html +8 -8
  90. package/dist/package.js +1 -1
  91. package/dist/src/agent/service/process-direct-one-shot.js +2 -1
  92. package/dist/src/agent/service/process-direct-streaming.js +2 -1
  93. package/dist/src/agent/workflow/builtins/index.js +2 -2
  94. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  95. package/dist/src/cli/commands/onboard/model.d.ts +2 -0
  96. package/dist/src/cli/commands/onboard/model.js +16 -3
  97. package/dist/src/config/schema.d.ts +2 -4
  98. package/dist/src/config/schema.js +1 -2
  99. package/dist/src/gateway/heartbeat/service.js +1 -1
  100. package/dist/src/gateway/hono/routes/composer-history.d.ts +3 -0
  101. package/dist/src/gateway/hono/routes/composer-history.js +28 -0
  102. package/dist/src/gateway/hono/routes/index.js +2 -0
  103. package/dist/src/gateway/hono/routes/sessions.js +13 -2
  104. package/dist/src/gateway/service/sessions-api.js +2 -2
  105. package/dist/src/heartbeat/index.js +1 -1
  106. package/dist/src/session/client-history.d.ts +2 -0
  107. package/dist/src/session/client-history.js +2 -0
  108. package/dist/src/session/reset-policy.js +3 -5
  109. package/dist/src/session/store.d.ts +1 -0
  110. package/dist/src/session/store.js +19 -8
  111. package/dist/src/storage/sqlite/composer-input-history-repository.d.ts +12 -0
  112. package/dist/src/storage/sqlite/composer-input-history-repository.js +42 -0
  113. package/dist/src/storage/sqlite/index.d.ts +2 -1
  114. package/dist/src/storage/sqlite/index.js +3 -2
  115. package/dist/src/storage/sqlite/migrations/059_composer_input_history.sql +8 -0
  116. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  117. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  118. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  119. package/dist/src/storage/sqlite/schema.js +1 -1
  120. package/dist/src/storage/sqlite/transcript-repository.d.ts +4 -3
  121. package/dist/src/storage/sqlite/transcript-repository.js +31 -22
  122. package/dist/src/tui/backends/embedded-backend.d.ts +3 -1
  123. package/dist/src/tui/backends/embedded-backend.js +7 -0
  124. package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -1
  125. package/dist/src/tui/backends/gateway-sse-backend.js +13 -0
  126. package/dist/src/tui/components/custom-editor.d.ts +1 -0
  127. package/dist/src/tui/components/custom-editor.js +6 -0
  128. package/dist/src/tui/tui-backend.d.ts +9 -0
  129. package/dist/src/tui/tui-submit.d.ts +1 -0
  130. package/dist/src/tui/tui-submit.js +1 -1
  131. package/dist/src/tui/tui.js +58 -1
  132. package/dist/src/workflows/domain/result.d.ts +4 -15
  133. package/dist/src/workflows/engine/workflow-engine.js +5 -14
  134. package/dist/src/workflows/runtime/graph-workflow-runtime.js +7 -11
  135. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  136. package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
  137. package/dist/src/workflows/store/run-index-store.js +1 -6
  138. package/package.json +1 -1
  139. package/dist/gateway/static/root/assets/capability-presets-settings-panel-o08SXqM4.js +0 -2
  140. package/dist/gateway/static/root/assets/channels-status-swr-ZrqadU60.js +0 -1
  141. package/dist/gateway/static/root/assets/index-DchbD-qM.js +0 -199
  142. package/dist/gateway/static/root/assets/index-DfE2j0g8.css +0 -1
  143. package/dist/gateway/static/root/assets/notes-page-BNECY6Oy.js +0 -1
  144. package/dist/gateway/static/root/assets/project-detail-page-md0ANZ-f.js +0 -1
  145. package/dist/gateway/static/root/assets/settings-advanced-gate-QOUph2Oq.js +0 -1
  146. package/dist/gateway/static/root/assets/skill-reload-api-DYtfQXB-.js +0 -1
  147. package/dist/gateway/static/root/assets/work-page-CLJLKqsf.js +0 -1
  148. package/dist/gateway/static/root/assets/workflows-page-BJOhlABF.js +0 -11
@@ -31,7 +31,7 @@ function ensureXopcDatabaseSchema(db) {
31
31
  bootstrapFreshDatabase(db);
32
32
  currentVersion = 11;
33
33
  }
34
- applyPendingMigrations(db, { targetVersion: 58 });
34
+ applyPendingMigrations(db, { targetVersion: 59 });
35
35
  }
36
36
  //#endregion
37
37
  export { SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, ensureSchemaMetaTable, ensureXopcDatabaseSchema, readSchemaVersion, readSchemaVersionForTest, setSchemaVersion };
@@ -8,6 +8,7 @@ export declare function appendTranscriptEntry(sessionKey: string, row: Transcrip
8
8
  tokenDelta?: number;
9
9
  }): TranscriptEntryRow;
10
10
  export declare function loadTranscriptRowsForSession(sessionKey: string): TranscriptStoredRow[];
11
+ export declare function loadTranscriptHistoryRowsForSession(sessionKey: string): TranscriptStoredRow[];
11
12
  export declare function loadTranscriptRows(sessionId: string): TranscriptStoredRow[];
12
13
  export declare function loadLlmMessagesForSession(sessionKey: string): AgentMessage[];
13
14
  export declare function replaceTranscriptRows(sessionKey: string, rows: TranscriptStoredRow[], opts?: {
@@ -17,10 +18,10 @@ export declare function loadCheckpointRows(sessionKey: string, checkpointId: str
17
18
  export declare function paginateTranscriptMessages(sessionKey: string, options?: {
18
19
  offset?: number;
19
20
  limit?: number;
20
- beforeSeq?: number;
21
- /** 0-based exclusive end index (legacy cursor from gateway UI). */
22
- beforeEndIndex?: number;
21
+ beforeIndex?: number;
23
22
  includeContext?: boolean;
23
+ /** Include reset/rollover transcripts for read-only conversation history. */
24
+ includeArchived?: boolean;
24
25
  }): {
25
26
  rows: TranscriptStoredRow[];
26
27
  messages: AgentMessage[];
@@ -63,6 +63,15 @@ function loadTranscriptRowsForSession(sessionKey) {
63
63
  if (!sessionId) return [];
64
64
  return loadTranscriptRows(sessionId);
65
65
  }
66
+ function loadTranscriptHistoryRowsForSession(sessionKey) {
67
+ if (!getCurrentSessionId(sessionKey)) return [];
68
+ return getSqliteDatabase().prepare(`SELECT e.entry_id, e.session_id, e.seq, e.entry_kind, e.role, e.payload_json, e.created_at
69
+ FROM transcript_entries e
70
+ JOIN transcripts t ON t.session_id = e.session_id
71
+ WHERE t.session_key = ?
72
+ AND (t.status = 'active' OR t.archive_reason IN ('reset', 'stale'))
73
+ ORDER BY t.created_at ASC, t.rowid ASC, e.seq ASC`).all(sessionKey).map(transcriptEntryRowToStoredRow);
74
+ }
66
75
  function loadTranscriptRows(sessionId) {
67
76
  return getSqliteDatabase().prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
68
77
  FROM transcript_entries
@@ -121,36 +130,36 @@ function paginateTranscriptMessages(sessionKey, options = {}) {
121
130
  const db = getSqliteDatabase();
122
131
  const kinds = options.includeContext ? ["message", "context"] : ["message"];
123
132
  const kindPlaceholders = kinds.map(() => "?").join(", ");
124
- const total = db.prepare(`SELECT COUNT(*) AS total FROM transcript_entries
125
- WHERE session_id = ? AND entry_kind IN (${kindPlaceholders})`).get(sessionId, ...kinds).total;
133
+ const includeArchived = options.includeArchived === true;
134
+ const transcriptWhere = includeArchived ? `t.session_key = ? AND (t.status = 'active' OR t.archive_reason IN ('reset', 'stale'))` : "e.session_id = ?";
135
+ const transcriptArg = includeArchived ? sessionKey : sessionId;
136
+ const total = db.prepare(`SELECT COUNT(*) AS total
137
+ FROM transcript_entries e
138
+ JOIN transcripts t ON t.session_id = e.session_id
139
+ WHERE ${transcriptWhere} AND e.entry_kind IN (${kindPlaceholders})`).get(transcriptArg, ...kinds).total;
126
140
  const limit = Math.min(200, Math.max(1, Math.trunc(options.limit ?? 50)));
127
141
  const offset = Math.max(0, Math.trunc(options.offset ?? 0));
128
142
  let rows;
129
- if (options.beforeEndIndex !== void 0 && Number.isFinite(options.beforeEndIndex)) {
130
- const endExclusive = Math.min(total, Math.max(0, Math.trunc(options.beforeEndIndex)));
143
+ if (options.beforeIndex !== void 0 && Number.isFinite(options.beforeIndex)) {
144
+ const endExclusive = Math.min(total, Math.max(0, Math.trunc(options.beforeIndex)));
131
145
  const startInclusive = Math.max(0, endExclusive - limit);
132
146
  rows = db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
133
147
  FROM (
134
- SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at,
135
- ROW_NUMBER() OVER (ORDER BY seq ASC) - 1 AS idx
136
- FROM transcript_entries
137
- WHERE session_id = ? AND entry_kind IN (${kindPlaceholders})
148
+ SELECT e.entry_id, e.session_id, e.seq, e.entry_kind, e.role, e.payload_json, e.created_at,
149
+ ROW_NUMBER() OVER (ORDER BY t.created_at ASC, t.rowid ASC, e.seq ASC) - 1 AS idx
150
+ FROM transcript_entries e
151
+ JOIN transcripts t ON t.session_id = e.session_id
152
+ WHERE ${transcriptWhere} AND e.entry_kind IN (${kindPlaceholders})
138
153
  )
139
154
  WHERE idx >= ? AND idx < ?
140
- ORDER BY seq ASC`).all(sessionId, ...kinds, startInclusive, endExclusive);
141
- } else if (options.beforeSeq !== void 0 && Number.isFinite(options.beforeSeq)) {
142
- rows = db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
143
- FROM transcript_entries
144
- WHERE session_id = ? AND entry_kind IN (${kindPlaceholders}) AND seq < ?
145
- ORDER BY seq DESC
146
- LIMIT ?`).all(sessionId, ...kinds, options.beforeSeq, limit);
147
- rows.reverse();
155
+ ORDER BY idx ASC`).all(transcriptArg, ...kinds, startInclusive, endExclusive);
148
156
  } else {
149
- rows = db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
150
- FROM transcript_entries
151
- WHERE session_id = ? AND entry_kind IN (${kindPlaceholders})
152
- ORDER BY seq DESC
153
- LIMIT ? OFFSET ?`).all(sessionId, ...kinds, limit, offset);
157
+ rows = db.prepare(`SELECT e.entry_id, e.session_id, e.seq, e.entry_kind, e.role, e.payload_json, e.created_at
158
+ FROM transcript_entries e
159
+ JOIN transcripts t ON t.session_id = e.session_id
160
+ WHERE ${transcriptWhere} AND e.entry_kind IN (${kindPlaceholders})
161
+ ORDER BY t.created_at DESC, t.rowid DESC, e.seq DESC
162
+ LIMIT ? OFFSET ?`).all(transcriptArg, ...kinds, limit, offset);
154
163
  rows.reverse();
155
164
  }
156
165
  const storedRows = rows.map(transcriptEntryRowToStoredRow);
@@ -244,4 +253,4 @@ function restoreCompactionCheckpoint(sessionKey, checkpointId) {
244
253
  });
245
254
  }
246
255
  //#endregion
247
- export { appendTranscriptEntry, captureCompactionCheckpoint, getCompactionCheckpointDetail, listCompactionCheckpoints, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreCompactionCheckpoint };
256
+ export { appendTranscriptEntry, captureCompactionCheckpoint, getCompactionCheckpointDetail, listCompactionCheckpoints, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreCompactionCheckpoint };
@@ -2,7 +2,7 @@ import type { ExtensionRegistryImpl } from '../../extensions/loader.js';
2
2
  import { type SessionTimelineItem } from '../../session/transcript-outline.js';
3
3
  import { type Config } from '../../config/schema.js';
4
4
  import type { ExportFormat } from '../../session/types.js';
5
- import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
5
+ import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiComposerHistoryItem, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
6
6
  import type { SessionInfo } from '../tui-types.js';
7
7
  interface EmbeddedBackendOptions {
8
8
  config?: Config;
@@ -33,6 +33,8 @@ export declare class EmbeddedBackend implements TuiBackend {
33
33
  onDisconnected?: (reason: string) => void;
34
34
  constructor(opts?: EmbeddedBackendOptions);
35
35
  get connectionLabel(): string;
36
+ getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
37
+ recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
36
38
  start(): void;
37
39
  private ensureAgent;
38
40
  private createAgent;
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { openXopcDatabase } from "../../storage/sqlite/connection.js";
4
+ import { appendComposerInputHistory, listComposerInputHistory } from "../../storage/sqlite/composer-input-history-repository.js";
4
5
  import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../../routing/agent-session-key.js";
5
6
  import { getSessionMetadata } from "../../storage/sqlite/session-repository.js";
6
7
  import "../../storage/sqlite/index.js";
@@ -77,6 +78,12 @@ var EmbeddedBackend = class {
77
78
  get connectionLabel() {
78
79
  return "local embedded";
79
80
  }
81
+ async getComposerInputHistory() {
82
+ return listComposerInputHistory();
83
+ }
84
+ async recordComposerInputHistory(text) {
85
+ return appendComposerInputHistory(text).item;
86
+ }
80
87
  start() {
81
88
  if (this.running) return;
82
89
  this.running = true;
@@ -1,6 +1,6 @@
1
1
  import type { ExportFormat } from '../../session/types.js';
2
2
  import type { SessionTimelineItem } from '../../session/transcript-outline.js';
3
- import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiStartupResources, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
3
+ import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiComposerHistoryItem, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiStartupResources, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
4
4
  import type { SessionInfo } from '../tui-types.js';
5
5
  import type { ReviewContext } from '../../review/review-git.js';
6
6
  import { type GatewayCredential } from '../../gateway/credential.js';
@@ -33,6 +33,8 @@ export declare class GatewaySseBackend implements TuiBackend {
33
33
  start(): void;
34
34
  stop(): void;
35
35
  getActiveSignal(): AbortSignal | undefined;
36
+ getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
37
+ recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
36
38
  sendChat(opts: ChatSendOptions): Promise<{
37
39
  runId: string;
38
40
  }>;
@@ -80,6 +80,19 @@ var GatewaySseBackend = class {
80
80
  const signal = this.chatAbort?.signal;
81
81
  return signal && !signal.aborted ? signal : void 0;
82
82
  }
83
+ async getComposerInputHistory() {
84
+ const res = await gatewayFetch(this.baseUrl, "/api/composer-history", this.credential);
85
+ if (!res.ok) throw new Error(`Failed to load composer history (${res.status})`);
86
+ return (await res.json()).items ?? [];
87
+ }
88
+ async recordComposerInputHistory(text) {
89
+ const res = await gatewayFetch(this.baseUrl, "/api/composer-history", this.credential, {
90
+ method: "POST",
91
+ body: JSON.stringify({ text })
92
+ });
93
+ if (!res.ok) throw new Error(`Failed to save composer history (${res.status})`);
94
+ return (await res.json()).item;
95
+ }
83
96
  async sendChat(opts) {
84
97
  this.chatAbort?.abort();
85
98
  this.chatAbort = new AbortController();
@@ -13,5 +13,6 @@ export declare class CustomEditor extends Editor {
13
13
  onExtensionShortcut?: (data: string) => boolean;
14
14
  constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: EditorOptions);
15
15
  onAction(action: XopcTuiAppKeybinding, handler: () => void): void;
16
+ replaceHistory(itemsNewestFirst: string[]): void;
16
17
  handleInput(data: string): void;
17
18
  }
@@ -18,6 +18,12 @@ var CustomEditor = class extends Editor {
18
18
  onAction(action, handler) {
19
19
  this.actionHandlers.set(action, handler);
20
20
  }
21
+ replaceHistory(itemsNewestFirst) {
22
+ const internals = this;
23
+ internals.history = itemsNewestFirst.slice(0, 100);
24
+ internals.historyIndex = -1;
25
+ internals.historyDraft = "";
26
+ }
21
27
  handleInput(data) {
22
28
  if (this.onExtensionShortcut?.(data)) return;
23
29
  if (this.keybindings.matches(data, "app.clipboard.pasteImage")) {
@@ -25,6 +25,11 @@ export interface TuiEvent {
25
25
  data: unknown;
26
26
  source?: TuiEventSource;
27
27
  }
28
+ export interface TuiComposerHistoryItem {
29
+ id: number;
30
+ text: string;
31
+ createdAt: number;
32
+ }
28
33
  /** Minimal session list item. */
29
34
  export interface TuiSessionItem {
30
35
  key: string;
@@ -180,6 +185,10 @@ export interface TuiBackend {
180
185
  stop(): void;
181
186
  /** Current active chat abort signal, if a run is in progress. */
182
187
  getActiveSignal?(): AbortSignal | undefined;
188
+ /** Global composer history, shared across sessions and clients. */
189
+ getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
190
+ /** Persist one submitted chat input. */
191
+ recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
183
192
  /** Send a chat message, returns the run id. */
184
193
  sendChat(opts: ChatSendOptions): Promise<{
185
194
  runId: string;
@@ -7,6 +7,7 @@ export declare function createEditorSubmitHandler(params: {
7
7
  setText: (value: string) => void;
8
8
  addToHistory: (value: string) => void;
9
9
  };
10
+ recordChatHistory?: (value: string) => void;
10
11
  handleCommand: (value: string) => void | Promise<void>;
11
12
  sendMessage: (value: string) => void | Promise<void>;
12
13
  handleBangLine: (value: string) => void | Promise<void>;
@@ -36,7 +36,7 @@ function createEditorSubmitHandler(params) {
36
36
  params.handleBangLine(raw);
37
37
  return;
38
38
  }
39
- params.editor.addToHistory(value);
39
+ if (rawTrimmed) (params.recordChatHistory ?? params.editor.addToHistory)(rawTrimmed);
40
40
  if (value.startsWith("/")) {
41
41
  params.handleCommand(value);
42
42
  return;
@@ -360,6 +360,7 @@ async function runTui(opts) {
360
360
  paddingX: tuiSettings.editorPaddingX,
361
361
  autocompleteMaxVisible: tuiSettings.autocompleteMaxVisible
362
362
  });
363
+ let composerHistoryTexts = [];
363
364
  let editor = defaultEditor;
364
365
  let editorComponentFactory;
365
366
  const editorContainer = new Container();
@@ -421,6 +422,7 @@ async function runTui(opts) {
421
422
  nextEditor.setAutocompleteProvider?.(extensionRuntime.autocompleteProvider);
422
423
  copyDefaultEditorAppHandlers(nextEditor);
423
424
  editor = nextEditor;
425
+ for (const text of composerHistoryTexts.slice().reverse()) editor.addToHistory?.(text);
424
426
  } else {
425
427
  defaultEditor.setText(currentText);
426
428
  editor = defaultEditor;
@@ -1762,12 +1764,48 @@ async function runTui(opts) {
1762
1764
  updateFooter();
1763
1765
  tui.requestRender();
1764
1766
  };
1767
+ let composerHistory = [];
1768
+ let composerHistoryWriteQueue = Promise.resolve();
1769
+ const applyComposerHistory = (next) => {
1770
+ composerHistory = next.slice(0, 100);
1771
+ composerHistoryTexts = composerHistory.map((item) => item.text);
1772
+ if (editor === defaultEditor) {
1773
+ defaultEditor.replaceHistory(composerHistory.map((item) => item.text));
1774
+ return;
1775
+ }
1776
+ for (const item of composerHistory.slice().reverse()) editor.addToHistory?.(item.text);
1777
+ };
1778
+ const refreshComposerHistory = async () => {
1779
+ try {
1780
+ await composerHistoryWriteQueue;
1781
+ applyComposerHistory(await client.getComposerInputHistory());
1782
+ } catch {}
1783
+ };
1784
+ const recordChatHistory = (value) => {
1785
+ const text = value.trim();
1786
+ if (!text) return;
1787
+ editor.addToHistory?.(text);
1788
+ if (composerHistory[0]?.text !== text) {
1789
+ composerHistory = [{
1790
+ id: 0,
1791
+ text,
1792
+ createdAt: Date.now()
1793
+ }, ...composerHistory].slice(0, 100);
1794
+ composerHistoryTexts = composerHistory.map((item) => item.text);
1795
+ }
1796
+ composerHistoryWriteQueue = composerHistoryWriteQueue.then(async () => {
1797
+ const item = await client.recordComposerInputHistory(text);
1798
+ const optimisticIndex = composerHistory.findIndex((entry) => entry.id === 0 && entry.text === item.text);
1799
+ if (optimisticIndex >= 0) composerHistory[optimisticIndex] = item;
1800
+ }).catch(() => {});
1801
+ };
1765
1802
  const submitBurst = createSubmitBurstCoalescer({
1766
1803
  submit: createEditorSubmitHandler({
1767
1804
  editor: {
1768
1805
  setText: (value) => editor.setText(value),
1769
1806
  addToHistory: (value) => editor.addToHistory?.(value)
1770
1807
  },
1808
+ recordChatHistory: (value) => recordChatHistory(value),
1771
1809
  handleCommand,
1772
1810
  sendMessage,
1773
1811
  handleBangLine: runLocalShellLine,
@@ -1798,7 +1836,7 @@ async function runTui(opts) {
1798
1836
  tui.requestRender();
1799
1837
  return;
1800
1838
  }
1801
- editor.addToHistory(text);
1839
+ recordChatHistory(text);
1802
1840
  state.messageFollowUpQueue.push(text);
1803
1841
  editor.setText("");
1804
1842
  chatLog.addSystem(theme.dim(`Queued follow-up (${state.messageFollowUpQueue.length} in queue). ${tuiSettings.followUpMode === "all" ? "All queued messages send together when this reply finishes." : "Next sends when this reply finishes."}`));
@@ -2052,6 +2090,23 @@ async function runTui(opts) {
2052
2090
  };
2053
2091
  client.onEvent = (evt) => {
2054
2092
  const data = evt.data ?? {};
2093
+ if (evt.event === "composer-history.appended") {
2094
+ const item = data;
2095
+ if (typeof item.text === "string" && typeof item.id === "number") {
2096
+ const optimisticIndex = composerHistory.findIndex((entry) => entry.id === 0 && entry.text === item.text);
2097
+ if (optimisticIndex >= 0) composerHistory[optimisticIndex] = item;
2098
+ else if (composerHistory[0]?.text !== item.text) {
2099
+ composerHistory = [item, ...composerHistory].slice(0, 100);
2100
+ composerHistoryTexts = composerHistory.map((entry) => entry.text);
2101
+ editor.addToHistory?.(item.text);
2102
+ } else composerHistory[0] = item;
2103
+ }
2104
+ return;
2105
+ }
2106
+ if (evt.event === "composer-history.cleared") {
2107
+ applyComposerHistory([]);
2108
+ return;
2109
+ }
2055
2110
  if (evt.event === "workflow.run.updated" && handleWorkflowRunUpdated(data)) return;
2056
2111
  dispatchAgentEvent(evt.event, data, state, chatLog, tui, setActivityStatus, touchStreamingActivity, onAgentRunEnded, (message) => sessionSnapshot.appendMessage("assistant", assistantMessagePlainText(message)), evt.source);
2057
2112
  };
@@ -2061,6 +2116,7 @@ async function runTui(opts) {
2061
2116
  setConnectionStatus(isLocalMode ? "local ready" : "gateway connected");
2062
2117
  touchStreamingActivity();
2063
2118
  (async () => {
2119
+ await refreshComposerHistory();
2064
2120
  if (opts.openSessionPickerOnStart && !startupSessionPickerOpened) {
2065
2121
  startupSessionPickerOpened = true;
2066
2122
  await openSessionPickerOverlay(pickerSvc, {
@@ -2125,6 +2181,7 @@ async function runTui(opts) {
2125
2181
  setConnectionStatus(`event gap: expected ${info.expected}, got ${info.received}`);
2126
2182
  if (state.activeRunId) recoverActiveRunFromHistory("broadcast event gap");
2127
2183
  else loadSessionHistory({ merge: true });
2184
+ refreshComposerHistory();
2128
2185
  tui.requestRender();
2129
2186
  };
2130
2187
  const sigintHandler = () => handleCtrlC();
@@ -1,18 +1,12 @@
1
1
  export interface WorkflowResultEnvelope {
2
2
  title?: string;
3
3
  summary: string;
4
- sections: WorkflowResultSection[];
4
+ sections?: WorkflowResultSection[];
5
5
  actions?: WorkflowNextAction[];
6
6
  artifacts?: WorkflowArtifactRef[];
7
7
  followUps?: WorkflowFollowUp[];
8
- structuredOutput?: unknown;
9
- }
10
- /** Product-level outcome contract for reusable workflow deliverables. */
11
- export interface WorkflowOutcome {
12
- summary: string;
13
- artifacts?: WorkflowArtifactRef[];
14
- followUps?: WorkflowFollowUp[];
15
- structuredOutput?: unknown;
8
+ /** Machine-readable workflow output. It is intentionally not rendered as user-facing content. */
9
+ data?: unknown;
16
10
  }
17
11
  export interface WorkflowFollowUp {
18
12
  id: string;
@@ -20,7 +14,7 @@ export interface WorkflowFollowUp {
20
14
  prompt?: string;
21
15
  priority?: 'low' | 'medium' | 'high';
22
16
  }
23
- export type WorkflowResultSection = WorkflowTextSection | WorkflowFindingsSection | WorkflowRisksSection | WorkflowQuestionsSection | WorkflowJsonSection;
17
+ export type WorkflowResultSection = WorkflowTextSection | WorkflowFindingsSection | WorkflowRisksSection | WorkflowQuestionsSection;
24
18
  export interface WorkflowTextSection {
25
19
  kind: 'text';
26
20
  title: string;
@@ -41,11 +35,6 @@ export interface WorkflowQuestionsSection {
41
35
  title: string;
42
36
  items: string[];
43
37
  }
44
- export interface WorkflowJsonSection {
45
- kind: 'json';
46
- title: string;
47
- value: unknown;
48
- }
49
38
  export interface WorkflowFinding {
50
39
  title: string;
51
40
  severity?: WorkflowSeverity;
@@ -177,7 +177,7 @@ var WorkflowEngine = class {
177
177
  await eventQueue;
178
178
  if (currentPhaseId) await appendEvent("phase_completed", { phaseId: currentPhaseId });
179
179
  const result = requireWorkflowResultEnvelope(runtimeResult.result);
180
- assertWorkflowOutput(definition, result);
180
+ assertWorkflowOutput(definition, result.data === void 0 ? result.summary : result.data);
181
181
  await appendEvent("run_completed", { result });
182
182
  await this.callHooks((hook) => hook.afterRun?.({
183
183
  runId,
@@ -622,16 +622,7 @@ function groupReplayTargetsByPhase(targets) {
622
622
  function buildReplayResultEnvelope(options, results) {
623
623
  return {
624
624
  summary: `Replay completed for ${results.filter((item) => item.status === "done").length}/${results.length} target${results.length === 1 ? "" : "s"}.`,
625
- sections: [{
626
- kind: "json",
627
- title: "Replay targets",
628
- value: {
629
- sourceRunId: options.sourceRunId,
630
- scope: options.replayScope,
631
- targets: results
632
- }
633
- }],
634
- structuredOutput: { replay: {
625
+ data: { replay: {
635
626
  sourceRunId: options.sourceRunId,
636
627
  scope: options.replayScope,
637
628
  targets: results
@@ -669,6 +660,7 @@ function normalizeCompletedAgentStatus(status) {
669
660
  function previewWorkflowValue(value) {
670
661
  if (value === null || value === void 0) return;
671
662
  if (typeof value === "string") return truncate(value, 300);
663
+ if (isWorkflowResultEnvelope(value)) return truncate(value.summary, 1200);
672
664
  try {
673
665
  return truncate(JSON.stringify(value), 300);
674
666
  } catch {
@@ -687,12 +679,11 @@ function assertWorkflowOutput(definition, value) {
687
679
  }
688
680
  function isWorkflowResultEnvelope(value) {
689
681
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
690
- const record = value;
691
- return typeof record.summary === "string" && Array.isArray(record.sections);
682
+ return typeof value.summary === "string";
692
683
  }
693
684
  function requireWorkflowResultEnvelope(value) {
694
685
  if (isWorkflowResultEnvelope(value)) return value;
695
- throw new WorkflowEngineRunError("result_validation_failed", "Workflow output node must return a result envelope with summary and sections.", false);
686
+ throw new WorkflowEngineRunError("result_validation_failed", "Workflow output node must return a result envelope with summary.", false);
696
687
  }
697
688
  function toWorkflowRunError(err, wasAborted, abortReason) {
698
689
  if (err instanceof WorkflowEngineRunError) return {
@@ -95,15 +95,10 @@ var GraphWorkflowRuntime = class {
95
95
  };
96
96
  } else if (node.kind === "merge") value = node.config.mode === "array" ? predecessors.map((entry) => entry.value) : Object.fromEntries(predecessors.map((entry) => [entry.id, entry.value]));
97
97
  else {
98
- const structuredOutput = predecessors.length === 1 ? predecessors[0].value : Object.fromEntries(predecessors.map((entry) => [entry.id, entry.value]));
98
+ const outputData = predecessors.length === 1 ? predecessors[0].value : Object.fromEntries(predecessors.map((entry) => [entry.id, entry.value]));
99
99
  value = {
100
- summary: node.config.summary ? renderTemplate(node.config.summary, options.args, outputs, predecessors, options.goal) : summarizeValue(structuredOutput),
101
- sections: [{
102
- kind: "json",
103
- title: node.config.title ?? "Workflow result",
104
- value: structuredOutput
105
- }],
106
- structuredOutput
100
+ summary: node.config.summary ? renderTemplate(node.config.summary, options.args, outputs, predecessors, options.goal) : renderResultContent(outputData),
101
+ ...typeof outputData === "string" ? {} : { data: outputData }
107
102
  };
108
103
  }
109
104
  outputs.set(node.id, value);
@@ -276,16 +271,17 @@ function createLimiter(limit) {
276
271
  }
277
272
  };
278
273
  }
279
- function summarizeValue(value) {
280
- if (typeof value === "string") return value.slice(0, 500);
274
+ function renderResultContent(value) {
275
+ if (typeof value === "string") return value.trim();
281
276
  if (value && typeof value === "object") {
282
277
  const record = value;
283
278
  for (const key of [
279
+ "content",
284
280
  "summary",
285
281
  "executiveSummary",
286
282
  "result",
287
283
  "answer"
288
- ]) if (typeof record[key] === "string") return record[key].slice(0, 500);
284
+ ]) if (typeof record[key] === "string") return record[key].trim();
289
285
  }
290
286
  return "Workflow completed.";
291
287
  }
@@ -4,8 +4,8 @@ import { publishAutomationProductEvent } from "../../automations/product-events.
4
4
  import { GoalService } from "../../goals/goal-service.js";
5
5
  import "../../goals/index.js";
6
6
  import { DelegateSubagentRunner } from "../../agent/workflow/subagent-runner.js";
7
- import { preflightWorkflowConnectors } from "../../connectors/workflow-preflight.js";
8
7
  import { resolveModelRef } from "../../config/agent-typed-models.js";
8
+ import { preflightWorkflowConnectors } from "../../connectors/workflow-preflight.js";
9
9
  import { CatalogWorkflowDefinitionRegistry } from "../registry/catalog-workflow-definition-registry.js";
10
10
  import { validateWorkflowJsonSchema } from "../domain/schema-validation.js";
11
11
  import { isTerminalWorkflowRunStatus } from "../domain/run.js";
@@ -160,7 +160,7 @@ var WorkflowSessionBridge = class {
160
160
  const projectId = view.run.metadata?.projectId?.trim();
161
161
  const agentId = view.run.metadata?.agentId?.trim();
162
162
  if (!projectId || !agentId) return;
163
- const resultText = view.run.result?.summary?.trim() || renderWorkflowText(runViewToSnapshot(view), view.run.status === "succeeded", { showResultPreviews: true });
163
+ const resultText = view.run.result?.summary.trim() || renderWorkflowText(runViewToSnapshot(view), view.run.status === "succeeded", { showResultPreviews: true });
164
164
  upsertMemoryRecord({
165
165
  id: `workflow-run:${view.run.id}`,
166
166
  providerId: "workflow-run",
@@ -19,12 +19,7 @@ function rowToSummary(row) {
19
19
  function resultPreview(view) {
20
20
  const result = view.run.result;
21
21
  if (result == null) return null;
22
- if (typeof result.summary === "string") return result.summary.slice(0, 500);
23
- try {
24
- return JSON.stringify(result).slice(0, 500);
25
- } catch {
26
- return null;
27
- }
22
+ return result.summary.slice(0, 500);
28
23
  }
29
24
  function parentSessionKey(view) {
30
25
  if (view.run.source.kind === "chat") return view.run.source.sessionKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.168",
3
+ "version": "0.0.170",
4
4
  "description": "Local-first AI system that remembers context, coordinates AI, and sustains long-term progress.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",