openfox 2.0.0-beta.1 → 2.0.0-beta.11

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 (49) hide show
  1. package/dist/agent-defaults/code-reviewer.agent.md +2 -1
  2. package/dist/{chat-handler-IVIWOR3D.js → chat-handler-NMJCOCCB.js} +14 -27
  3. package/dist/{chunk-ZLUBZ4K4.js → chunk-4RLDN2LL.js} +222 -106
  4. package/dist/{chunk-CEZNMLOO.js → chunk-7TTEGAO6.js} +12 -13
  5. package/dist/chunk-BU56QFHW.js +315 -0
  6. package/dist/{chunk-FQLK5GL5.js → chunk-BVHFMAVN.js} +1 -1
  7. package/dist/{chunk-RF2JGDSS.js → chunk-DMH6JVPF.js} +13 -10
  8. package/dist/{chunk-ALH4KM2Y.js → chunk-EQQDA4D3.js} +2967 -3248
  9. package/dist/{chunk-QFSSKIQ3.js → chunk-EXYMWI7A.js} +4 -4
  10. package/dist/{chunk-NNEHZT3V.js → chunk-EZUR7OEP.js} +11 -3
  11. package/dist/{chunk-NONI4CRP.js → chunk-ITWVFGFV.js} +5 -61
  12. package/dist/{chunk-4U4CSRBE.js → chunk-LCRJWUW7.js} +6 -6
  13. package/dist/{chunk-XKR3HCAL.js → chunk-NSBYORD5.js} +177 -34
  14. package/dist/{chunk-PSJIT5LZ.js → chunk-RFNEDBVO.js} +4 -4
  15. package/dist/chunk-RI6GAMNP.js +13 -0
  16. package/dist/{chunk-HHAJ3QF6.js → chunk-UKTPL5ZG.js} +16 -28
  17. package/dist/{chunk-HGAMIPFO.js → chunk-VIIRNJDT.js} +39 -178
  18. package/dist/cli/dev.js +1 -1
  19. package/dist/cli/index.js +1 -1
  20. package/dist/compactor-TDNRM3A7.js +9 -0
  21. package/dist/{config-YU7NYZYG.js → config-TDVA7MQN.js} +9 -8
  22. package/dist/{events-OHJWCI3S.js → events-UGTGGFG3.js} +8 -7
  23. package/dist/{folding-U6UHQAS5.js → folding-YOCGTZYH.js} +2 -2
  24. package/dist/{orchestrator-7ZXM4J22.js → orchestrator-75L5UGDU.js} +18 -22
  25. package/dist/package.json +1 -1
  26. package/dist/{processor-TKBJLQ2N.js → processor-GHESQ2YV.js} +8 -9
  27. package/dist/{protocol-BQ12Aw5J.d.ts → protocol-B9R1CUvt.d.ts} +14 -39
  28. package/dist/{protocol-K62EPEGS.js → protocol-CN24IKQN.js} +3 -5
  29. package/dist/{provider-HTJEB3ON.js → provider-BGH4MBLH.js} +25 -10
  30. package/dist/{serve-5KA6SSSP.js → serve-I6T7V62Z.js} +25 -26
  31. package/dist/server/index.d.ts +1 -6
  32. package/dist/server/index.js +15 -16
  33. package/dist/{settings-VRAOAPLA.js → settings-6XX56F3F.js} +2 -2
  34. package/dist/shared/index.d.ts +2 -2
  35. package/dist/shared/index.js +1 -1
  36. package/dist/{tools-Z7X4HXZN.js → tools-D3WWIOQD.js} +11 -13
  37. package/dist/web/assets/{index-BY8EbT5Z.css → index-CSOB8dwI.css} +1 -1
  38. package/dist/web/assets/index-tJDr1ODC.js +299 -0
  39. package/dist/web/index.html +2 -2
  40. package/dist/web/sw.js +1 -1
  41. package/dist/workflow-defaults/default.workflow.json +9 -4
  42. package/package.json +1 -1
  43. package/dist/auto-compaction-UIWTO3H5.js +0 -27
  44. package/dist/chunk-CGZHLM3K.js +0 -70
  45. package/dist/chunk-SZKEGZIB.js +0 -140
  46. package/dist/chunk-UFY4I643.js +0 -332
  47. package/dist/runtime-config-NPSPMRDA.js +0 -9
  48. package/dist/vision-fallback-3MIZZ6NQ.js +0 -22
  49. package/dist/web/assets/index-CqOJgw7l.js +0 -299
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  getEventStore,
3
3
  updateSessionMetadata
4
- } from "./chunk-XKR3HCAL.js";
4
+ } from "./chunk-NSBYORD5.js";
5
5
  import {
6
6
  buildMessagesFromStoredEvents,
7
7
  foldPendingConfirmations
8
- } from "./chunk-NONI4CRP.js";
8
+ } from "./chunk-ITWVFGFV.js";
9
9
  import {
10
10
  createContextStateMessage,
11
11
  createSessionStateMessage
12
- } from "./chunk-CEZNMLOO.js";
12
+ } from "./chunk-7TTEGAO6.js";
13
13
  import {
14
14
  logger
15
15
  } from "./chunk-K44MW7JJ.js";
@@ -143,4 +143,4 @@ export {
143
143
  needsNameGenerationCheck,
144
144
  applyGeneratedSessionName
145
145
  };
146
- //# sourceMappingURL=chunk-QFSSKIQ3.js.map
146
+ //# sourceMappingURL=chunk-EXYMWI7A.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  detectModel
3
- } from "./chunk-HHAJ3QF6.js";
3
+ } from "./chunk-UKTPL5ZG.js";
4
4
  import {
5
5
  detectBackend
6
- } from "./chunk-HGAMIPFO.js";
6
+ } from "./chunk-VIIRNJDT.js";
7
7
  import {
8
8
  getGlobalConfigPath
9
9
  } from "./chunk-CQGTEGKL.js";
@@ -71,6 +71,7 @@ var providerSchema = z.object({
71
71
  models: z.array(modelConfigSchema).default([]),
72
72
  isActive: z.boolean(),
73
73
  createdAt: z.string(),
74
+ isLocal: z.boolean().optional(),
74
75
  // Deprecated: model field kept for migration, will be removed after migration
75
76
  model: z.string().optional(),
76
77
  // Deprecated: maxContext kept for migration
@@ -323,6 +324,12 @@ function addProvider(config, provider) {
323
324
  }
324
325
  };
325
326
  }
327
+ function updateProvider(config, providerId, updates) {
328
+ return {
329
+ ...config,
330
+ providers: config.providers.map((p) => p.id === providerId ? { ...p, ...updates } : p)
331
+ };
332
+ }
326
333
  function removeProvider(config, providerId) {
327
334
  const currentProviders = config.providers ?? [];
328
335
  const filtered = currentProviders.filter((p) => p.id !== providerId);
@@ -431,8 +438,9 @@ export {
431
438
  getDefaultModel,
432
439
  setDefaultModelSelection,
433
440
  addProvider,
441
+ updateProvider,
434
442
  removeProvider,
435
443
  activateProvider,
436
444
  mergeConfigs
437
445
  };
438
- //# sourceMappingURL=chunk-NNEHZT3V.js.map
446
+ //# sourceMappingURL=chunk-EZUR7OEP.js.map
@@ -40,7 +40,6 @@ function updateMessageDone(msg, data) {
40
40
  if (data.stats) msg.stats = data.stats;
41
41
  if (data.segments) msg.segments = data.segments;
42
42
  if (data.partial) msg.partial = true;
43
- if (data.promptContext) msg.promptContext = data.promptContext;
44
43
  if (data.tokenCount !== void 0) msg.tokenCount = data.tokenCount;
45
44
  if ("preparingToolCalls" in msg) {
46
45
  msg.preparingToolCalls = [];
@@ -135,9 +134,10 @@ function applyEvents(initialMessages, events, options) {
135
134
  }
136
135
  break;
137
136
  }
138
- case "format.retry": {
137
+ case "pattern.retry": {
139
138
  const data = event.data;
140
- for (const msg of messages.values()) {
139
+ const msg = messages.get(data.messageId);
140
+ if (msg) {
141
141
  const retries = msg.formatRetries ?? [];
142
142
  retries.push({ attempt: data.attempt, maxAttempts: data.maxAttempts, timestamp: event.timestamp });
143
143
  msg.formatRetries = retries;
@@ -210,30 +210,6 @@ function deepCloneMessage(msg) {
210
210
  return cloned;
211
211
  }
212
212
 
213
- // src/server/events/optimize-storage.ts
214
- function stripPromptContextMessages(messages) {
215
- let lastAssistantIdx = -1;
216
- for (let i = messages.length - 1; i >= 0; i--) {
217
- const msg = messages[i];
218
- if (!msg) continue;
219
- if (msg.role === "assistant" && msg.promptContext) {
220
- lastAssistantIdx = i;
221
- break;
222
- }
223
- }
224
- let changed = false;
225
- for (let i = 0; i < messages.length; i++) {
226
- const msg = messages[i];
227
- if (!msg) continue;
228
- const pc = msg.promptContext;
229
- if (pc && pc.messages && pc.messages.length > 0 && i !== lastAssistantIdx) {
230
- pc.messages = [];
231
- changed = true;
232
- }
233
- }
234
- return changed;
235
- }
236
-
237
213
  // src/server/events/folding.ts
238
214
  import stripAnsi from "strip-ansi";
239
215
  function cloneMessage(message) {
@@ -266,7 +242,6 @@ function spreadOptionalMessageFields(message) {
266
242
  ...message.messageKind !== void 0 && { messageKind: message.messageKind },
267
243
  ...message.contextWindowId !== void 0 && { contextWindowId: message.contextWindowId },
268
244
  ...message.isCompactionSummary !== void 0 && { isCompactionSummary: message.isCompactionSummary },
269
- ...message.promptContext !== void 0 && { promptContext: message.promptContext },
270
245
  ...message.attachments !== void 0 && { attachments: message.attachments },
271
246
  ...message.preparingToolCalls !== void 0 && message.preparingToolCalls.length > 0 && { preparingToolCalls: message.preparingToolCalls },
272
247
  ...message.metadata !== void 0 && { metadata: message.metadata }
@@ -646,30 +621,12 @@ function foldSessionState(events, initialWindowId, maxTokens, initialMessages) {
646
621
  dynamicContextChanged: false
647
622
  };
648
623
  const contextState = baseContextState.compactionCount !== contextResult.compactionCount || baseContextState.maxTokens !== maxTokens ? { ...baseContextState, compactionCount: contextResult.compactionCount, maxTokens } : { ...baseContextState, maxTokens };
649
- let messageReminderMode;
650
- let snapshotReminderMode;
651
624
  let cachedSystemPrompt;
652
625
  let dynamicContextHash;
653
626
  for (let i = events.length - 1; i >= 0; i--) {
654
627
  const event = events[i];
655
- if (event.type === "message.start") {
656
- const data = event.data;
657
- if (data.role === "user" && data.messageKind === "auto-prompt" && data.content?.includes("<system-reminder>")) {
658
- if (data.content.includes("Plan Mode")) {
659
- messageReminderMode = { seq: event.seq, mode: "planner" };
660
- } else if (data.content.includes("Build Mode")) {
661
- messageReminderMode = { seq: event.seq, mode: "builder" };
662
- }
663
- }
664
- }
665
628
  if (event.type === "turn.snapshot") {
666
629
  const snapshotData = event.data;
667
- if (snapshotData.lastModeWithReminder) {
668
- snapshotReminderMode = {
669
- seq: event.seq,
670
- mode: snapshotData.lastModeWithReminder
671
- };
672
- }
673
630
  if (snapshotData.cachedSystemPrompt && !cachedSystemPrompt) {
674
631
  cachedSystemPrompt = snapshotData.cachedSystemPrompt;
675
632
  }
@@ -681,14 +638,6 @@ function foldSessionState(events, initialWindowId, maxTokens, initialMessages) {
681
638
  }
682
639
  }
683
640
  }
684
- let lastModeWithReminder;
685
- if (messageReminderMode && snapshotReminderMode) {
686
- lastModeWithReminder = messageReminderMode.seq > snapshotReminderMode.seq ? messageReminderMode.mode : snapshotReminderMode.mode;
687
- } else if (snapshotReminderMode) {
688
- lastModeWithReminder = snapshotReminderMode.mode;
689
- } else if (messageReminderMode) {
690
- lastModeWithReminder = messageReminderMode.mode;
691
- }
692
641
  let sessionInit;
693
642
  let sessionTitle;
694
643
  const visionFallbacks = [];
@@ -734,7 +683,7 @@ function foldSessionState(events, initialWindowId, maxTokens, initialMessages) {
734
683
  }
735
684
  break;
736
685
  }
737
- case "format.retry": {
686
+ case "pattern.retry": {
738
687
  const data = event.data;
739
688
  formatRetries.push({
740
689
  attempt: data.attempt,
@@ -783,7 +732,6 @@ function foldSessionState(events, initialWindowId, maxTokens, initialMessages) {
783
732
  contextState,
784
733
  currentContextWindowId: contextResult.currentContextWindowId,
785
734
  readFiles: contextResult.readFiles,
786
- ...lastModeWithReminder !== void 0 && { lastModeWithReminder },
787
735
  ...cachedSystemPrompt !== void 0 && { cachedSystemPrompt },
788
736
  ...dynamicContextHash !== void 0 && { dynamicContextHash },
789
737
  pendingConfirmations,
@@ -809,7 +757,6 @@ function buildSnapshot(foldedState, latestSeq, snapshotAt = Date.now()) {
809
757
  currentContextWindowId: foldedState.currentContextWindowId,
810
758
  todos: foldedState.todos,
811
759
  readFiles: foldedState.readFiles,
812
- ...foldedState.lastModeWithReminder !== void 0 && { lastModeWithReminder: foldedState.lastModeWithReminder },
813
760
  ...foldedState.cachedSystemPrompt !== void 0 && { cachedSystemPrompt: foldedState.cachedSystemPrompt },
814
761
  ...foldedState.dynamicContextHash !== void 0 && { dynamicContextHash: foldedState.dynamicContextHash },
815
762
  snapshotSeq: latestSeq,
@@ -845,7 +792,6 @@ function buildSnapshotFromSessionState(input) {
845
792
  latestSnapshotEvent.data.messages,
846
793
  events.slice(latestSnapshotIndex + 1)
847
794
  ) : foldedState.messages;
848
- stripPromptContextMessages(messages);
849
795
  return {
850
796
  mode: session.mode,
851
797
  phase: session.phase,
@@ -867,7 +813,6 @@ function buildSnapshotFromSessionState(input) {
867
813
  snapshotSeq: latestSeq,
868
814
  snapshotAt,
869
815
  ...foldedState.sessionInit !== void 0 && { sessionInit: foldedState.sessionInit },
870
- ...foldedState.lastModeWithReminder !== void 0 && { lastModeWithReminder: foldedState.lastModeWithReminder },
871
816
  ...input.cachedSystemPrompt !== void 0 ? { cachedSystemPrompt: input.cachedSystemPrompt } : foldedState.cachedSystemPrompt !== void 0 ? { cachedSystemPrompt: foldedState.cachedSystemPrompt } : {},
872
817
  ...input.dynamicContextHash !== void 0 ? { dynamicContextHash: input.dynamicContextHash } : foldedState.dynamicContextHash !== void 0 ? { dynamicContextHash: foldedState.dynamicContextHash } : {}
873
818
  };
@@ -886,7 +831,6 @@ function buildContextMessagesFromMessages(messages, windowId) {
886
831
  }
887
832
 
888
833
  export {
889
- stripPromptContextMessages,
890
834
  spreadOptionalMessageFields,
891
835
  buildMessagesFromStoredEvents,
892
836
  buildContextMessagesFromStoredEvents,
@@ -912,4 +856,4 @@ export {
912
856
  getMessagesForWindow,
913
857
  buildContextMessagesFromMessages
914
858
  };
915
- //# sourceMappingURL=chunk-NONI4CRP.js.map
859
+ //# sourceMappingURL=chunk-ITWVFGFV.js.map
@@ -33,7 +33,7 @@ Options:
33
33
  }
34
34
  async function runNetworkSetup(mode) {
35
35
  const { loadAuthConfig, saveAuthConfig, encryptPassword } = await import("./auth-56SIRACI.js");
36
- const { saveGlobalConfig } = await import("./config-YU7NYZYG.js");
36
+ const { saveGlobalConfig } = await import("./config-TDVA7MQN.js");
37
37
  const { getAuthKeyPath } = await import("./paths-X46PPOI2.js");
38
38
  const existingAuth = await loadAuthConfig(mode);
39
39
  if (existingAuth) {
@@ -94,7 +94,7 @@ async function runNetworkSetup(mode) {
94
94
  console.log("\u2713 Configuration saved!\n");
95
95
  }
96
96
  async function runConfig(mode) {
97
- const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import("./config-YU7NYZYG.js");
97
+ const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import("./config-TDVA7MQN.js");
98
98
  const { getGlobalConfigPath } = await import("./paths-X46PPOI2.js");
99
99
  const config = await loadGlobalConfig(mode);
100
100
  const configPath = getGlobalConfigPath(mode);
@@ -151,7 +151,7 @@ async function runCli(options) {
151
151
  break;
152
152
  }
153
153
  case "provider": {
154
- const { runProviderCommand } = await import("./provider-HTJEB3ON.js");
154
+ const { runProviderCommand } = await import("./provider-BGH4MBLH.js");
155
155
  const [, subcommand] = positionals;
156
156
  await runProviderCommand(mode, subcommand);
157
157
  break;
@@ -188,12 +188,12 @@ async function runCli(options) {
188
188
  break;
189
189
  }
190
190
  default: {
191
- const { configFileExists } = await import("./config-YU7NYZYG.js");
191
+ const { configFileExists } = await import("./config-TDVA7MQN.js");
192
192
  const configExists = await configFileExists(mode);
193
193
  if (!configExists) {
194
194
  await runNetworkSetup(mode);
195
195
  }
196
- const { runServe } = await import("./serve-5KA6SSSP.js");
196
+ const { runServe } = await import("./serve-I6T7V62Z.js");
197
197
  const serveOptions = { mode };
198
198
  if (values.port) serveOptions.port = parseInt(values.port);
199
199
  if (values["no-browser"] === true) serveOptions.openBrowser = false;
@@ -205,4 +205,4 @@ async function runCli(options) {
205
205
  export {
206
206
  runCli
207
207
  };
208
- //# sourceMappingURL=chunk-4U4CSRBE.js.map
208
+ //# sourceMappingURL=chunk-LCRJWUW7.js.map
@@ -1,18 +1,14 @@
1
- import {
2
- getDatabase
3
- } from "./chunk-FBGWG4N6.js";
4
1
  import {
5
2
  buildContextMessagesFromEventHistory,
6
3
  buildMessagesFromStoredEvents,
7
4
  buildSnapshot,
8
5
  foldContextState,
9
6
  foldSessionState,
10
- spreadOptionalMessageFields,
11
- stripPromptContextMessages
12
- } from "./chunk-NONI4CRP.js";
7
+ spreadOptionalMessageFields
8
+ } from "./chunk-ITWVFGFV.js";
13
9
  import {
14
- getRuntimeConfig
15
- } from "./chunk-CGZHLM3K.js";
10
+ getDatabase
11
+ } from "./chunk-FBGWG4N6.js";
16
12
  import {
17
13
  logger
18
14
  } from "./chunk-K44MW7JJ.js";
@@ -105,6 +101,18 @@ var EventStore = class {
105
101
  CREATE INDEX IF NOT EXISTS idx_events_session_type
106
102
  ON events(session_id, event_type)
107
103
  `);
104
+ this.db.exec(`
105
+ CREATE TABLE IF NOT EXISTS tombstones (
106
+ session_id TEXT NOT NULL,
107
+ seq INTEGER NOT NULL,
108
+ timestamp INTEGER NOT NULL,
109
+ UNIQUE(session_id, seq)
110
+ )
111
+ `);
112
+ this.db.exec(`
113
+ CREATE INDEX IF NOT EXISTS idx_tombstones_session_seq
114
+ ON tombstones(session_id, seq)
115
+ `);
108
116
  }
109
117
  // --------------------------------------------------------------------------
110
118
  // Append
@@ -183,10 +191,41 @@ var EventStore = class {
183
191
  * Get all events for a session, optionally starting from a specific seq
184
192
  */
185
193
  getEvents(sessionId, fromSeq) {
186
- const query = fromSeq !== void 0 ? `SELECT * FROM events WHERE session_id = ? AND seq >= ? ORDER BY seq` : `SELECT * FROM events WHERE session_id = ? ORDER BY seq`;
194
+ const query = fromSeq !== void 0 ? `SELECT e.* FROM events e
195
+ LEFT JOIN tombstones t ON e.session_id = t.session_id AND e.seq = t.seq
196
+ WHERE e.session_id = ? AND e.seq >= ? AND t.seq IS NULL
197
+ ORDER BY e.seq` : `SELECT e.* FROM events e
198
+ LEFT JOIN tombstones t ON e.session_id = t.session_id AND e.seq = t.seq
199
+ WHERE e.session_id = ? AND t.seq IS NULL
200
+ ORDER BY e.seq`;
187
201
  const rows = fromSeq !== void 0 ? this.db.prepare(query).all(sessionId, fromSeq) : this.db.prepare(query).all(sessionId);
188
202
  return rows.map((row) => this.rowToStoredEvent(row));
189
203
  }
204
+ /**
205
+ * Soft-delete (tombstone) events by sequence number.
206
+ * Tombstoned events are hidden from getEvents but remain in the database.
207
+ *
208
+ * @param sessionId - The session ID
209
+ * @param seqs - Array of sequence numbers to tombstone
210
+ * @returns The number of events tombstoned
211
+ */
212
+ tombstoneEvents(sessionId, seqs) {
213
+ if (seqs.length === 0) return 0;
214
+ const timestamp = Date.now();
215
+ const insert = this.db.prepare(
216
+ `INSERT OR IGNORE INTO tombstones (session_id, seq, timestamp)
217
+ VALUES (?, ?, ?)`
218
+ );
219
+ let count = 0;
220
+ const transaction = this.db.transaction(() => {
221
+ for (const seq of seqs) {
222
+ const result = insert.run(sessionId, seq, timestamp);
223
+ count += result.changes;
224
+ }
225
+ });
226
+ transaction();
227
+ return count;
228
+ }
190
229
  /**
191
230
  * Get the latest sequence number for a session
192
231
  */
@@ -224,6 +263,55 @@ var EventStore = class {
224
263
  events
225
264
  };
226
265
  }
266
+ /**
267
+ * Get ALL events for a session, including synthetic events reconstructed
268
+ * from the latest snapshot's messages. This provides a unified view of the
269
+ * full event history even after cleanupOldEvents has deleted raw events.
270
+ *
271
+ * Synthetic events have seq=0 and are reconstructed as message.start +
272
+ * message.done pairs from snapshot messages. Real events since the snapshot
273
+ * keep their original seq numbers.
274
+ */
275
+ getAllEvents(sessionId) {
276
+ const { snapshot, events } = this.getEventsSinceSnapshot(sessionId);
277
+ if (!snapshot) {
278
+ return events;
279
+ }
280
+ const syntheticEvents = [];
281
+ for (const msg of snapshot.messages) {
282
+ syntheticEvents.push({
283
+ seq: 0,
284
+ timestamp: msg.timestamp,
285
+ sessionId,
286
+ type: "message.start",
287
+ data: {
288
+ messageId: msg.id,
289
+ role: msg.role,
290
+ content: msg.content,
291
+ ...msg.contextWindowId !== void 0 && { contextWindowId: msg.contextWindowId },
292
+ ...msg.isSystemGenerated !== void 0 && { isSystemGenerated: msg.isSystemGenerated },
293
+ ...msg.messageKind !== void 0 && { messageKind: msg.messageKind },
294
+ ...msg.metadata !== void 0 && { metadata: msg.metadata },
295
+ ...msg.subAgentId !== void 0 && { subAgentId: msg.subAgentId },
296
+ ...msg.subAgentType !== void 0 && { subAgentType: msg.subAgentType },
297
+ ...msg.isCompactionSummary !== void 0 && { isCompactionSummary: msg.isCompactionSummary },
298
+ ...msg.attachments !== void 0 && { attachments: msg.attachments }
299
+ }
300
+ });
301
+ syntheticEvents.push({
302
+ seq: 0,
303
+ timestamp: msg.timestamp,
304
+ sessionId,
305
+ type: "message.done",
306
+ data: { messageId: msg.id }
307
+ });
308
+ }
309
+ return [...syntheticEvents, ...events].sort((a, b) => {
310
+ const tsDiff = a.timestamp - b.timestamp;
311
+ if (tsDiff !== 0) return tsDiff;
312
+ return a.seq - b.seq;
313
+ });
314
+ }
227
315
  rowToStoredEvent(row) {
228
316
  return {
229
317
  seq: row.seq,
@@ -375,13 +463,10 @@ var EventStore = class {
375
463
  return result.changes;
376
464
  }
377
465
  /**
378
- * One-time storage optimization: delete old snapshots and strip
379
- * promptContext.messages from remaining snapshots across all sessions.
466
+ * One-time storage optimization: delete old snapshots across all sessions.
380
467
  * Safe to run multiple times (idempotent).
381
468
  */
382
469
  optimizeStorage() {
383
- let deletedSnapshots = 0;
384
- let strippedSnapshots = 0;
385
470
  const deleteResult = this.db.prepare(
386
471
  `
387
472
  DELETE FROM events
@@ -397,20 +482,7 @@ var EventStore = class {
397
482
  )
398
483
  `
399
484
  ).run();
400
- deletedSnapshots = deleteResult.changes;
401
- const snapshots = this.db.prepare(`SELECT id, payload FROM events WHERE event_type = 'turn.snapshot'`).all();
402
- const updateStmt = this.db.prepare(`UPDATE events SET payload = ? WHERE id = ?`);
403
- for (const row of snapshots) {
404
- const data = JSON.parse(row.payload);
405
- const messages = data.messages;
406
- if (!messages) continue;
407
- const changed = stripPromptContextMessages(messages);
408
- if (changed) {
409
- updateStmt.run(JSON.stringify(data), row.id);
410
- strippedSnapshots++;
411
- }
412
- }
413
- return { deletedSnapshots, strippedSnapshots };
485
+ return { deletedSnapshots: deleteResult.changes };
414
486
  }
415
487
  /**
416
488
  * Get the latest snapshot sequence number for a session
@@ -521,7 +593,7 @@ function initEventStore(db) {
521
593
  }
522
594
  resetStaleRunningSessions(eventStoreInstance, db);
523
595
  const result = eventStoreInstance.optimizeStorage();
524
- if (result.deletedSnapshots > 0 || result.strippedSnapshots > 0) {
596
+ if (result.deletedSnapshots > 0) {
525
597
  logger.info("Storage optimized", result);
526
598
  }
527
599
  setImmediate(() => {
@@ -808,6 +880,70 @@ function mapSessionSummaryRow(row) {
808
880
  };
809
881
  }
810
882
 
883
+ // src/server/config.ts
884
+ import { z } from "zod";
885
+ var backendSchema = z.enum(["auto", "vllm", "sglang", "ollama", "llamacpp"]).default("auto");
886
+ var envSchema = z.object({
887
+ // New env var name, with fallback to old name for backward compatibility
888
+ OPENFOX_LLM_URL: z.string().url().optional(),
889
+ OPENFOX_VLLM_URL: z.string().url().optional(),
890
+ OPENFOX_BACKEND: backendSchema,
891
+ OPENFOX_MODEL_NAME: z.string().default("qwen3.5-122b-int4-autoround"),
892
+ OPENFOX_MAX_CONTEXT: z.coerce.number().default(2e5),
893
+ OPENFOX_PORT: z.coerce.number().default(10369),
894
+ OPENFOX_HOST: z.string().optional(),
895
+ OPENFOX_WORKDIR: z.string().optional(),
896
+ OPENFOX_DB_PATH: z.string().default("./openfox.db"),
897
+ OPENFOX_LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
898
+ OPENFOX_DISABLE_THINKING: z.coerce.boolean().default(false),
899
+ OPENFOX_DEV: z.coerce.boolean().default(false)
900
+ });
901
+ function loadConfig() {
902
+ const env = envSchema.parse(process.env);
903
+ const llmUrl = env.OPENFOX_LLM_URL ?? env.OPENFOX_VLLM_URL ?? "http://localhost:8000/v1";
904
+ const workdir = env.OPENFOX_WORKDIR ?? process.cwd();
905
+ return {
906
+ llm: {
907
+ baseUrl: llmUrl,
908
+ model: env.OPENFOX_MODEL_NAME,
909
+ timeout: 3e5,
910
+ // 5 minutes (deprecated, kept for backward compatibility)
911
+ idleTimeout: 3e5,
912
+ // 5 minutes of inactivity
913
+ backend: env.OPENFOX_BACKEND,
914
+ disableThinking: env.OPENFOX_DISABLE_THINKING
915
+ },
916
+ context: {
917
+ maxTokens: env.OPENFOX_MAX_CONTEXT,
918
+ compactionThreshold: 0.85,
919
+ compactionTarget: 0.6
920
+ },
921
+ agent: {
922
+ maxIterations: 10,
923
+ maxConsecutiveFailures: 3,
924
+ toolTimeout: 3e5
925
+ },
926
+ server: {
927
+ port: env.OPENFOX_PORT,
928
+ ...env.OPENFOX_HOST !== void 0 ? { host: env.OPENFOX_HOST } : {}
929
+ },
930
+ database: {
931
+ path: env.OPENFOX_DB_PATH
932
+ },
933
+ mode: env.OPENFOX_DEV ? "development" : "production",
934
+ workdir
935
+ };
936
+ }
937
+
938
+ // src/server/runtime-config.ts
939
+ var runtimeConfig = null;
940
+ function setRuntimeConfig(config) {
941
+ runtimeConfig = config;
942
+ }
943
+ function getRuntimeConfig() {
944
+ return runtimeConfig ?? loadConfig();
945
+ }
946
+
811
947
  // src/server/events/session.ts
812
948
  function toSnapshotMessage(message) {
813
949
  return {
@@ -890,6 +1026,10 @@ function getCurrentContextWindowId(sessionId) {
890
1026
  const contextResult = foldContextState(events, "");
891
1027
  return contextResult.currentContextWindowId || void 0;
892
1028
  }
1029
+ function getCurrentWindowMessageOptions(sessionId) {
1030
+ const contextWindowId = getCurrentContextWindowId(sessionId);
1031
+ return contextWindowId ? { contextWindowId } : void 0;
1032
+ }
893
1033
  function getReadFilesCache(sessionId) {
894
1034
  const state = getSessionState(sessionId);
895
1035
  return state?.readFiles ?? [];
@@ -976,7 +1116,6 @@ function emitMessageDone(sessionId, messageId, options) {
976
1116
  ...options?.stats !== void 0 && { stats: options.stats },
977
1117
  ...options?.segments !== void 0 && { segments: options.segments },
978
1118
  ...options?.partial !== void 0 && { partial: options.partial },
979
- ...options?.promptContext !== void 0 && { promptContext: options.promptContext },
980
1119
  ...options?.tokenCount !== void 0 && { tokenCount: options.tokenCount }
981
1120
  }
982
1121
  });
@@ -1115,11 +1254,11 @@ function emitChatError(sessionId, error, recoverable) {
1115
1254
  data: { error, recoverable }
1116
1255
  });
1117
1256
  }
1118
- function emitFormatRetry(sessionId, attempt, maxAttempts) {
1257
+ function emitPatternRetry(sessionId, messageId, pattern, field, attempt, maxAttempts, matchedContent) {
1119
1258
  const eventStore = getEventStore();
1120
1259
  eventStore.append(sessionId, {
1121
- type: "format.retry",
1122
- data: { attempt, maxAttempts }
1260
+ type: "pattern.retry",
1261
+ data: { messageId, pattern, field, attempt, maxAttempts, matchedContent }
1123
1262
  });
1124
1263
  }
1125
1264
  function emitTurnSnapshot(sessionId, snapshot) {
@@ -1245,10 +1384,14 @@ export {
1245
1384
  listSessions,
1246
1385
  listSessionsByProject,
1247
1386
  deleteSession,
1387
+ loadConfig,
1388
+ setRuntimeConfig,
1389
+ getRuntimeConfig,
1248
1390
  getSessionState,
1249
1391
  getCurrentWindowMessages,
1250
1392
  getContextMessages,
1251
1393
  getCurrentContextWindowId,
1394
+ getCurrentWindowMessageOptions,
1252
1395
  getReadFilesCache,
1253
1396
  isFileInCache,
1254
1397
  emitSessionInitialized,
@@ -1273,10 +1416,10 @@ export {
1273
1416
  emitContextState,
1274
1417
  emitChatDone,
1275
1418
  emitChatError,
1276
- emitFormatRetry,
1419
+ emitPatternRetry,
1277
1420
  emitTurnSnapshot,
1278
1421
  truncateSessionMessages,
1279
1422
  compactContext,
1280
1423
  getRecentUserPromptsForSession
1281
1424
  };
1282
- //# sourceMappingURL=chunk-XKR3HCAL.js.map
1425
+ //# sourceMappingURL=chunk-NSBYORD5.js.map
@@ -15,9 +15,9 @@ var SETTINGS_KEYS = {
15
15
  DISPLAY_USER_PRESETS: "display.userPresets",
16
16
  DISPLAY_FOLLOW_SYSTEM_THEME: "display.followSystemTheme",
17
17
  DISPLAY_SHOW_OPEN_IN_EDITOR: "display.showOpenInEditorLinks",
18
- LLM_DISABLE_XML_PROTECTION: "llm.disableXmlProtection",
19
18
  LLM_DYNAMIC_SYSTEM_PROMPT: "llm.dynamicSystemPrompt",
20
- KEYBINDINGS: "keybindings"
19
+ KEYBINDINGS: "keybindings",
20
+ RETRY_PATTERNS: "agent.retryPatterns"
21
21
  };
22
22
  var SETTINGS_DEFAULTS = {
23
23
  [SETTINGS_KEYS.DISPLAY_SHOW_THINKING]: "true",
@@ -29,8 +29,8 @@ var SETTINGS_DEFAULTS = {
29
29
  [SETTINGS_KEYS.DISPLAY_THEME]: JSON.stringify({ preset: "dark" }),
30
30
  [SETTINGS_KEYS.DISPLAY_FOLLOW_SYSTEM_THEME]: "true",
31
31
  [SETTINGS_KEYS.DISPLAY_SHOW_OPEN_IN_EDITOR]: "false",
32
- [SETTINGS_KEYS.LLM_DISABLE_XML_PROTECTION]: "false",
33
32
  [SETTINGS_KEYS.LLM_DYNAMIC_SYSTEM_PROMPT]: "false",
33
+ [SETTINGS_KEYS.RETRY_PATTERNS]: JSON.stringify({ patterns: [], maxRetriesPerTurn: 10 }),
34
34
  [SETTINGS_KEYS.KEYBINDINGS]: JSON.stringify({
35
35
  terminalToggle: { type: "double-press", key: "Control", threshold: 300 },
36
36
  quickAction: { type: "double-press", key: "Shift", threshold: 300 },
@@ -88,4 +88,4 @@ export {
88
88
  deleteSetting,
89
89
  getAllSettings
90
90
  };
91
- //# sourceMappingURL=chunk-PSJIT5LZ.js.map
91
+ //# sourceMappingURL=chunk-RFNEDBVO.js.map
@@ -0,0 +1,13 @@
1
+ // src/server/context/compactor.ts
2
+ function shouldCompact(currentTokens, maxTokens, threshold) {
3
+ return currentTokens > maxTokens * threshold;
4
+ }
5
+ function getCompactionTarget(maxTokens, targetRatio) {
6
+ return Math.floor(maxTokens * targetRatio);
7
+ }
8
+
9
+ export {
10
+ shouldCompact,
11
+ getCompactionTarget
12
+ };
13
+ //# sourceMappingURL=chunk-RI6GAMNP.js.map