@xopcai/xopc 0.0.169 → 0.0.171

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 (198) 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-DumQD8EX.js → activity-store-BLz30jWq.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CNI1HQdV.js → agent-avatar-dicebear-BKZO0EFn.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-ZCIC8mhO.js +2 -0
  6. package/dist/gateway/static/root/assets/{api-D7eNcGmE.js → api-N2qKY-WI.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-BPbnbnFn.js → app-management-settings-panel-CNZkpXCD.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-WWFCDver.js → appearance-settings-Drf5a563.js} +1 -1
  9. package/dist/gateway/static/root/assets/{apps-page-B27faKqW.js → apps-page-DJmgBaAm.js} +1 -1
  10. package/dist/gateway/static/root/assets/{archive-plugin-Cu2dsFtI.js → archive-plugin-ChVwOXE5.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-C9mycbtr.js → attachment-load-BVK3Y2d9.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automation-suggestion-card-DtHqVViI.js → automation-suggestion-card-DH4N0SYR.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-page-Ddot8-Md.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-DqrPRyjm.js → binary-plugins-CeHY6VVP.js} +1 -1
  15. package/dist/gateway/static/root/assets/block-editor-D3GIllO3.js +184 -0
  16. package/dist/gateway/static/root/assets/browser-settings-page-DvETvRcg.js +8 -0
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-70k5yvTc.js → browser-workflow-inputs-femCtfpo.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-DBNuaWwR.js → browser-workflows-page-o0GVE_aF.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-ChXIYbys.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-CvV4M4Oe.js → capability-presets-api-Bx-JJC0R.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CUekXsJy.js +1 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-BnLOBd7v.js → channel-recipient-api-CTw3ibx4.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-CkhveNsQ.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-DRTb8DBk.js +1 -0
  25. package/dist/gateway/static/root/assets/{connector-logo-CYQPu4Nn.js → connector-logo-CQznQcd4.js} +1 -1
  26. package/dist/gateway/static/root/assets/connectors-page-DkSGIxWP.js +2 -0
  27. package/dist/gateway/static/root/assets/desktop-pet-BtP-xUQ9.js +1 -0
  28. package/dist/gateway/static/root/assets/{desktop-pet-settings-DHTY5Ku1.js → desktop-pet-settings-CIeH4VyP.js} +1 -1
  29. package/dist/gateway/static/root/assets/{directory-picker-path-field-cGL2aEB6.js → directory-picker-path-field-Ddgt6c3K.js} +1 -1
  30. package/dist/gateway/static/root/assets/{dreaming-settings-C2XF2wL4.js → dreaming-settings-gd9W6SLj.js} +3 -3
  31. package/dist/gateway/static/root/assets/{extension-debug-page-F8AzDx0d.js → extension-debug-page-CJGwUaQX.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-ZrX_Ge87.js → extension-page-B3zHKJAB.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-VypAD6ok.js → extension-settings-page-Cj9rrSr1.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-api-C-UsxEKi.js → gateway-config-api-BdmtlJRP.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-settings-ChG26Coy.js → gateway-settings-C2RwKIsl.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-startup-retry-D73V3EVy.js → gateway-startup-retry-mcMq_uu_.js} +1 -1
  37. package/dist/gateway/static/root/assets/goal-create-dialog-5Ryd_rx4.js +1 -0
  38. package/dist/gateway/static/root/assets/goal-detail-page-DizZ6Cpl.js +4 -0
  39. package/dist/gateway/static/root/assets/{goals-config-api-fv7JLhjy.js → goals-config-api-CAO1J4jn.js} +1 -1
  40. package/dist/gateway/static/root/assets/goals-page-Dqry_hi2.js +2 -0
  41. package/dist/gateway/static/root/assets/{goals-settings-DlfyneMz.js → goals-settings-Boj2izKZ.js} +1 -1
  42. package/dist/gateway/static/root/assets/{heartbeat-settings-BPyFbSbh.js → heartbeat-settings-DbPC9a_y.js} +1 -1
  43. package/dist/gateway/static/root/assets/{image-generation-api-CSKX7PsM.js → image-generation-api-DrLCLTXn.js} +1 -1
  44. package/dist/gateway/static/root/assets/index-DEdyUjxM.css +1 -0
  45. package/dist/gateway/static/root/assets/{index-DJtuKve9.js → index-vHb2z7VS.js} +83 -70
  46. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BUxrnWH_.js → keyboard-shortcuts-settings-BrxfptgY.js} +1 -1
  47. package/dist/gateway/static/root/assets/local-app-workbench-page-BP0_Ih0e.js +2 -0
  48. package/dist/gateway/static/root/assets/{local-apps-page-BsZMeDnS.js → local-apps-page-DNCRlfFs.js} +1 -1
  49. package/dist/gateway/static/root/assets/{locale-store-DXq-Y8Bi.js → locale-store-CzIfXqm8.js} +1 -1
  50. package/dist/gateway/static/root/assets/logs-page-mT48mcF4.js +7 -0
  51. package/dist/gateway/static/root/assets/{markdown-split-Cmaw70yM.js → markdown-split-CIUH9Lor.js} +1 -1
  52. package/dist/gateway/static/root/assets/{media-plugins-Blqj_oJD.js → media-plugins-DX4AgkCs.js} +1 -1
  53. package/dist/gateway/static/root/assets/messages-CKZuaOeG.js +3 -0
  54. package/dist/gateway/static/root/assets/{notes-page-B6Fdlf_s.js → notes-page-D1KprtxL.js} +1 -1
  55. package/dist/gateway/static/root/assets/notes-workbench-wgt2Osyk.js +4 -0
  56. package/dist/gateway/static/root/assets/{page-tabs-D6zFoyJY.js → page-tabs-DjZPJGf6.js} +1 -1
  57. package/dist/gateway/static/root/assets/{preview-open-alternatives-BLoo7Ad8.js → preview-open-alternatives-DNiJTpwZ.js} +1 -1
  58. package/dist/gateway/static/root/assets/{product-open-page-0-tt2dp7.js → product-open-page-CNfR17-g.js} +1 -1
  59. package/dist/gateway/static/root/assets/project-detail-page-CDjHvxJm.js +1 -0
  60. package/dist/gateway/static/root/assets/projects-page-kJZwQXfC.js +1 -0
  61. package/dist/gateway/static/root/assets/remote-access-hub-MJdI9ek_.js +1 -0
  62. package/dist/gateway/static/root/assets/{save-bar-controls-9ujl7LRy.js → save-bar-controls-BGZFVO9S.js} +1 -1
  63. package/dist/gateway/static/root/assets/{schedule-field-e80Mj-0z.js → schedule-field-BAZiHtds.js} +1 -1
  64. package/dist/gateway/static/root/assets/{schema-form-DYZQD-PL.js → schema-form-CesBcwJH.js} +1 -1
  65. package/dist/gateway/static/root/assets/sessions-page-BqC7GDC_.js +1 -0
  66. package/dist/gateway/static/root/assets/settings-advanced-gate-CYwz8MfF.js +1 -0
  67. package/dist/gateway/static/root/assets/{settings-form-section-Clt3p-mk.js → settings-form-section-Bxc54BLj.js} +1 -1
  68. package/dist/gateway/static/root/assets/{settings-loading-skeleton-CTuS66nC.js → settings-loading-skeleton-CYrho7Db.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-page-CMP_owwc.js → settings-page-C03X5fkh.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-layout-BWUV_wx6.js → settings-page-layout-CZAJbv4E.js} +1 -1
  71. package/dist/gateway/static/root/assets/setup-status-panel-Jv8_bcOD.js +1 -0
  72. package/dist/gateway/static/root/assets/{share-preview-page-tISZJtRK.js → share-preview-page-DSC7tKKG.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-h8tGDkA3.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-D2DGvRUn.js +1 -0
  75. package/dist/gateway/static/root/assets/skills-page-vqhjSMhZ.js +2 -0
  76. package/dist/gateway/static/root/assets/{system-settings-panel-6u0k0wJi.js → system-settings-panel-BO89zw5H.js} +1 -1
  77. package/dist/gateway/static/root/assets/{theme-store-DSpAOJ9G.js → theme-store-1OkdVC8l.js} +1 -1
  78. package/dist/gateway/static/root/assets/time-picker-mtD64kFB.js +1 -0
  79. package/dist/gateway/static/root/assets/{typed-models-lib-CyRCjjGS.js → typed-models-lib-D-_vct_y.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-channel-catalog-B_Igd7ec.js → use-channel-catalog-VlFtjlET.js} +1 -1
  81. package/dist/gateway/static/root/assets/user-context-page-BgF0WxjM.js +1 -0
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-BanJk_cf.js → voice-api-key-field-BhDk-UV_.js} +1 -1
  83. package/dist/gateway/static/root/assets/work-discovery-page-CP0Daig-.js +1 -0
  84. package/dist/gateway/static/root/assets/work-item-detail-page-NEWZPKB_.js +1 -0
  85. package/dist/gateway/static/root/assets/work-page-BkWntcQh.js +1 -0
  86. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DCXTQx7p.js → workflow-run-setup-panel-uVw4Yoej.js} +2 -2
  87. package/dist/gateway/static/root/assets/workflows-page-DRvhNQGe.js +11 -0
  88. package/dist/gateway/static/root/index.html +7 -7
  89. package/dist/package.js +1 -1
  90. package/dist/src/agent/embedded/run-for-session.js +71 -24
  91. package/dist/src/agent/embedded/run-turn.js +68 -4
  92. package/dist/src/agent/inbound/inbound-loop.d.ts +0 -2
  93. package/dist/src/agent/inbound/inbound-loop.js +0 -2
  94. package/dist/src/agent/memory/compaction-planner.d.ts +16 -0
  95. package/dist/src/agent/memory/compaction-planner.js +152 -0
  96. package/dist/src/agent/memory/compaction-policy.d.ts +10 -0
  97. package/dist/src/agent/memory/compaction-policy.js +24 -0
  98. package/dist/src/agent/memory/compaction.d.ts +21 -22
  99. package/dist/src/agent/memory/compaction.js +220 -194
  100. package/dist/src/agent/memory/context-budget.d.ts +40 -0
  101. package/dist/src/agent/memory/context-budget.js +106 -0
  102. package/dist/src/agent/memory/dreaming/config.js +1 -1
  103. package/dist/src/agent/orchestration/context-overflow.d.ts +1 -0
  104. package/dist/src/agent/orchestration/context-overflow.js +19 -0
  105. package/dist/src/agent/orchestration/loop-guard.js +13 -9
  106. package/dist/src/agent/reply/post-compaction-context.d.ts +4 -0
  107. package/dist/src/agent/reply/post-compaction-context.js +5 -3
  108. package/dist/src/agent/service.d.ts +0 -2
  109. package/dist/src/agent/service.js +13 -44
  110. package/dist/src/agent/session/session-inspector.js +10 -2
  111. package/dist/src/agent/workflow/builtins/index.js +2 -2
  112. package/dist/src/agent-runtime/index.js +1 -1
  113. package/dist/src/agent-runtime/runtime-profile.js +1 -1
  114. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  115. package/dist/src/cli/commands/onboard/model.d.ts +2 -0
  116. package/dist/src/cli/commands/onboard/model.js +16 -3
  117. package/dist/src/config/agent-profile.js +1 -1
  118. package/dist/src/config/schema.d.ts +19 -5
  119. package/dist/src/config/schema.js +1 -2
  120. package/dist/src/gateway/agents-admin.js +1 -1
  121. package/dist/src/gateway/hono/lib/config-payload.d.ts +23 -0
  122. package/dist/src/gateway/hono/lib/config-payload.js +3 -0
  123. package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +1 -1
  124. package/dist/src/gateway/hono/routes/config-patch/misc.js +28 -0
  125. package/dist/src/gateway/hono/routes/sessions.js +30 -44
  126. package/dist/src/gateway/service/sessions-api.d.ts +2 -3
  127. package/dist/src/gateway/service/sessions-api.js +6 -9
  128. package/dist/src/session/index.d.ts +1 -2
  129. package/dist/src/session/index.js +1 -2
  130. package/dist/src/session/init-session-turn.d.ts +0 -1
  131. package/dist/src/session/init-session-turn.js +1 -2
  132. package/dist/src/session/manager.d.ts +11 -17
  133. package/dist/src/session/manager.js +11 -14
  134. package/dist/src/session/reset-policy.js +3 -5
  135. package/dist/src/session/session-context-for-llm.d.ts +19 -1
  136. package/dist/src/session/session-context-for-llm.js +87 -129
  137. package/dist/src/session/store.d.ts +29 -23
  138. package/dist/src/session/store.js +109 -87
  139. package/dist/src/session/transcript-format.d.ts +2 -8
  140. package/dist/src/session/types.d.ts +8 -6
  141. package/dist/src/session/user-round-delete.d.ts +3 -6
  142. package/dist/src/session/user-round-delete.js +12 -16
  143. package/dist/src/storage/sqlite/index.d.ts +1 -1
  144. package/dist/src/storage/sqlite/index.js +2 -2
  145. package/dist/src/storage/sqlite/migrations/060_remove_runtime_transcript_messages.sql +45 -0
  146. package/dist/src/storage/sqlite/migrations/061_drop_compaction_checkpoints.sql +2 -0
  147. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  148. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  149. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  150. package/dist/src/storage/sqlite/schema.js +1 -1
  151. package/dist/src/storage/sqlite/schema.sql +0 -19
  152. package/dist/src/storage/sqlite/transcript-repository.d.ts +10 -14
  153. package/dist/src/storage/sqlite/transcript-repository.js +120 -105
  154. package/dist/src/user-context/config.d.ts +67 -2
  155. package/dist/src/user-context/config.js +36 -3
  156. package/dist/src/workflows/domain/result.d.ts +4 -15
  157. package/dist/src/workflows/engine/workflow-engine.js +5 -14
  158. package/dist/src/workflows/runtime/graph-workflow-runtime.js +7 -11
  159. package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
  160. package/dist/src/workflows/store/run-index-store.js +1 -6
  161. package/package.json +1 -1
  162. package/dist/gateway/static/root/assets/agents-DfpeWAnu.js +0 -2
  163. package/dist/gateway/static/root/assets/automations-page-BoH5grBX.js +0 -6
  164. package/dist/gateway/static/root/assets/block-editor-B9dc3pqc.js +0 -184
  165. package/dist/gateway/static/root/assets/browser-settings-page-CK2fnxHY.js +0 -8
  166. package/dist/gateway/static/root/assets/capabilities-settings-panel-gg9GXU00.js +0 -7
  167. package/dist/gateway/static/root/assets/capability-presets-settings-panel-A1qGVyll.js +0 -1
  168. package/dist/gateway/static/root/assets/channels-settings-H4vCzqiD.js +0 -1
  169. package/dist/gateway/static/root/assets/channels-status-swr-DtswVkDX.js +0 -1
  170. package/dist/gateway/static/root/assets/connectors-page-DphVkloc.js +0 -2
  171. package/dist/gateway/static/root/assets/desktop-pet-Deb8fsr-.js +0 -1
  172. package/dist/gateway/static/root/assets/goal-create-dialog-B6aBG2KK.js +0 -1
  173. package/dist/gateway/static/root/assets/goal-detail-page-B_G9oVL1.js +0 -4
  174. package/dist/gateway/static/root/assets/goals-page-BQmg_7aD.js +0 -2
  175. package/dist/gateway/static/root/assets/index-DfE2j0g8.css +0 -1
  176. package/dist/gateway/static/root/assets/local-app-workbench-page-Dzlj4fH8.js +0 -2
  177. package/dist/gateway/static/root/assets/logs-page-Bg1B-cKU.js +0 -7
  178. package/dist/gateway/static/root/assets/messages-Cj_n7gUv.js +0 -3
  179. package/dist/gateway/static/root/assets/notes-workbench-4HYPR6Hb.js +0 -4
  180. package/dist/gateway/static/root/assets/project-detail-page-CGa68F1d.js +0 -1
  181. package/dist/gateway/static/root/assets/projects-page-BXmIeErj.js +0 -1
  182. package/dist/gateway/static/root/assets/remote-access-hub-bxrIHaRt.js +0 -1
  183. package/dist/gateway/static/root/assets/sessions-page-D_7ms_LG.js +0 -1
  184. package/dist/gateway/static/root/assets/settings-advanced-gate-VLuu9WHc.js +0 -1
  185. package/dist/gateway/static/root/assets/setup-status-panel-CAClgrxi.js +0 -1
  186. package/dist/gateway/static/root/assets/shares-settings-t-hP0QDv.js +0 -1
  187. package/dist/gateway/static/root/assets/skill-reload-api-CYRaxTqs.js +0 -1
  188. package/dist/gateway/static/root/assets/skills-page-C6CXLWnN.js +0 -2
  189. package/dist/gateway/static/root/assets/time-picker-BF3f8el1.js +0 -1
  190. package/dist/gateway/static/root/assets/user-context-page-B3zeQLeM.js +0 -1
  191. package/dist/gateway/static/root/assets/work-discovery-page-BCANmOUS.js +0 -1
  192. package/dist/gateway/static/root/assets/work-item-detail-page-t5xiIEFv.js +0 -1
  193. package/dist/gateway/static/root/assets/work-page-CEI3zs-y.js +0 -1
  194. package/dist/gateway/static/root/assets/workflows-page-B8FRLCHp.js +0 -11
  195. package/dist/src/agent/lifecycle/handlers/compaction.d.ts +0 -13
  196. package/dist/src/agent/lifecycle/handlers/compaction.js +0 -18
  197. package/dist/src/session/compaction-checkpoints.d.ts +0 -8
  198. package/dist/src/session/compaction-checkpoints.js +0 -19
@@ -11,12 +11,16 @@ const DEFAULT_CONFIG = {
11
11
  * Stable fingerprint for tool call comparison.
12
12
  * Recursively sorts object keys; truncates long string values.
13
13
  */
14
- function fingerprint(toolName, params) {
15
- return `${toolName}::${JSON.stringify(params, (_key, value) => {
16
- if (typeof value === "object" && value !== null && !Array.isArray(value)) return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)));
17
- if (typeof value === "string" && value.length > 200) return `${value.slice(0, 80)}…[${value.length}]`;
18
- return value;
19
- })}`;
14
+ function stableJson(value) {
15
+ return JSON.stringify(value, (_key, item) => {
16
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) return Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b)));
17
+ if (typeof item === "string" && item.length > 200) return `${item.slice(0, 80)}…[${item.length}]`;
18
+ return item;
19
+ });
20
+ }
21
+ function fingerprint(call) {
22
+ const result = call.resultPreview === void 0 ? "" : `::result=${stableJson(call.resultPreview)}`;
23
+ return `${call.name}::${stableJson(call.params)}${result}`;
20
24
  }
21
25
  /**
22
26
  * Analyze recent tool calls and produce loop guard result.
@@ -70,11 +74,11 @@ function findConsecutiveRepeats(calls) {
70
74
  let index = calls.length - 1;
71
75
  while (index >= 0) {
72
76
  const current = calls[index];
73
- const fp = fingerprint(current.name, current.params);
77
+ const fp = fingerprint(current);
74
78
  let count = 1;
75
79
  while (index - count >= 0) {
76
80
  const prev = calls[index - count];
77
- if (fingerprint(prev.name, prev.params) !== fp) break;
81
+ if (fingerprint(prev) !== fp) break;
78
82
  count++;
79
83
  }
80
84
  if (count >= 2) groups.push({
@@ -92,7 +96,7 @@ function findConsecutiveRepeats(calls) {
92
96
  function countFrequency(calls) {
93
97
  const map = /* @__PURE__ */ new Map();
94
98
  for (const call of calls) {
95
- const fp = fingerprint(call.name, call.params);
99
+ const fp = fingerprint(call);
96
100
  map.set(fp, (map.get(fp) ?? 0) + 1);
97
101
  }
98
102
  return map;
@@ -5,6 +5,8 @@ export type PostCompactionContextOptions = {
5
5
  agentId?: string;
6
6
  nowMs?: number;
7
7
  userTimezone?: string;
8
+ sectionNames?: string[];
9
+ maxContextChars?: number;
8
10
  };
9
11
  export declare function readPostCompactionContextFromAgentsMd(agentsMdContent: string, options?: PostCompactionContextOptions): string | null;
10
12
  export declare function readPostCompactionContext(params: {
@@ -13,4 +15,6 @@ export declare function readPostCompactionContext(params: {
13
15
  agentId?: string;
14
16
  nowMs?: number;
15
17
  userTimezone?: string;
18
+ sectionNames?: string[];
19
+ maxContextChars?: number;
16
20
  }): string | null;
@@ -53,7 +53,7 @@ function extractSections(content, sectionNames, foundNames) {
53
53
  return results;
54
54
  }
55
55
  function readPostCompactionContextFromAgentsMd(agentsMdContent, options) {
56
- const sectionNames = DEFAULT_POST_COMPACTION_SECTIONS;
56
+ const sectionNames = options?.sectionNames ?? DEFAULT_POST_COMPACTION_SECTIONS;
57
57
  if (sectionNames.length === 0) return null;
58
58
  const foundSectionNames = [];
59
59
  const sections = extractSections(agentsMdContent, sectionNames, foundSectionNames);
@@ -62,7 +62,7 @@ function readPostCompactionContextFromAgentsMd(agentsMdContent, options) {
62
62
  const timezone = options?.userTimezone?.trim() || Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
63
63
  const nowMs = options?.nowMs ?? Date.now();
64
64
  const dateStamp = new Intl.DateTimeFormat("en-CA", { timeZone: timezone }).format(new Date(nowMs));
65
- const maxContextChars = MAX_CONTEXT_CHARS;
65
+ const maxContextChars = Math.max(1, options?.maxContextChars ?? MAX_CONTEXT_CHARS);
66
66
  const combined = sections.join("\n\n").replaceAll("YYYY-MM-DD", dateStamp);
67
67
  const safeContent = combined.length > maxContextChars ? `${combined.slice(0, maxContextChars)}\n...[truncated]...` : combined;
68
68
  const isDefaultSections = sectionNames.length === DEFAULT_POST_COMPACTION_SECTIONS.length && sectionNames.every((name, index) => normalizeHeading(name) === normalizeHeading(DEFAULT_POST_COMPACTION_SECTIONS[index] ?? ""));
@@ -84,7 +84,9 @@ function readPostCompactionContext(params) {
84
84
  cfg,
85
85
  agentId,
86
86
  nowMs: params.nowMs,
87
- userTimezone: params.userTimezone
87
+ userTimezone: params.userTimezone,
88
+ sectionNames: params.sectionNames,
89
+ maxContextChars: params.maxContextChars
88
90
  });
89
91
  } catch {
90
92
  return null;
@@ -102,7 +102,6 @@ export declare class AgentService {
102
102
  private createHookRunner;
103
103
  private createProgressManager;
104
104
  private initializeReliabilityModules;
105
- private initializeLifecycleHandlers;
106
105
  setChannelManager(channelManager: ChannelManager): void;
107
106
  /**
108
107
  * Apply config after save or hot reload so the default model updates without restarting the gateway.
@@ -191,7 +190,6 @@ export declare class AgentService {
191
190
  * Handle events from a specific session's agent
192
191
  */
193
192
  private handleSessionEvent;
194
- private checkAndCompact;
195
193
  private getContextWindowForSession;
196
194
  private dispose;
197
195
  }
@@ -15,6 +15,7 @@ import { onSessionTranscriptUpdate } from "../session/transcript-events.js";
15
15
  import { persistInboundAttachments } from "../channels/attachments/inbound-persist.js";
16
16
  import { AgentManager } from "./agent-manager.js";
17
17
  import { maybeRefineSessionTitleWithLlm, maybeSetProvisionalSessionTitle } from "../session/session-title.js";
18
+ import { resolveCompactionPolicy } from "./memory/compaction-policy.js";
18
19
  import { SessionStore } from "../session/store.js";
19
20
  import { SessionConfigStore } from "../session/config-store.js";
20
21
  import "../session/index.js";
@@ -38,7 +39,6 @@ import "./middleware/index.js";
38
39
  import { TurnDiffTracker } from "./coding/turn-diff-tracker.js";
39
40
  import { LifecycleManager } from "./lifecycle/manager.js";
40
41
  import "./lifecycle/index.js";
41
- import { CompactionLifecycleHandler } from "./lifecycle/handlers/compaction.js";
42
42
  import { MessageRouter } from "./messaging/message-router.js";
43
43
  import { CommandHandler } from "./messaging/command-handler.js";
44
44
  import { StreamManager } from "./messaging/stream-manager.js";
@@ -203,10 +203,20 @@ var AgentService = class {
203
203
  return this.currentContext?.sessionKey;
204
204
  }
205
205
  });
206
+ this.sessionStore.setCompactionHooks({
207
+ before: ({ sessionKey, messageCount, tokenCount }) => this.hookHandler.triggerWithSessionKey(sessionKey, "before_compaction", {
208
+ messageCount,
209
+ tokenCount
210
+ }),
211
+ after: ({ sessionKey, messageCount, tokenCount, compactedCount }) => this.hookHandler.triggerWithSessionKey(sessionKey, "after_compaction", {
212
+ messageCount,
213
+ tokenCount,
214
+ compactedCount
215
+ })
216
+ });
206
217
  this.progressManager = this.createProgressManager();
207
218
  this.initializeReliabilityModules();
208
219
  this.lifecycleManager = new LifecycleManager();
209
- this.initializeLifecycleHandlers();
210
220
  this.streamManager = new StreamManager();
211
221
  this.sessionContextManager = new SessionContextManager();
212
222
  this.feedbackCoordinator = new FeedbackCoordinator({
@@ -400,7 +410,6 @@ var AgentService = class {
400
410
  setupSessionEventHandling: (sk) => this.setupSessionEventHandling(sk),
401
411
  sessionHydrator: this.sessionHydrator,
402
412
  getLastAssistantPlainText: (sk) => this.getLastAssistantPlainText(sk),
403
- checkAndCompact: (sk, msgs) => this.checkAndCompact(sk, msgs),
404
413
  enqueueMaybeAutoTitleAfterPersist: (sk) => this.enqueueMaybeAutoTitleAfterPersist(sk),
405
414
  getConfig: () => this.effectiveAppConfig(),
406
415
  resetSession: (sk) => this.resetSession(sk),
@@ -418,19 +427,9 @@ var AgentService = class {
418
427
  keepRecentMessages: 20,
419
428
  preserveSystemMessages: true
420
429
  };
421
- const compactionConfig = {
422
- enabled: true,
423
- mode: "abstractive",
424
- reserveTokens: 8e3,
425
- triggerThreshold: .8,
426
- minMessagesBeforeCompact: 10,
427
- keepRecentMessages: 10,
428
- evictionWindow: .2,
429
- retentionWindow: 6
430
- };
431
430
  const appCfg = this.config.config;
432
431
  if (!appCfg) throw new Error("AgentService requires config.config for session store paths");
433
- return new SessionStore({ config: appCfg }, windowConfig, compactionConfig);
432
+ return new SessionStore({ config: appCfg }, windowConfig, resolveCompactionPolicy(appCfg));
434
433
  }
435
434
  createHookRunner() {
436
435
  if (!this.config.extensionRegistry) return void 0;
@@ -498,15 +497,6 @@ var AgentService = class {
498
497
  });
499
498
  this.contextMiddleware = new ContextMiddleware();
500
499
  }
501
- initializeLifecycleHandlers() {
502
- this.lifecycleManager.on("llm_response", new CompactionLifecycleHandler({
503
- minMessages: 20,
504
- maxTokens: 8e3,
505
- preserveReasoning: true,
506
- accumulateUsage: true
507
- }));
508
- log.debug({ handlers: this.lifecycleManager.getRegisteredHandlers() }, "Lifecycle handlers initialized");
509
- }
510
500
  setChannelManager(channelManager) {
511
501
  this.inboundLoop.setChannelManager(channelManager);
512
502
  }
@@ -809,27 +799,6 @@ var AgentService = class {
809
799
  }
810
800
  this.agentEventHandler.handle(event, currentContext);
811
801
  }
812
- async checkAndCompact(sessionKey, messages) {
813
- const contextWindow = this.getContextWindowForSession(sessionKey);
814
- const prep = this.sessionStore.prepareCompaction(sessionKey, messages, contextWindow);
815
- if (!prep.needsCompaction) return;
816
- log.info({
817
- sessionKey,
818
- reason: prep.stats?.reason,
819
- usagePercent: prep.stats?.usagePercent
820
- }, "Session needs compaction");
821
- const result = await this.sessionStore.compact(sessionKey, messages, contextWindow, void 0, false);
822
- await this.hookHandler.trigger("after_compaction", {
823
- messageCount: messages.length,
824
- tokenCount: result.tokensBefore,
825
- compactedCount: messages.length - result.firstKeptIndex
826
- });
827
- log.info({
828
- sessionKey,
829
- tokensBefore: result.tokensBefore,
830
- tokensAfter: result.tokensAfter
831
- }, "Session compacted");
832
- }
833
802
  getContextWindowForSession(sessionKey) {
834
803
  try {
835
804
  return this.modelManager.getResolvedModelForSession(sessionKey).contextWindow ?? 128e3;
@@ -2,8 +2,10 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { init_workspace_defaults, resolveDefaultAgentWorkspaceDir } from "../../config/workspace-defaults.js";
4
4
  import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
5
+ import { init_providers, resolveModel } from "../../providers/index.js";
5
6
  import { effectiveWorkspacePathForSession, projectWorkspacePath } from "../../session/session-workspace.js";
6
7
  import { getProjectForSession } from "../../projects/workspace.js";
8
+ import { resolveCompactionPolicy } from "../memory/compaction-policy.js";
7
9
  import { resolveVerboseLevel } from "../../session/config-store.js";
8
10
  import { resolveEffectiveReasoningLevel, resolveEffectiveThinkingLevel } from "../../session/thinking-resolve.js";
9
11
  import "../../session/index.js";
@@ -12,6 +14,7 @@ import { formatSessionContextReport } from "../service/session-context-report.js
12
14
  //#region src/agent/session/session-inspector.ts
13
15
  init_workspace_defaults();
14
16
  init_logger();
17
+ init_providers();
15
18
  const log = createLogger("SessionInspector");
16
19
  var SessionInspector = class {
17
20
  opts;
@@ -37,8 +40,13 @@ var SessionInspector = class {
37
40
  */
38
41
  async compact(sessionKey, options) {
39
42
  const messages = await this.opts.sessionStore.load(sessionKey);
40
- const contextWindow = await this.contextWindowForSession(sessionKey);
41
- const result = await this.opts.sessionStore.compact(sessionKey, messages, contextWindow, options?.instructions, options?.force ?? true);
43
+ await this.ensureEffectiveSessionModel(sessionKey);
44
+ const policy = resolveCompactionPolicy(this.opts.getConfig());
45
+ const sessionModel = this.opts.modelManager.getResolvedModelForSession(sessionKey);
46
+ const model = policy.model ? resolveModel(policy.model) : sessionModel;
47
+ const primaryRef = `${model.provider}/${model.id}`;
48
+ const fallbackModels = this.opts.modelManager.getFallbackCandidatesForSession(sessionKey).map((candidate) => resolveModel(`${candidate.provider}/${candidate.model}`)).filter((candidate) => `${candidate.provider}/${candidate.id}` !== primaryRef);
49
+ const result = await this.opts.sessionStore.compact(sessionKey, messages, model, options?.instructions, options?.force ?? true, { fallbackModels });
42
50
  if (result.compacted) this.opts.agentManager.removeAgent(sessionKey);
43
51
  log.info({
44
52
  sessionKey,
@@ -230,12 +230,12 @@ function createParallelGraph(spec) {
230
230
  {
231
231
  id: "output",
232
232
  kind: "output",
233
- title: "Result",
233
+ title: "Deliverable",
234
234
  position: {
235
235
  x: 1280,
236
236
  y: 260
237
237
  },
238
- config: { title: "Final result" }
238
+ config: {}
239
239
  }
240
240
  ],
241
241
  edges: [
@@ -1,7 +1,7 @@
1
+ import { buildMemoryRuntime } from "./memory-runtime.js";
1
2
  import { checkBoundary } from "./boundary-guard.js";
2
3
  import { resolveModelRole } from "./model-router.js";
3
4
  import { buildRuntimeToolRegistry } from "./tool-registry.js";
4
- import { buildMemoryRuntime } from "./memory-runtime.js";
5
5
  import { resolveWorkflow, validateWorkflowForRuntime } from "./workflow-runtime.js";
6
6
  import { buildAgentRuntimeProfile } from "./runtime-profile.js";
7
7
  import { appendAgentRunEvent, createAgentRunTrace, finishAgentRunTrace, hashEffectiveManifest } from "./run-trace.js";
@@ -1,9 +1,9 @@
1
1
  import { buildAgentManifestPromptSection } from "../agent-manifest/prompt.js";
2
2
  import "../agent-manifest/index.js";
3
+ import { buildMemoryRuntime } from "./memory-runtime.js";
3
4
  import { checkBoundary } from "./boundary-guard.js";
4
5
  import { resolveModelRole } from "./model-router.js";
5
6
  import { buildRuntimeToolRegistry } from "./tool-registry.js";
6
- import { buildMemoryRuntime } from "./memory-runtime.js";
7
7
  import { resolveWorkflow, validateWorkflowForRuntime } from "./workflow-runtime.js";
8
8
  //#region src/agent-runtime/runtime-profile.ts
9
9
  function buildAgentRuntimeProfile(params) {
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
52
52
  id: "database-schema",
53
53
  label: "Database schema",
54
54
  status: "pass",
55
- message: `SQLite schema v${status.dbVersion} (current release v59).`,
55
+ message: `SQLite schema v${status.dbVersion} (current release v61).`,
56
56
  hints: []
57
57
  };
58
58
  }
@@ -2,5 +2,7 @@
2
2
  * Catalog-driven model configuration for onboarding.
3
3
  */
4
4
  import type { Config } from '../../../config/schema.js';
5
+ import { XopcCloudModelSource } from '../../../providers/xopc-cloud-model-source.js';
5
6
  import type { CLIContext } from '../../registry.js';
7
+ export declare function refreshOnboardModelCatalogIfNeeded(provider: string, hasCatalogModels: boolean, source?: Pick<XopcCloudModelSource, 'refresh'>): Promise<void>;
6
8
  export declare function setupModel(existingConfig: Config | null, ctx: CLIContext): Promise<Config>;
@@ -9,6 +9,7 @@ import { getDomesticProviderBaseUrl, getDomesticProviderPreset, getDomesticProvi
9
9
  import { getProviderHint, getRecommendedModelsForProvider, sortModelsForPicker, sortProvidersForPicker } from "../../../providers/presentation.js";
10
10
  import { prepareUpdateGlobalDefaults } from "../../../gateway/global-defaults-admin.js";
11
11
  import { discoverProviderModels, isProviderApiDiscoverable } from "../../../providers/model-discovery.js";
12
+ import { XopcCloudModelSource } from "../../../providers/xopc-cloud-model-source.js";
12
13
  import { listProfilesForProvider } from "../../../auth/profiles/profiles.js";
13
14
  import { getOAuthProvider } from "../../utils/oauth-providers.js";
14
15
  import { colors } from "../../utils/colors.js";
@@ -89,6 +90,13 @@ function getModelsForProvider(provider) {
89
90
  };
90
91
  });
91
92
  }
93
+ async function refreshOnboardModelCatalogIfNeeded(provider, hasCatalogModels, source) {
94
+ if (provider !== "xopc-cloud" || hasCatalogModels) return;
95
+ console.log("\n→ Loading models from XOPC Model Service...");
96
+ const result = await (source ?? new XopcCloudModelSource()).refresh();
97
+ if (result.status === "skipped") throw new Error("XOPC Model Service credentials are unavailable after OAuth login. Please sign in again.");
98
+ console.log(colors.green(`✓ Loaded ${result.modelCount} models`));
99
+ }
92
100
  function discoveredModelsToChoices(provider, models) {
93
101
  return models.filter((model) => !model.id.includes("/")).map((model) => ({
94
102
  value: `${provider}/${model.id}`,
@@ -445,8 +453,13 @@ async function setupModel(existingConfig, ctx) {
445
453
  console.error(`\n❌ Could not configure credentials for ${providerName}.`);
446
454
  return config;
447
455
  }
448
- const modelChoices = getModelsForProvider(provider);
449
- if (modelChoices.length === 0) throw new Error(`No catalog models found for ${providerName}. Add a Custom API provider instead.`);
456
+ let modelChoices = getModelsForProvider(provider);
457
+ await refreshOnboardModelCatalogIfNeeded(provider, modelChoices.length > 0);
458
+ modelChoices = getModelsForProvider(provider);
459
+ if (modelChoices.length === 0) {
460
+ if (provider === "xopc-cloud") throw new Error(`No models are currently available for ${providerName}.`);
461
+ throw new Error(`No catalog models found for ${providerName}. Add a Custom API provider instead.`);
462
+ }
450
463
  console.log(`\n📋 Models for ${providerName}:`);
451
464
  const model = await select({
452
465
  message: "Model:",
@@ -459,4 +472,4 @@ async function setupModel(existingConfig, ctx) {
459
472
  return setPrimaryModel(config, ctx.workspacePath, model);
460
473
  }
461
474
  //#endregion
462
- export { setupModel };
475
+ export { refreshOnboardModelCatalogIfNeeded, setupModel };
@@ -1,6 +1,6 @@
1
+ import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
1
2
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
3
  import "../agent-manifest/index.js";
3
- import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
4
4
  import { init_session_key, parseSessionKey } from "../routing/session-key.js";
5
5
  import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
6
6
  //#region src/config/agent-profile.ts
@@ -460,7 +460,6 @@ export declare const SessionConfigSchema: z.ZodDefault<z.ZodObject<{
460
460
  }>>;
461
461
  identityLinks: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
462
462
  resetTriggers: z.ZodOptional<z.ZodArray<z.ZodString>>;
463
- idleMinutes: z.ZodOptional<z.ZodNumber>;
464
463
  reset: z.ZodOptional<z.ZodObject<{
465
464
  mode: z.ZodOptional<z.ZodEnum<{
466
465
  idle: "idle";
@@ -507,7 +506,7 @@ export declare const SessionConfigSchema: z.ZodDefault<z.ZodObject<{
507
506
  pruneAfterMs: z.ZodOptional<z.ZodNumber>;
508
507
  maxEntries: z.ZodOptional<z.ZodNumber>;
509
508
  }, z.core.$strip>>;
510
- }, z.core.$strip>>;
509
+ }, z.core.$strict>>;
511
510
  /** Channel buckets — shapes validated post-parse by registered channel plugins. */
512
511
  export declare const ChannelsConfigSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
513
512
  export declare const SearchProviderEntrySchema: z.ZodObject<{
@@ -1553,7 +1552,23 @@ export declare const ConfigSchema: z.ZodDefault<z.ZodObject<{
1553
1552
  }>>;
1554
1553
  }, z.core.$strict>>;
1555
1554
  retention: z.ZodOptional<z.ZodObject<{
1556
- compaction: z.ZodDefault<z.ZodBoolean>;
1555
+ compaction: z.ZodDefault<z.ZodObject<{
1556
+ enabled: z.ZodDefault<z.ZodBoolean>;
1557
+ triggerThreshold: z.ZodDefault<z.ZodNumber>;
1558
+ reserveTokens: z.ZodDefault<z.ZodNumber>;
1559
+ minMessagesBeforeCompact: z.ZodDefault<z.ZodNumber>;
1560
+ keepRecentTokens: z.ZodDefault<z.ZodNumber>;
1561
+ recentTurnsPreserve: z.ZodDefault<z.ZodNumber>;
1562
+ summaryMaxTokens: z.ZodDefault<z.ZodNumber>;
1563
+ summaryChunkTokens: z.ZodDefault<z.ZodNumber>;
1564
+ summaryTimeoutMs: z.ZodDefault<z.ZodNumber>;
1565
+ summaryRetries: z.ZodDefault<z.ZodNumber>;
1566
+ qualityGuard: z.ZodDefault<z.ZodBoolean>;
1567
+ model: z.ZodOptional<z.ZodString>;
1568
+ minToolResultKeepChars: z.ZodDefault<z.ZodNumber>;
1569
+ maxActiveTranscriptBytes: z.ZodDefault<z.ZodNumber>;
1570
+ postCompactionSections: z.ZodDefault<z.ZodArray<z.ZodString>>;
1571
+ }, z.core.$strict>>;
1557
1572
  maxAgeDays: z.ZodOptional<z.ZodNumber>;
1558
1573
  maxItems: z.ZodOptional<z.ZodNumber>;
1559
1574
  maxChars: z.ZodOptional<z.ZodNumber>;
@@ -1905,7 +1920,6 @@ export declare const ConfigSchema: z.ZodDefault<z.ZodObject<{
1905
1920
  }>>;
1906
1921
  identityLinks: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
1907
1922
  resetTriggers: z.ZodOptional<z.ZodArray<z.ZodString>>;
1908
- idleMinutes: z.ZodOptional<z.ZodNumber>;
1909
1923
  reset: z.ZodOptional<z.ZodObject<{
1910
1924
  mode: z.ZodOptional<z.ZodEnum<{
1911
1925
  idle: "idle";
@@ -1952,7 +1966,7 @@ export declare const ConfigSchema: z.ZodDefault<z.ZodObject<{
1952
1966
  pruneAfterMs: z.ZodOptional<z.ZodNumber>;
1953
1967
  maxEntries: z.ZodOptional<z.ZodNumber>;
1954
1968
  }, z.core.$strip>>;
1955
- }, z.core.$strip>>;
1969
+ }, z.core.$strict>>;
1956
1970
  channels: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1957
1971
  gateway: z.ZodDefault<z.ZodObject<{
1958
1972
  bind: z.ZodOptional<z.ZodEnum<{
@@ -263,12 +263,11 @@ var init_schema = __esmMin((() => {
263
263
  dmScope: SessionDmScopeSchema.default("main"),
264
264
  identityLinks: z.record(z.string(), z.array(z.string())).optional(),
265
265
  resetTriggers: z.array(z.string()).optional(),
266
- idleMinutes: z.number().int().positive().optional(),
267
266
  reset: SessionResetConfigSchema.optional(),
268
267
  resetByType: SessionResetByTypeSchema.optional(),
269
268
  resetByChannel: z.record(z.string(), SessionResetConfigSchema).optional(),
270
269
  storage: SessionStorageConfigSchema.optional()
271
- }).default({
270
+ }).strict().default({
272
271
  scope: "per-sender",
273
272
  mainKey: "main",
274
273
  dmScope: "main"
@@ -1,5 +1,5 @@
1
- import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
1
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
2
+ import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
3
3
  import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
4
4
  import { WORKSPACE_FILES, init_paths, resolveUserProfilePath } from "../config/paths.js";
5
5
  import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
@@ -307,6 +307,29 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
307
307
  maxEntries: number;
308
308
  };
309
309
  };
310
+ userContext: {
311
+ memory: {
312
+ retention: {
313
+ compaction: {
314
+ enabled: boolean;
315
+ triggerThreshold: number;
316
+ reserveTokens: number;
317
+ minMessagesBeforeCompact: number;
318
+ keepRecentTokens: number;
319
+ recentTurnsPreserve: number;
320
+ summaryMaxTokens: number;
321
+ summaryChunkTokens: number;
322
+ summaryTimeoutMs: number;
323
+ summaryRetries: number;
324
+ qualityGuard: boolean;
325
+ minToolResultKeepChars: number;
326
+ maxActiveTranscriptBytes: number;
327
+ postCompactionSections: string[];
328
+ model?: string;
329
+ };
330
+ };
331
+ };
332
+ };
310
333
  tui: {
311
334
  defaultAgent: string;
312
335
  };
@@ -1,3 +1,4 @@
1
+ import { ContextCompactionPolicySchema, init_config } from "../../../user-context/config.js";
1
2
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
2
3
  import { resolveModelsJsonPath } from "../../../config/paths.js";
3
4
  import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
@@ -20,6 +21,7 @@ init_credentials();
20
21
  init_models_json();
21
22
  init_providers();
22
23
  init_plugin_registry();
24
+ init_config();
23
25
  function readModelsJsonProviderApiKey(providerId) {
24
26
  const { config } = loadModelsJson(resolveModelsJsonPath());
25
27
  const key = (config.providers?.[providerId])?.apiKey;
@@ -175,6 +177,7 @@ async function buildSafeWebConfigPayload(service, options = {}) {
175
177
  browser: buildSafeBrowserConfigForWeb(config.browser),
176
178
  goals: resolveGoalsConfigForWeb(config),
177
179
  session: resolveSessionConfigForWeb(config),
180
+ userContext: { memory: { retention: { compaction: ContextCompactionPolicySchema.parse(config.userContext?.memory.retention?.compaction) } } },
178
181
  tui: { defaultAgent: config.tui?.defaultAgent ?? "coder" },
179
182
  tunnel: {
180
183
  enabled: config.tunnel?.enabled === true,
@@ -2,7 +2,7 @@
2
2
  * `PATCH /api/config` — tail sections that are each <50 lines:
3
3
  * update / goals / session / gateway.{skillsMarketplaceProvider,
4
4
  * skillsStoreBaseUrl} / providers / providersConfig / stt / tts / tools /
5
- * tunnel / bindings / mcp.
5
+ * userContext.memory.retention.compaction / tunnel / bindings / mcp.
6
6
  *
7
7
  * Most of these delegate to a `mergeXxxConfigPatch(config, body) → { ok,
8
8
  * message? }` helper that lives next to the schema, so this file is mostly
@@ -1,3 +1,4 @@
1
+ import { ContextCompactionPolicySchema, init_config } from "../../../../user-context/config.js";
1
2
  import { BindingsConfigSchema, BrowserConfigSchema, McpConfigSchema, VoiceConfigSchema, init_schema } from "../../../../config/schema.js";
2
3
  import { CredentialResolver, init_credentials } from "../../../../auth/credentials.js";
3
4
  import { canonicalizeConfiguredMcpServer } from "../../../../config/mcp-config-normalize.js";
@@ -13,6 +14,7 @@ import { PATCH_OK, patchError } from "./result.js";
13
14
  //#region src/gateway/hono/routes/config-patch/misc.ts
14
15
  init_schema();
15
16
  init_credentials();
17
+ init_config();
16
18
  async function applyMiscPatch(config, body) {
17
19
  if (body.update !== void 0 && typeof body.update === "object" && body.update !== null) {
18
20
  const updateResult = mergeUpdateConfigPatch(config, body.update);
@@ -28,6 +30,32 @@ async function applyMiscPatch(config, body) {
28
30
  const sessionResult = mergeSessionConfigPatch(config, body.session);
29
31
  if (sessionResult.ok === false) return patchError(sessionResult.message);
30
32
  }
33
+ if (body.userContext !== void 0) {
34
+ if (typeof body.userContext !== "object" || body.userContext === null || Array.isArray(body.userContext)) return patchError("userContext must be an object");
35
+ const userContextPatch = body.userContext;
36
+ if (userContextPatch.memory !== void 0) {
37
+ if (typeof userContextPatch.memory !== "object" || userContextPatch.memory === null || Array.isArray(userContextPatch.memory)) return patchError("userContext.memory must be an object");
38
+ const memoryPatch = userContextPatch.memory;
39
+ if (memoryPatch.retention !== void 0) {
40
+ if (typeof memoryPatch.retention !== "object" || memoryPatch.retention === null || Array.isArray(memoryPatch.retention)) return patchError("userContext.memory.retention must be an object");
41
+ const retentionPatch = memoryPatch.retention;
42
+ if (retentionPatch.compaction !== void 0) {
43
+ const parsed = ContextCompactionPolicySchema.safeParse(retentionPatch.compaction);
44
+ if (!parsed.success) return patchError(parsed.error.issues.map((issue) => issue.message).join("; "));
45
+ config.userContext = {
46
+ ...config.userContext,
47
+ memory: {
48
+ ...config.userContext?.memory,
49
+ retention: {
50
+ ...config.userContext?.memory?.retention,
51
+ compaction: parsed.data
52
+ }
53
+ }
54
+ };
55
+ }
56
+ }
57
+ }
58
+ }
31
59
  if (body.tui !== void 0) {
32
60
  if (typeof body.tui !== "object" || body.tui === null || Array.isArray(body.tui)) return patchError("tui must be an object");
33
61
  const tuiPatch = body.tui;