omk-agent-core 1.2.0 → 1.2.3

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 (65) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +8 -0
  3. package/dist/agent-loop.d.ts.map +1 -1
  4. package/dist/agent-loop.js +27 -24
  5. package/dist/agent-loop.js.map +1 -1
  6. package/dist/agent-state.d.ts +9 -0
  7. package/dist/agent-state.d.ts.map +1 -0
  8. package/dist/agent-state.js +40 -0
  9. package/dist/agent-state.js.map +1 -0
  10. package/dist/agent.d.ts.map +1 -1
  11. package/dist/agent.js +4 -39
  12. package/dist/agent.js.map +1 -1
  13. package/dist/commit-conflicts.d.ts +4 -0
  14. package/dist/commit-conflicts.d.ts.map +1 -0
  15. package/dist/commit-conflicts.js +43 -0
  16. package/dist/commit-conflicts.js.map +1 -0
  17. package/dist/commit-graph.d.ts +5 -0
  18. package/dist/commit-graph.d.ts.map +1 -0
  19. package/dist/commit-graph.js +93 -0
  20. package/dist/commit-graph.js.map +1 -0
  21. package/dist/commit-input.d.ts +4 -0
  22. package/dist/commit-input.d.ts.map +1 -0
  23. package/dist/commit-input.js +105 -0
  24. package/dist/commit-input.js.map +1 -0
  25. package/dist/commit-planner.d.ts +4 -0
  26. package/dist/commit-planner.d.ts.map +1 -0
  27. package/dist/commit-planner.js +136 -0
  28. package/dist/commit-planner.js.map +1 -0
  29. package/dist/commit-types.d.ts +55 -0
  30. package/dist/commit-types.d.ts.map +1 -0
  31. package/dist/commit-types.js +7 -0
  32. package/dist/commit-types.js.map +1 -0
  33. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  34. package/dist/harness/compaction/compaction.js +0 -11
  35. package/dist/harness/compaction/compaction.js.map +1 -1
  36. package/dist/harness/session/jsonl-labels.d.ts +4 -0
  37. package/dist/harness/session/jsonl-labels.d.ts.map +1 -0
  38. package/dist/harness/session/jsonl-labels.js +16 -0
  39. package/dist/harness/session/jsonl-labels.js.map +1 -0
  40. package/dist/harness/session/jsonl-storage.d.ts.map +1 -1
  41. package/dist/harness/session/jsonl-storage.js +23 -39
  42. package/dist/harness/session/jsonl-storage.js.map +1 -1
  43. package/dist/harness/session/session.d.ts.map +1 -1
  44. package/dist/harness/session/session.js +2 -1
  45. package/dist/harness/session/session.js.map +1 -1
  46. package/dist/index.d.ts +2 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +2 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/tool-dag-deferred.d.ts +17 -0
  51. package/dist/tool-dag-deferred.d.ts.map +1 -0
  52. package/dist/tool-dag-deferred.js +17 -0
  53. package/dist/tool-dag-deferred.js.map +1 -0
  54. package/dist/tool-dag-ecraf-exchange.d.ts +13 -0
  55. package/dist/tool-dag-ecraf-exchange.d.ts.map +1 -0
  56. package/dist/tool-dag-ecraf-exchange.js +68 -0
  57. package/dist/tool-dag-ecraf-exchange.js.map +1 -0
  58. package/dist/tool-dag-memo.d.ts +1 -1
  59. package/dist/tool-dag-memo.d.ts.map +1 -1
  60. package/dist/tool-dag-memo.js +3 -1
  61. package/dist/tool-dag-memo.js.map +1 -1
  62. package/dist/tool-dag-scheduler.d.ts.map +1 -1
  63. package/dist/tool-dag-scheduler.js +3 -0
  64. package/dist/tool-dag-scheduler.js.map +1 -1
  65. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,KAAK,EASX,cAAc,EAEd,eAAe,EACf,cAAc,EACd,gBAAgB,EAEhB,MAAM,aAAa,CAAC;AAGrB,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,gBAAgB,EAAE,GAAG,cAAc,CA0DnF;AAED,qBAAa,OAAO,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe;IACvE,OAAO,CAAC,OAAO,CAA4B;IAE3C,YAAY,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,EAE7C;IAED,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAEhC;IAED,UAAU,IAAI,cAAc,CAAC,SAAS,CAAC,CAEtC;IAED,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAElC;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAE1D;IAED,UAAU,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAExC;IAEK,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAG5D;IAEK,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAE5C;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAEhD;IAEK,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAGlD;YAEa,gBAAgB;IAKxB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ1D;IAEK,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQtE;IAEK,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS1E;IAEK,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxE;IAEK,gBAAgB,CAAC,CAAC,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,CAAC,EACX,QAAQ,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,MAAM,CAAC,CAYjB;IAEK,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAS3E;IAEK,wBAAwB,CAAC,CAAC,GAAG,OAAO,EACzC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,EAChD,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,CAAC,GACT,OAAO,CAAC,MAAM,CAAC,CAWjB;IAEK,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAY9E;IAEK,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQrD;IAEK,MAAM,CACX,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAClE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB7B;CACD","sourcesContent":["import type { ImageContent, TextContent } from \"omk-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from \"../messages.ts\";\nimport type {\n\tActiveToolsChangeEntry,\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tLabelEntry,\n\tMessageEntry,\n\tModelChangeEntry,\n\tSessionContext,\n\tSessionInfoEntry,\n\tSessionMetadata,\n\tSessionStorage,\n\tSessionTreeEntry,\n\tThinkingLevelChangeEntry,\n} from \"../types.ts\";\nimport { SessionError } from \"../types.ts\";\n\nexport function buildSessionContext(pathEntries: SessionTreeEntry[]): SessionContext {\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\tlet activeToolNames: string[] | null = null;\n\tlet compaction: CompactionEntry | null = null;\n\n\tfor (const entry of pathEntries) {\n\t\tif (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tmodel = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t} else if (entry.type === \"active_tools_change\") {\n\t\t\tactiveToolNames = [...entry.activeToolNames];\n\t\t} else if (entry.type === \"compaction\") {\n\t\t\tcompaction = entry;\n\t\t}\n\t}\n\n\tconst messages: AgentMessage[] = [];\n\tconst appendMessage = (entry: SessionTreeEntry) => {\n\t\tif (entry.type === \"message\") {\n\t\t\tmessages.push(entry.message as AgentMessage);\n\t\t} else if (entry.type === \"custom_message\") {\n\t\t\tmessages.push(\n\t\t\t\tcreateCustomMessage(\n\t\t\t\t\tentry.customType,\n\t\t\t\t\tentry.content as string | (TextContent | ImageContent)[],\n\t\t\t\t\tentry.display,\n\t\t\t\t\tentry.details,\n\t\t\t\t\tentry.timestamp,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (entry.type === \"branch_summary\" && entry.summary) {\n\t\t\tmessages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));\n\t\t}\n\t};\n\n\tif (compaction) {\n\t\tmessages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));\n\t\tconst compactionIdx = pathEntries.findIndex((e) => e.type === \"compaction\" && e.id === compaction.id);\n\t\tlet foundFirstKept = false;\n\t\tfor (let i = 0; i < compactionIdx; i++) {\n\t\t\tconst entry = pathEntries[i]!;\n\t\t\tif (entry.id === compaction.firstKeptEntryId) foundFirstKept = true;\n\t\t\tif (foundFirstKept) appendMessage(entry);\n\t\t}\n\t\tfor (let i = compactionIdx + 1; i < pathEntries.length; i++) {\n\t\t\tappendMessage(pathEntries[i]!);\n\t\t}\n\t} else {\n\t\tfor (const entry of pathEntries) {\n\t\t\tappendMessage(entry);\n\t\t}\n\t}\n\n\treturn { messages, thinkingLevel, model, activeToolNames };\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> {\n\tprivate storage: SessionStorage<TMetadata>;\n\n\tconstructor(storage: SessionStorage<TMetadata>) {\n\t\tthis.storage = storage;\n\t}\n\n\tgetMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tgetStorage(): SessionStorage<TMetadata> {\n\t\treturn this.storage;\n\t}\n\n\tgetLeafId(): Promise<string | null> {\n\t\treturn this.storage.getLeafId();\n\t}\n\n\tgetEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tgetEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn this.storage.getEntries();\n\t}\n\n\tasync getBranch(fromId?: string): Promise<SessionTreeEntry[]> {\n\t\tconst leafId = fromId ?? (await this.storage.getLeafId());\n\t\treturn this.storage.getPathToRoot(leafId);\n\t}\n\n\tasync buildContext(): Promise<SessionContext> {\n\t\treturn buildSessionContext(await this.getBranch());\n\t}\n\n\tgetLabel(id: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(id);\n\t}\n\n\tasync getSessionName(): Promise<string | undefined> {\n\t\tconst entries = await this.storage.findEntries(\"session_info\");\n\t\treturn entries[entries.length - 1]?.name?.trim() || undefined;\n\t}\n\n\tprivate async appendTypedEntry<TEntry extends SessionTreeEntry>(entry: TEntry): Promise<string> {\n\t\tawait this.storage.appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t} satisfies MessageEntry);\n\t}\n\n\tasync appendThinkingLevelChange(thinkingLevel: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t} satisfies ThinkingLevelChangeEntry);\n\t}\n\n\tasync appendModelChange(provider: string, modelId: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"model_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t} satisfies ModelChangeEntry);\n\t}\n\n\tasync appendActiveToolsChange(activeToolNames: string[]): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"active_tools_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tactiveToolNames: [...activeToolNames],\n\t\t} satisfies ActiveToolsChangeEntry);\n\t}\n\n\tasync appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"compaction\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t} satisfies CompactionEntry<T>);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t} satisfies CustomEntry);\n\t}\n\n\tasync appendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom_message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t} satisfies CustomMessageEntry<T>);\n\t}\n\n\tasync appendLabel(targetId: string, label: string | undefined): Promise<string> {\n\t\tif (!(await this.storage.getEntry(targetId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${targetId} not found`);\n\t\t}\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"label\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t} satisfies LabelEntry);\n\t}\n\n\tasync appendSessionName(name: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"session_info\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: name.trim(),\n\t\t} satisfies SessionInfoEntry);\n\t}\n\n\tasync moveTo(\n\t\tentryId: string | null,\n\t\tsummary?: { summary: string; details?: unknown; fromHook?: boolean },\n\t): Promise<string | undefined> {\n\t\tif (entryId !== null && !(await this.storage.getEntry(entryId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${entryId} not found`);\n\t\t}\n\t\tawait this.storage.setLeafId(entryId);\n\t\tif (!summary) return undefined;\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: entryId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: entryId ?? \"root\",\n\t\t\tsummary: summary.summary,\n\t\t\tdetails: summary.details,\n\t\t\tfromHook: summary.fromHook,\n\t\t} satisfies BranchSummaryEntry);\n\t}\n}\n"]}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,KAAK,EASX,cAAc,EAEd,eAAe,EACf,cAAc,EACd,gBAAgB,EAEhB,MAAM,aAAa,CAAC;AAGrB,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,gBAAgB,EAAE,GAAG,cAAc,CA0DnF;AAED,qBAAa,OAAO,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe;IACvE,OAAO,CAAC,OAAO,CAA4B;IAE3C,YAAY,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,EAE7C;IAED,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAEhC;IAED,UAAU,IAAI,cAAc,CAAC,SAAS,CAAC,CAEtC;IAED,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAElC;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAE1D;IAED,UAAU,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAExC;IAEK,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAG5D;IAEK,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAE5C;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAEhD;IAEK,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAGlD;YAEa,gBAAgB;IAKxB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ1D;IAEK,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQtE;IAEK,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS1E;IAEK,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxE;IAEK,gBAAgB,CAAC,CAAC,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,CAAC,EACX,QAAQ,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,MAAM,CAAC,CAYjB;IAEK,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAS3E;IAEK,wBAAwB,CAAC,CAAC,GAAG,OAAO,EACzC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,EAChD,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,CAAC,GACT,OAAO,CAAC,MAAM,CAAC,CAWjB;IAEK,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAY9E;IAEK,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASrD;IAEK,MAAM,CACX,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAClE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB7B;CACD","sourcesContent":["import type { ImageContent, TextContent } from \"omk-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from \"../messages.ts\";\nimport type {\n\tActiveToolsChangeEntry,\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tLabelEntry,\n\tMessageEntry,\n\tModelChangeEntry,\n\tSessionContext,\n\tSessionInfoEntry,\n\tSessionMetadata,\n\tSessionStorage,\n\tSessionTreeEntry,\n\tThinkingLevelChangeEntry,\n} from \"../types.ts\";\nimport { SessionError } from \"../types.ts\";\n\nexport function buildSessionContext(pathEntries: SessionTreeEntry[]): SessionContext {\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\tlet activeToolNames: string[] | null = null;\n\tlet compaction: CompactionEntry | null = null;\n\n\tfor (const entry of pathEntries) {\n\t\tif (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tmodel = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t} else if (entry.type === \"active_tools_change\") {\n\t\t\tactiveToolNames = [...entry.activeToolNames];\n\t\t} else if (entry.type === \"compaction\") {\n\t\t\tcompaction = entry;\n\t\t}\n\t}\n\n\tconst messages: AgentMessage[] = [];\n\tconst appendMessage = (entry: SessionTreeEntry) => {\n\t\tif (entry.type === \"message\") {\n\t\t\tmessages.push(entry.message as AgentMessage);\n\t\t} else if (entry.type === \"custom_message\") {\n\t\t\tmessages.push(\n\t\t\t\tcreateCustomMessage(\n\t\t\t\t\tentry.customType,\n\t\t\t\t\tentry.content as string | (TextContent | ImageContent)[],\n\t\t\t\t\tentry.display,\n\t\t\t\t\tentry.details,\n\t\t\t\t\tentry.timestamp,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (entry.type === \"branch_summary\" && entry.summary) {\n\t\t\tmessages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));\n\t\t}\n\t};\n\n\tif (compaction) {\n\t\tmessages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));\n\t\tconst compactionIdx = pathEntries.findIndex((e) => e.type === \"compaction\" && e.id === compaction.id);\n\t\tlet foundFirstKept = false;\n\t\tfor (let i = 0; i < compactionIdx; i++) {\n\t\t\tconst entry = pathEntries[i]!;\n\t\t\tif (entry.id === compaction.firstKeptEntryId) foundFirstKept = true;\n\t\t\tif (foundFirstKept) appendMessage(entry);\n\t\t}\n\t\tfor (let i = compactionIdx + 1; i < pathEntries.length; i++) {\n\t\t\tappendMessage(pathEntries[i]!);\n\t\t}\n\t} else {\n\t\tfor (const entry of pathEntries) {\n\t\t\tappendMessage(entry);\n\t\t}\n\t}\n\n\treturn { messages, thinkingLevel, model, activeToolNames };\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> {\n\tprivate storage: SessionStorage<TMetadata>;\n\n\tconstructor(storage: SessionStorage<TMetadata>) {\n\t\tthis.storage = storage;\n\t}\n\n\tgetMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tgetStorage(): SessionStorage<TMetadata> {\n\t\treturn this.storage;\n\t}\n\n\tgetLeafId(): Promise<string | null> {\n\t\treturn this.storage.getLeafId();\n\t}\n\n\tgetEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tgetEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn this.storage.getEntries();\n\t}\n\n\tasync getBranch(fromId?: string): Promise<SessionTreeEntry[]> {\n\t\tconst leafId = fromId ?? (await this.storage.getLeafId());\n\t\treturn this.storage.getPathToRoot(leafId);\n\t}\n\n\tasync buildContext(): Promise<SessionContext> {\n\t\treturn buildSessionContext(await this.getBranch());\n\t}\n\n\tgetLabel(id: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(id);\n\t}\n\n\tasync getSessionName(): Promise<string | undefined> {\n\t\tconst entries = await this.storage.findEntries(\"session_info\");\n\t\treturn entries[entries.length - 1]?.name?.trim() || undefined;\n\t}\n\n\tprivate async appendTypedEntry<TEntry extends SessionTreeEntry>(entry: TEntry): Promise<string> {\n\t\tawait this.storage.appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t} satisfies MessageEntry);\n\t}\n\n\tasync appendThinkingLevelChange(thinkingLevel: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t} satisfies ThinkingLevelChangeEntry);\n\t}\n\n\tasync appendModelChange(provider: string, modelId: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"model_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t} satisfies ModelChangeEntry);\n\t}\n\n\tasync appendActiveToolsChange(activeToolNames: string[]): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"active_tools_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tactiveToolNames: [...activeToolNames],\n\t\t} satisfies ActiveToolsChangeEntry);\n\t}\n\n\tasync appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"compaction\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t} satisfies CompactionEntry<T>);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t} satisfies CustomEntry);\n\t}\n\n\tasync appendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom_message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t} satisfies CustomMessageEntry<T>);\n\t}\n\n\tasync appendLabel(targetId: string, label: string | undefined): Promise<string> {\n\t\tif (!(await this.storage.getEntry(targetId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${targetId} not found`);\n\t\t}\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"label\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t} satisfies LabelEntry);\n\t}\n\n\tasync appendSessionName(name: string): Promise<string> {\n\t\tconst sanitizedName = name.replace(/[\\r\\n]+/g, \" \").trim();\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"session_info\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: sanitizedName,\n\t\t} satisfies SessionInfoEntry);\n\t}\n\n\tasync moveTo(\n\t\tentryId: string | null,\n\t\tsummary?: { summary: string; details?: unknown; fromHook?: boolean },\n\t): Promise<string | undefined> {\n\t\tif (entryId !== null && !(await this.storage.getEntry(entryId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${entryId} not found`);\n\t\t}\n\t\tawait this.storage.setLeafId(entryId);\n\t\tif (!summary) return undefined;\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: entryId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: entryId ?? \"root\",\n\t\t\tsummary: summary.summary,\n\t\t\tdetails: summary.details,\n\t\t\tfromHook: summary.fromHook,\n\t\t} satisfies BranchSummaryEntry);\n\t}\n}\n"]}
@@ -180,12 +180,13 @@ export class Session {
180
180
  });
181
181
  }
182
182
  async appendSessionName(name) {
183
+ const sanitizedName = name.replace(/[\r\n]+/g, " ").trim();
183
184
  return this.appendTypedEntry({
184
185
  type: "session_info",
185
186
  id: await this.storage.createEntryId(),
186
187
  parentId: await this.storage.getLeafId(),
187
188
  timestamp: new Date().toISOString(),
188
- name: name.trim(),
189
+ name: sanitizedName,
189
190
  });
190
191
  }
191
192
  async moveTo(entryId, summary) {
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,8BAA8B,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAiBjH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,UAAU,mBAAmB,CAAC,WAA+B,EAAkB;IACpF,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,KAAK,GAAiD,IAAI,CAAC;IAC/D,IAAI,eAAe,GAAoB,IAAI,CAAC;IAC5C,IAAI,UAAU,GAA2B,IAAI,CAAC;IAE9C,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;YAC5C,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;QACrC,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC1C,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAC9D,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC3E,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC5E,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACjD,eAAe,GAAG,CAAC,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACxC,UAAU,GAAG,KAAK,CAAC;QACpB,CAAC;IACF,CAAC;IAED,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,MAAM,aAAa,GAAG,CAAC,KAAuB,EAAE,EAAE,CAAC;QAClD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAuB,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAC5C,QAAQ,CAAC,IAAI,CACZ,mBAAmB,CAClB,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,OAAkD,EACxD,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,SAAS,CACf,CACD,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAC7D,QAAQ,CAAC,IAAI,CAAC,0BAA0B,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QACzF,CAAC;IAAA,CACD,CAAC;IAEF,IAAI,UAAU,EAAE,CAAC;QAChB,QAAQ,CAAC,IAAI,CAAC,8BAA8B,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,YAAY,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QACjH,MAAM,aAAa,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,EAAE,CAAC,CAAC;QACtG,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,EAAE,KAAK,UAAU,CAAC,gBAAgB;gBAAE,cAAc,GAAG,IAAI,CAAC;YACpE,IAAI,cAAc;gBAAE,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,aAAa,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7D,aAAa,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,CAAC;QAChC,CAAC;IACF,CAAC;SAAM,CAAC;QACP,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YACjC,aAAa,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;AAAA,CAC3D;AAED,MAAM,OAAO,OAAO;IACX,OAAO,CAA4B;IAE3C,YAAY,OAAkC,EAAE;QAC/C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAAA,CACvB;IAED,WAAW,GAAuB;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAAA,CAClC;IAED,UAAU,GAA8B;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC;IAAA,CACpB;IAED,SAAS,GAA2B;QACnC,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAAA,CAChC;IAED,QAAQ,CAAC,EAAU,EAAyC;QAC3D,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAAA,CACjC;IAED,UAAU,GAAgC;QACzC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;IAAA,CACjC;IAED,KAAK,CAAC,SAAS,CAAC,MAAe,EAA+B;QAC7D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAAA,CAC1C;IAED,KAAK,CAAC,YAAY,GAA4B;QAC7C,OAAO,mBAAmB,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAAA,CACnD;IAED,QAAQ,CAAC,EAAU,EAA+B;QACjD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAAA,CACjC;IAED,KAAK,CAAC,cAAc,GAAgC;QACnD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QAC/D,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAAA,CAC9D;IAEO,KAAK,CAAC,gBAAgB,CAAkC,KAAa,EAAmB;QAC/F,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACtC,OAAO,KAAK,CAAC,EAAE,CAAC;IAAA,CAChB;IAED,KAAK,CAAC,aAAa,CAAC,OAAqB,EAAmB;QAC3D,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,SAAS;YACf,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO;SACgB,CAAC,CAAC;IAAA,CAC1B;IAED,KAAK,CAAC,yBAAyB,CAAC,aAAqB,EAAmB;QACvE,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,uBAAuB;YAC7B,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,aAAa;SACsB,CAAC,CAAC;IAAA,CACtC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,OAAe,EAAmB;QAC3E,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ;YACR,OAAO;SACoB,CAAC,CAAC;IAAA,CAC9B;IAED,KAAK,CAAC,uBAAuB,CAAC,eAAyB,EAAmB;QACzE,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,qBAAqB;YAC3B,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,eAAe,EAAE,CAAC,GAAG,eAAe,CAAC;SACJ,CAAC,CAAC;IAAA,CACpC;IAED,KAAK,CAAC,gBAAgB,CACrB,OAAe,EACf,gBAAwB,EACxB,YAAoB,EACpB,OAAW,EACX,QAAkB,EACA;QAClB,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,YAAY;YAClB,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO;YACP,gBAAgB;YAChB,YAAY;YACZ,OAAO;YACP,QAAQ;SACqB,CAAC,CAAC;IAAA,CAChC;IAED,KAAK,CAAC,iBAAiB,CAAC,UAAkB,EAAE,IAAc,EAAmB;QAC5E,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,QAAQ;YACd,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,UAAU;YACV,IAAI;SACkB,CAAC,CAAC;IAAA,CACzB;IAED,KAAK,CAAC,wBAAwB,CAC7B,UAAkB,EAClB,OAAgD,EAChD,OAAgB,EAChB,OAAW,EACO;QAClB,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,gBAAgB;YACtB,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,UAAU;YACV,OAAO;YACP,OAAO;YACP,OAAO;SACyB,CAAC,CAAC;IAAA,CACnC;IAED,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,KAAyB,EAAmB;QAC/E,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,SAAS,QAAQ,YAAY,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,OAAO;YACb,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ;YACR,KAAK;SACgB,CAAC,CAAC;IAAA,CACxB;IAED,KAAK,CAAC,iBAAiB,CAAC,IAAY,EAAmB;QACtD,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;SACU,CAAC,CAAC;IAAA,CAC9B;IAED,KAAK,CAAC,MAAM,CACX,OAAsB,EACtB,OAAoE,EACtC;QAC9B,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,SAAS,OAAO,YAAY,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC5B,IAAI,EAAE,gBAAgB;YACtB,EAAE,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;YACtC,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,OAAO,IAAI,MAAM;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SACG,CAAC,CAAC;IAAA,CAChC;CACD","sourcesContent":["import type { ImageContent, TextContent } from \"omk-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from \"../messages.ts\";\nimport type {\n\tActiveToolsChangeEntry,\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tLabelEntry,\n\tMessageEntry,\n\tModelChangeEntry,\n\tSessionContext,\n\tSessionInfoEntry,\n\tSessionMetadata,\n\tSessionStorage,\n\tSessionTreeEntry,\n\tThinkingLevelChangeEntry,\n} from \"../types.ts\";\nimport { SessionError } from \"../types.ts\";\n\nexport function buildSessionContext(pathEntries: SessionTreeEntry[]): SessionContext {\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\tlet activeToolNames: string[] | null = null;\n\tlet compaction: CompactionEntry | null = null;\n\n\tfor (const entry of pathEntries) {\n\t\tif (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tmodel = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t} else if (entry.type === \"active_tools_change\") {\n\t\t\tactiveToolNames = [...entry.activeToolNames];\n\t\t} else if (entry.type === \"compaction\") {\n\t\t\tcompaction = entry;\n\t\t}\n\t}\n\n\tconst messages: AgentMessage[] = [];\n\tconst appendMessage = (entry: SessionTreeEntry) => {\n\t\tif (entry.type === \"message\") {\n\t\t\tmessages.push(entry.message as AgentMessage);\n\t\t} else if (entry.type === \"custom_message\") {\n\t\t\tmessages.push(\n\t\t\t\tcreateCustomMessage(\n\t\t\t\t\tentry.customType,\n\t\t\t\t\tentry.content as string | (TextContent | ImageContent)[],\n\t\t\t\t\tentry.display,\n\t\t\t\t\tentry.details,\n\t\t\t\t\tentry.timestamp,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (entry.type === \"branch_summary\" && entry.summary) {\n\t\t\tmessages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));\n\t\t}\n\t};\n\n\tif (compaction) {\n\t\tmessages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));\n\t\tconst compactionIdx = pathEntries.findIndex((e) => e.type === \"compaction\" && e.id === compaction.id);\n\t\tlet foundFirstKept = false;\n\t\tfor (let i = 0; i < compactionIdx; i++) {\n\t\t\tconst entry = pathEntries[i]!;\n\t\t\tif (entry.id === compaction.firstKeptEntryId) foundFirstKept = true;\n\t\t\tif (foundFirstKept) appendMessage(entry);\n\t\t}\n\t\tfor (let i = compactionIdx + 1; i < pathEntries.length; i++) {\n\t\t\tappendMessage(pathEntries[i]!);\n\t\t}\n\t} else {\n\t\tfor (const entry of pathEntries) {\n\t\t\tappendMessage(entry);\n\t\t}\n\t}\n\n\treturn { messages, thinkingLevel, model, activeToolNames };\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> {\n\tprivate storage: SessionStorage<TMetadata>;\n\n\tconstructor(storage: SessionStorage<TMetadata>) {\n\t\tthis.storage = storage;\n\t}\n\n\tgetMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tgetStorage(): SessionStorage<TMetadata> {\n\t\treturn this.storage;\n\t}\n\n\tgetLeafId(): Promise<string | null> {\n\t\treturn this.storage.getLeafId();\n\t}\n\n\tgetEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tgetEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn this.storage.getEntries();\n\t}\n\n\tasync getBranch(fromId?: string): Promise<SessionTreeEntry[]> {\n\t\tconst leafId = fromId ?? (await this.storage.getLeafId());\n\t\treturn this.storage.getPathToRoot(leafId);\n\t}\n\n\tasync buildContext(): Promise<SessionContext> {\n\t\treturn buildSessionContext(await this.getBranch());\n\t}\n\n\tgetLabel(id: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(id);\n\t}\n\n\tasync getSessionName(): Promise<string | undefined> {\n\t\tconst entries = await this.storage.findEntries(\"session_info\");\n\t\treturn entries[entries.length - 1]?.name?.trim() || undefined;\n\t}\n\n\tprivate async appendTypedEntry<TEntry extends SessionTreeEntry>(entry: TEntry): Promise<string> {\n\t\tawait this.storage.appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t} satisfies MessageEntry);\n\t}\n\n\tasync appendThinkingLevelChange(thinkingLevel: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t} satisfies ThinkingLevelChangeEntry);\n\t}\n\n\tasync appendModelChange(provider: string, modelId: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"model_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t} satisfies ModelChangeEntry);\n\t}\n\n\tasync appendActiveToolsChange(activeToolNames: string[]): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"active_tools_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tactiveToolNames: [...activeToolNames],\n\t\t} satisfies ActiveToolsChangeEntry);\n\t}\n\n\tasync appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"compaction\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t} satisfies CompactionEntry<T>);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t} satisfies CustomEntry);\n\t}\n\n\tasync appendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom_message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t} satisfies CustomMessageEntry<T>);\n\t}\n\n\tasync appendLabel(targetId: string, label: string | undefined): Promise<string> {\n\t\tif (!(await this.storage.getEntry(targetId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${targetId} not found`);\n\t\t}\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"label\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t} satisfies LabelEntry);\n\t}\n\n\tasync appendSessionName(name: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"session_info\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: name.trim(),\n\t\t} satisfies SessionInfoEntry);\n\t}\n\n\tasync moveTo(\n\t\tentryId: string | null,\n\t\tsummary?: { summary: string; details?: unknown; fromHook?: boolean },\n\t): Promise<string | undefined> {\n\t\tif (entryId !== null && !(await this.storage.getEntry(entryId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${entryId} not found`);\n\t\t}\n\t\tawait this.storage.setLeafId(entryId);\n\t\tif (!summary) return undefined;\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: entryId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: entryId ?? \"root\",\n\t\t\tsummary: summary.summary,\n\t\t\tdetails: summary.details,\n\t\t\tfromHook: summary.fromHook,\n\t\t} satisfies BranchSummaryEntry);\n\t}\n}\n"]}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, TextContent } from \"omk-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from \"../messages.ts\";\nimport type {\n\tActiveToolsChangeEntry,\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tLabelEntry,\n\tMessageEntry,\n\tModelChangeEntry,\n\tSessionContext,\n\tSessionInfoEntry,\n\tSessionMetadata,\n\tSessionStorage,\n\tSessionTreeEntry,\n\tThinkingLevelChangeEntry,\n} from \"../types.ts\";\nimport { SessionError } from \"../types.ts\";\n\nexport function buildSessionContext(pathEntries: SessionTreeEntry[]): SessionContext {\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\tlet activeToolNames: string[] | null = null;\n\tlet compaction: CompactionEntry | null = null;\n\n\tfor (const entry of pathEntries) {\n\t\tif (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tmodel = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t} else if (entry.type === \"active_tools_change\") {\n\t\t\tactiveToolNames = [...entry.activeToolNames];\n\t\t} else if (entry.type === \"compaction\") {\n\t\t\tcompaction = entry;\n\t\t}\n\t}\n\n\tconst messages: AgentMessage[] = [];\n\tconst appendMessage = (entry: SessionTreeEntry) => {\n\t\tif (entry.type === \"message\") {\n\t\t\tmessages.push(entry.message as AgentMessage);\n\t\t} else if (entry.type === \"custom_message\") {\n\t\t\tmessages.push(\n\t\t\t\tcreateCustomMessage(\n\t\t\t\t\tentry.customType,\n\t\t\t\t\tentry.content as string | (TextContent | ImageContent)[],\n\t\t\t\t\tentry.display,\n\t\t\t\t\tentry.details,\n\t\t\t\t\tentry.timestamp,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (entry.type === \"branch_summary\" && entry.summary) {\n\t\t\tmessages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));\n\t\t}\n\t};\n\n\tif (compaction) {\n\t\tmessages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));\n\t\tconst compactionIdx = pathEntries.findIndex((e) => e.type === \"compaction\" && e.id === compaction.id);\n\t\tlet foundFirstKept = false;\n\t\tfor (let i = 0; i < compactionIdx; i++) {\n\t\t\tconst entry = pathEntries[i]!;\n\t\t\tif (entry.id === compaction.firstKeptEntryId) foundFirstKept = true;\n\t\t\tif (foundFirstKept) appendMessage(entry);\n\t\t}\n\t\tfor (let i = compactionIdx + 1; i < pathEntries.length; i++) {\n\t\t\tappendMessage(pathEntries[i]!);\n\t\t}\n\t} else {\n\t\tfor (const entry of pathEntries) {\n\t\t\tappendMessage(entry);\n\t\t}\n\t}\n\n\treturn { messages, thinkingLevel, model, activeToolNames };\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> {\n\tprivate storage: SessionStorage<TMetadata>;\n\n\tconstructor(storage: SessionStorage<TMetadata>) {\n\t\tthis.storage = storage;\n\t}\n\n\tgetMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tgetStorage(): SessionStorage<TMetadata> {\n\t\treturn this.storage;\n\t}\n\n\tgetLeafId(): Promise<string | null> {\n\t\treturn this.storage.getLeafId();\n\t}\n\n\tgetEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tgetEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn this.storage.getEntries();\n\t}\n\n\tasync getBranch(fromId?: string): Promise<SessionTreeEntry[]> {\n\t\tconst leafId = fromId ?? (await this.storage.getLeafId());\n\t\treturn this.storage.getPathToRoot(leafId);\n\t}\n\n\tasync buildContext(): Promise<SessionContext> {\n\t\treturn buildSessionContext(await this.getBranch());\n\t}\n\n\tgetLabel(id: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(id);\n\t}\n\n\tasync getSessionName(): Promise<string | undefined> {\n\t\tconst entries = await this.storage.findEntries(\"session_info\");\n\t\treturn entries[entries.length - 1]?.name?.trim() || undefined;\n\t}\n\n\tprivate async appendTypedEntry<TEntry extends SessionTreeEntry>(entry: TEntry): Promise<string> {\n\t\tawait this.storage.appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t} satisfies MessageEntry);\n\t}\n\n\tasync appendThinkingLevelChange(thinkingLevel: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t} satisfies ThinkingLevelChangeEntry);\n\t}\n\n\tasync appendModelChange(provider: string, modelId: string): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"model_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t} satisfies ModelChangeEntry);\n\t}\n\n\tasync appendActiveToolsChange(activeToolNames: string[]): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"active_tools_change\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tactiveToolNames: [...activeToolNames],\n\t\t} satisfies ActiveToolsChangeEntry);\n\t}\n\n\tasync appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"compaction\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t} satisfies CompactionEntry<T>);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t} satisfies CustomEntry);\n\t}\n\n\tasync appendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): Promise<string> {\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"custom_message\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t} satisfies CustomMessageEntry<T>);\n\t}\n\n\tasync appendLabel(targetId: string, label: string | undefined): Promise<string> {\n\t\tif (!(await this.storage.getEntry(targetId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${targetId} not found`);\n\t\t}\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"label\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t} satisfies LabelEntry);\n\t}\n\n\tasync appendSessionName(name: string): Promise<string> {\n\t\tconst sanitizedName = name.replace(/[\\r\\n]+/g, \" \").trim();\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"session_info\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: await this.storage.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: sanitizedName,\n\t\t} satisfies SessionInfoEntry);\n\t}\n\n\tasync moveTo(\n\t\tentryId: string | null,\n\t\tsummary?: { summary: string; details?: unknown; fromHook?: boolean },\n\t): Promise<string | undefined> {\n\t\tif (entryId !== null && !(await this.storage.getEntry(entryId))) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${entryId} not found`);\n\t\t}\n\t\tawait this.storage.setLeafId(entryId);\n\t\tif (!summary) return undefined;\n\t\treturn this.appendTypedEntry({\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: await this.storage.createEntryId(),\n\t\t\tparentId: entryId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: entryId ?? \"root\",\n\t\t\tsummary: summary.summary,\n\t\t\tdetails: summary.details,\n\t\t\tfromHook: summary.fromHook,\n\t\t} satisfies BranchSummaryEntry);\n\t}\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from "./agent.ts";
2
2
  export * from "./agent-loop.ts";
3
+ export { planAtomicCommits } from "./commit-planner.ts";
4
+ export type { ChangeAtom, ChangeRelation, CommitGroup, CommitPlan, CommitPlannerInput } from "./commit-types.ts";
3
5
  export * from "./harness/abort-delivery.ts";
4
6
  export * from "./harness/agent-harness.ts";
5
7
  export { type BranchPreparation, type BranchSummaryDetails, type CollectEntriesResult, collectEntriesForBranchSummary, generateBranchSummary, prepareBranchEntries, } from "./harness/compaction/branch-summarization.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAE3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,8BAA8B,EAC9B,qBAAqB,EACrB,oBAAoB,GACpB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACN,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACb,MAAM,oCAAoC,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAE3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAE5C,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,YAAY,EACZ,0BAA0B,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,KAAK,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEtF,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AAExC,OAAO,EACN,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,iBAAiB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACN,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,KAAK,wBAAwB,EAC7B,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACtB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,GAC9B,MAAM,gCAAgC,CAAC;AAExC,cAAc,YAAY,CAAC","sourcesContent":["// Core Agent\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\nexport * from \"./harness/abort-delivery.ts\";\nexport * from \"./harness/agent-harness.ts\";\nexport {\n\ttype BranchPreparation,\n\ttype BranchSummaryDetails,\n\ttype CollectEntriesResult,\n\tcollectEntriesForBranchSummary,\n\tgenerateBranchSummary,\n\tprepareBranchEntries,\n} from \"./harness/compaction/branch-summarization.ts\";\nexport {\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgetLastAssistantUsage,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./harness/compaction/compaction.ts\";\nexport * from \"./harness/deferred-commands.ts\";\nexport * from \"./harness/messages.ts\";\nexport * from \"./harness/prompt-templates.ts\";\nexport * from \"./harness/reverse-skill.ts\";\nexport * from \"./harness/session/jsonl-repo.ts\";\nexport * from \"./harness/session/memory-repo.ts\";\nexport * from \"./harness/session/repo-utils.ts\";\nexport * from \"./harness/session/session.ts\";\nexport { uuidv7 } from \"./harness/session/uuid.ts\";\nexport * from \"./harness/skills.ts\";\nexport * from \"./harness/system-prompt.ts\";\n// Harness\nexport * from \"./harness/types.ts\";\nexport * from \"./harness/utils/shell-output.ts\";\nexport * from \"./harness/utils/truncate.ts\";\n// Parallel tool batch policy\nexport {\n\tNEVER_PARALLEL_TOOLS,\n\tPARALLEL_SAFE_TOOLS,\n\tPATH_SCOPED_TOOLS,\n\tpartitionToolBatchWaves,\n\tpathsOverlap,\n\tshouldParallelizeToolBatch,\n} from \"./parallel-tool-batch.ts\";\nexport { type ProviderInputProjection, projectToolImagesForModel } from \"./provider-input.ts\";\nexport { applyModelContract, type ProviderRequestEvent } from \"./provider-request.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\nexport * from \"./run-model-contract.ts\";\n// Deterministic resource-claim DAG scheduler (dag-v2)\nexport {\n\tapplyConcurrencyCap,\n\tassignDagLevels,\n\tcomputePlanKey,\n\ttype DagSchedulePlan,\n\ttype ResolvedClaimEntry,\n\tresolveBatchClaims,\n\ttype ScheduleDagLevelsOptions,\n\tscheduleDagLevels,\n} from \"./tool-dag-scheduler.ts\";\n// Resource-claim model (dag-v2)\nexport {\n\ttype ClaimableToolCall,\n\tcanonicalizeClaims,\n\tclaimsConflict,\n\tcompareClaims,\n\ttype ResolveToolClaimsOptions,\n\tresolutionsConflict,\n\tresolvePathClaimKey,\n\tresolveToolClaims,\n\ttype ToolClaimResolution,\n\ttype ToolResourceAccess,\n\ttype ToolResourceClaim,\n} from \"./tool-resource-claims.ts\";\n// Per-call timeout / cancellation / late settlement (ALG-004)\nexport {\n\tcreateAbortedToolResult,\n\tcreateTimeoutToolResult,\n\tresolveToolExecutionPolicy,\n\tresolveToolTimeoutMs,\n\ttype ToolDispositionEnvelope,\n\ttype ToolLateSettlement,\n} from \"./tool-timeout.ts\";\nexport {\n\tcreateSyntheticToolResult,\n\tinspectTranscriptIntegrity,\n\trepairTranscriptIntegrity,\n\tTranscriptIntegrityError,\n\ttype TranscriptIntegrityIssue,\n\ttype TranscriptIntegrityIssueKind,\n\ttype TranscriptIntegrityReport,\n} from \"./tool-transcript-integrity.ts\";\n// Types\nexport * from \"./types.ts\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAE3B,cAAc,iBAAiB,CAAC;AAEhC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACjH,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,8BAA8B,EAC9B,qBAAqB,EACrB,oBAAoB,GACpB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACN,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACb,MAAM,oCAAoC,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAE3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAE5C,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,YAAY,EACZ,0BAA0B,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,KAAK,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEtF,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AAExC,OAAO,EACN,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,iBAAiB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACN,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,KAAK,wBAAwB,EAC7B,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACtB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,GAC9B,MAAM,gCAAgC,CAAC;AAExC,cAAc,YAAY,CAAC","sourcesContent":["// Core Agent\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\n// Read-only atomic commit planning; candidates are not execution authorization.\nexport { planAtomicCommits } from \"./commit-planner.ts\";\nexport type { ChangeAtom, ChangeRelation, CommitGroup, CommitPlan, CommitPlannerInput } from \"./commit-types.ts\";\nexport * from \"./harness/abort-delivery.ts\";\nexport * from \"./harness/agent-harness.ts\";\nexport {\n\ttype BranchPreparation,\n\ttype BranchSummaryDetails,\n\ttype CollectEntriesResult,\n\tcollectEntriesForBranchSummary,\n\tgenerateBranchSummary,\n\tprepareBranchEntries,\n} from \"./harness/compaction/branch-summarization.ts\";\nexport {\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgetLastAssistantUsage,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./harness/compaction/compaction.ts\";\nexport * from \"./harness/deferred-commands.ts\";\nexport * from \"./harness/messages.ts\";\nexport * from \"./harness/prompt-templates.ts\";\nexport * from \"./harness/reverse-skill.ts\";\nexport * from \"./harness/session/jsonl-repo.ts\";\nexport * from \"./harness/session/memory-repo.ts\";\nexport * from \"./harness/session/repo-utils.ts\";\nexport * from \"./harness/session/session.ts\";\nexport { uuidv7 } from \"./harness/session/uuid.ts\";\nexport * from \"./harness/skills.ts\";\nexport * from \"./harness/system-prompt.ts\";\n// Harness\nexport * from \"./harness/types.ts\";\nexport * from \"./harness/utils/shell-output.ts\";\nexport * from \"./harness/utils/truncate.ts\";\n// Parallel tool batch policy\nexport {\n\tNEVER_PARALLEL_TOOLS,\n\tPARALLEL_SAFE_TOOLS,\n\tPATH_SCOPED_TOOLS,\n\tpartitionToolBatchWaves,\n\tpathsOverlap,\n\tshouldParallelizeToolBatch,\n} from \"./parallel-tool-batch.ts\";\nexport { type ProviderInputProjection, projectToolImagesForModel } from \"./provider-input.ts\";\nexport { applyModelContract, type ProviderRequestEvent } from \"./provider-request.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\nexport * from \"./run-model-contract.ts\";\n// Deterministic resource-claim DAG scheduler (dag-v2)\nexport {\n\tapplyConcurrencyCap,\n\tassignDagLevels,\n\tcomputePlanKey,\n\ttype DagSchedulePlan,\n\ttype ResolvedClaimEntry,\n\tresolveBatchClaims,\n\ttype ScheduleDagLevelsOptions,\n\tscheduleDagLevels,\n} from \"./tool-dag-scheduler.ts\";\n// Resource-claim model (dag-v2)\nexport {\n\ttype ClaimableToolCall,\n\tcanonicalizeClaims,\n\tclaimsConflict,\n\tcompareClaims,\n\ttype ResolveToolClaimsOptions,\n\tresolutionsConflict,\n\tresolvePathClaimKey,\n\tresolveToolClaims,\n\ttype ToolClaimResolution,\n\ttype ToolResourceAccess,\n\ttype ToolResourceClaim,\n} from \"./tool-resource-claims.ts\";\n// Per-call timeout / cancellation / late settlement (ALG-004)\nexport {\n\tcreateAbortedToolResult,\n\tcreateTimeoutToolResult,\n\tresolveToolExecutionPolicy,\n\tresolveToolTimeoutMs,\n\ttype ToolDispositionEnvelope,\n\ttype ToolLateSettlement,\n} from \"./tool-timeout.ts\";\nexport {\n\tcreateSyntheticToolResult,\n\tinspectTranscriptIntegrity,\n\trepairTranscriptIntegrity,\n\tTranscriptIntegrityError,\n\ttype TranscriptIntegrityIssue,\n\ttype TranscriptIntegrityIssueKind,\n\ttype TranscriptIntegrityReport,\n} from \"./tool-transcript-integrity.ts\";\n// Types\nexport * from \"./types.ts\";\n"]}
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@
2
2
  export * from "./agent.js";
3
3
  // Loop functions
4
4
  export * from "./agent-loop.js";
5
+ // Read-only atomic commit planning; candidates are not execution authorization.
6
+ export { planAtomicCommits } from "./commit-planner.js";
5
7
  export * from "./harness/abort-delivery.js";
6
8
  export * from "./harness/agent-harness.js";
7
9
  export { collectEntriesForBranchSummary, generateBranchSummary, prepareBranchEntries, } from "./harness/compaction/branch-summarization.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,YAAY,CAAC;AAC3B,iBAAiB;AACjB,cAAc,iBAAiB,CAAC;AAChC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAIN,8BAA8B,EAC9B,qBAAqB,EACrB,oBAAoB,GACpB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACN,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACb,MAAM,oCAAoC,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,UAAU;AACV,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,6BAA6B;AAC7B,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,YAAY,EACZ,0BAA0B,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAgC,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAA6B,MAAM,uBAAuB,CAAC;AACtF,kBAAkB;AAClB,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,sDAAsD;AACtD,OAAO,EACN,mBAAmB,EACnB,eAAe,EACf,cAAc,EAGd,kBAAkB,EAElB,iBAAiB,GACjB,MAAM,yBAAyB,CAAC;AACjC,gCAAgC;AAChC,OAAO,EAEN,kBAAkB,EAClB,cAAc,EACd,aAAa,EAEb,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAIjB,MAAM,2BAA2B,CAAC;AACnC,8DAA8D;AAC9D,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,GAGpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,GAIxB,MAAM,gCAAgC,CAAC;AACxC,QAAQ;AACR,cAAc,YAAY,CAAC","sourcesContent":["// Core Agent\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\nexport * from \"./harness/abort-delivery.ts\";\nexport * from \"./harness/agent-harness.ts\";\nexport {\n\ttype BranchPreparation,\n\ttype BranchSummaryDetails,\n\ttype CollectEntriesResult,\n\tcollectEntriesForBranchSummary,\n\tgenerateBranchSummary,\n\tprepareBranchEntries,\n} from \"./harness/compaction/branch-summarization.ts\";\nexport {\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgetLastAssistantUsage,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./harness/compaction/compaction.ts\";\nexport * from \"./harness/deferred-commands.ts\";\nexport * from \"./harness/messages.ts\";\nexport * from \"./harness/prompt-templates.ts\";\nexport * from \"./harness/reverse-skill.ts\";\nexport * from \"./harness/session/jsonl-repo.ts\";\nexport * from \"./harness/session/memory-repo.ts\";\nexport * from \"./harness/session/repo-utils.ts\";\nexport * from \"./harness/session/session.ts\";\nexport { uuidv7 } from \"./harness/session/uuid.ts\";\nexport * from \"./harness/skills.ts\";\nexport * from \"./harness/system-prompt.ts\";\n// Harness\nexport * from \"./harness/types.ts\";\nexport * from \"./harness/utils/shell-output.ts\";\nexport * from \"./harness/utils/truncate.ts\";\n// Parallel tool batch policy\nexport {\n\tNEVER_PARALLEL_TOOLS,\n\tPARALLEL_SAFE_TOOLS,\n\tPATH_SCOPED_TOOLS,\n\tpartitionToolBatchWaves,\n\tpathsOverlap,\n\tshouldParallelizeToolBatch,\n} from \"./parallel-tool-batch.ts\";\nexport { type ProviderInputProjection, projectToolImagesForModel } from \"./provider-input.ts\";\nexport { applyModelContract, type ProviderRequestEvent } from \"./provider-request.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\nexport * from \"./run-model-contract.ts\";\n// Deterministic resource-claim DAG scheduler (dag-v2)\nexport {\n\tapplyConcurrencyCap,\n\tassignDagLevels,\n\tcomputePlanKey,\n\ttype DagSchedulePlan,\n\ttype ResolvedClaimEntry,\n\tresolveBatchClaims,\n\ttype ScheduleDagLevelsOptions,\n\tscheduleDagLevels,\n} from \"./tool-dag-scheduler.ts\";\n// Resource-claim model (dag-v2)\nexport {\n\ttype ClaimableToolCall,\n\tcanonicalizeClaims,\n\tclaimsConflict,\n\tcompareClaims,\n\ttype ResolveToolClaimsOptions,\n\tresolutionsConflict,\n\tresolvePathClaimKey,\n\tresolveToolClaims,\n\ttype ToolClaimResolution,\n\ttype ToolResourceAccess,\n\ttype ToolResourceClaim,\n} from \"./tool-resource-claims.ts\";\n// Per-call timeout / cancellation / late settlement (ALG-004)\nexport {\n\tcreateAbortedToolResult,\n\tcreateTimeoutToolResult,\n\tresolveToolExecutionPolicy,\n\tresolveToolTimeoutMs,\n\ttype ToolDispositionEnvelope,\n\ttype ToolLateSettlement,\n} from \"./tool-timeout.ts\";\nexport {\n\tcreateSyntheticToolResult,\n\tinspectTranscriptIntegrity,\n\trepairTranscriptIntegrity,\n\tTranscriptIntegrityError,\n\ttype TranscriptIntegrityIssue,\n\ttype TranscriptIntegrityIssueKind,\n\ttype TranscriptIntegrityReport,\n} from \"./tool-transcript-integrity.ts\";\n// Types\nexport * from \"./types.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,YAAY,CAAC;AAC3B,iBAAiB;AACjB,cAAc,iBAAiB,CAAC;AAChC,gFAAgF;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAIN,8BAA8B,EAC9B,qBAAqB,EACrB,oBAAoB,GACpB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACN,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACb,MAAM,oCAAoC,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,UAAU;AACV,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,6BAA6B;AAC7B,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,YAAY,EACZ,0BAA0B,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAgC,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAA6B,MAAM,uBAAuB,CAAC;AACtF,kBAAkB;AAClB,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,sDAAsD;AACtD,OAAO,EACN,mBAAmB,EACnB,eAAe,EACf,cAAc,EAGd,kBAAkB,EAElB,iBAAiB,GACjB,MAAM,yBAAyB,CAAC;AACjC,gCAAgC;AAChC,OAAO,EAEN,kBAAkB,EAClB,cAAc,EACd,aAAa,EAEb,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAIjB,MAAM,2BAA2B,CAAC;AACnC,8DAA8D;AAC9D,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,GAGpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,GAIxB,MAAM,gCAAgC,CAAC;AACxC,QAAQ;AACR,cAAc,YAAY,CAAC","sourcesContent":["// Core Agent\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\n// Read-only atomic commit planning; candidates are not execution authorization.\nexport { planAtomicCommits } from \"./commit-planner.ts\";\nexport type { ChangeAtom, ChangeRelation, CommitGroup, CommitPlan, CommitPlannerInput } from \"./commit-types.ts\";\nexport * from \"./harness/abort-delivery.ts\";\nexport * from \"./harness/agent-harness.ts\";\nexport {\n\ttype BranchPreparation,\n\ttype BranchSummaryDetails,\n\ttype CollectEntriesResult,\n\tcollectEntriesForBranchSummary,\n\tgenerateBranchSummary,\n\tprepareBranchEntries,\n} from \"./harness/compaction/branch-summarization.ts\";\nexport {\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgetLastAssistantUsage,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./harness/compaction/compaction.ts\";\nexport * from \"./harness/deferred-commands.ts\";\nexport * from \"./harness/messages.ts\";\nexport * from \"./harness/prompt-templates.ts\";\nexport * from \"./harness/reverse-skill.ts\";\nexport * from \"./harness/session/jsonl-repo.ts\";\nexport * from \"./harness/session/memory-repo.ts\";\nexport * from \"./harness/session/repo-utils.ts\";\nexport * from \"./harness/session/session.ts\";\nexport { uuidv7 } from \"./harness/session/uuid.ts\";\nexport * from \"./harness/skills.ts\";\nexport * from \"./harness/system-prompt.ts\";\n// Harness\nexport * from \"./harness/types.ts\";\nexport * from \"./harness/utils/shell-output.ts\";\nexport * from \"./harness/utils/truncate.ts\";\n// Parallel tool batch policy\nexport {\n\tNEVER_PARALLEL_TOOLS,\n\tPARALLEL_SAFE_TOOLS,\n\tPATH_SCOPED_TOOLS,\n\tpartitionToolBatchWaves,\n\tpathsOverlap,\n\tshouldParallelizeToolBatch,\n} from \"./parallel-tool-batch.ts\";\nexport { type ProviderInputProjection, projectToolImagesForModel } from \"./provider-input.ts\";\nexport { applyModelContract, type ProviderRequestEvent } from \"./provider-request.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\nexport * from \"./run-model-contract.ts\";\n// Deterministic resource-claim DAG scheduler (dag-v2)\nexport {\n\tapplyConcurrencyCap,\n\tassignDagLevels,\n\tcomputePlanKey,\n\ttype DagSchedulePlan,\n\ttype ResolvedClaimEntry,\n\tresolveBatchClaims,\n\ttype ScheduleDagLevelsOptions,\n\tscheduleDagLevels,\n} from \"./tool-dag-scheduler.ts\";\n// Resource-claim model (dag-v2)\nexport {\n\ttype ClaimableToolCall,\n\tcanonicalizeClaims,\n\tclaimsConflict,\n\tcompareClaims,\n\ttype ResolveToolClaimsOptions,\n\tresolutionsConflict,\n\tresolvePathClaimKey,\n\tresolveToolClaims,\n\ttype ToolClaimResolution,\n\ttype ToolResourceAccess,\n\ttype ToolResourceClaim,\n} from \"./tool-resource-claims.ts\";\n// Per-call timeout / cancellation / late settlement (ALG-004)\nexport {\n\tcreateAbortedToolResult,\n\tcreateTimeoutToolResult,\n\tresolveToolExecutionPolicy,\n\tresolveToolTimeoutMs,\n\ttype ToolDispositionEnvelope,\n\ttype ToolLateSettlement,\n} from \"./tool-timeout.ts\";\nexport {\n\tcreateSyntheticToolResult,\n\tinspectTranscriptIntegrity,\n\trepairTranscriptIntegrity,\n\tTranscriptIntegrityError,\n\ttype TranscriptIntegrityIssue,\n\ttype TranscriptIntegrityIssueKind,\n\ttype TranscriptIntegrityReport,\n} from \"./tool-transcript-integrity.ts\";\n// Types\nexport * from \"./types.ts\";\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Deferred-call bookkeeping for the dag-v2 ready frontier.
3
+ *
4
+ * A call yields its turn when its post-hook claims conflict with an unsettled or
5
+ * running call. The stored resolution is only used to prove that conflict — a
6
+ * deferral decision is "wait", so a stale answer executes nothing — while
7
+ * admission always re-resolves, because dynamic resource identities may change
8
+ * across the wait.
9
+ */
10
+ import type { ToolClaimResolution } from "./tool-resource-claims.ts";
11
+ export interface DeferredCall<Preparation> {
12
+ readonly preparation: Preparation;
13
+ readonly resolution: ToolClaimResolution;
14
+ }
15
+ /** True when the resolution still conflicts with an earlier unsettled or later running call. */
16
+ export declare function deferredStillConflicts(sourceIndex: number, resolution: ToolClaimResolution, settled: ReadonlySet<number>, running: ReadonlySet<number>, resolutions: ReadonlyMap<number, ToolClaimResolution>): boolean;
17
+ //# sourceMappingURL=tool-dag-deferred.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-dag-deferred.d.ts","sourceRoot":"","sources":["../src/tool-dag-deferred.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,MAAM,WAAW,YAAY,CAAC,WAAW;IACxC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;CACzC;AAKD,gGAAgG;AAChG,wBAAgB,sBAAsB,CACrC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,mBAAmB,EAC/B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,GACnD,OAAO,CAET","sourcesContent":["/**\n * Deferred-call bookkeeping for the dag-v2 ready frontier.\n *\n * A call yields its turn when its post-hook claims conflict with an unsettled or\n * running call. The stored resolution is only used to prove that conflict — a\n * deferral decision is \"wait\", so a stale answer executes nothing — while\n * admission always re-resolves, because dynamic resource identities may change\n * across the wait.\n */\n\nimport { conflictsWithUnsettledClaim } from \"./tool-dag-scheduler.ts\";\nimport type { ToolClaimResolution } from \"./tool-resource-claims.ts\";\n\nexport interface DeferredCall<Preparation> {\n\treadonly preparation: Preparation;\n\treadonly resolution: ToolClaimResolution;\n}\n\n/** The frontier's ready queue is already ordered, so a drift check exempts no peer. */\nconst NO_READY_PEERS: ReadonlySet<number> = new Set<number>();\n\n/** True when the resolution still conflicts with an earlier unsettled or later running call. */\nexport function deferredStillConflicts(\n\tsourceIndex: number,\n\tresolution: ToolClaimResolution,\n\tsettled: ReadonlySet<number>,\n\trunning: ReadonlySet<number>,\n\tresolutions: ReadonlyMap<number, ToolClaimResolution>,\n): boolean {\n\treturn conflictsWithUnsettledClaim(sourceIndex, resolution, NO_READY_PEERS, settled, running, resolutions);\n}\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Deferred-call bookkeeping for the dag-v2 ready frontier.
3
+ *
4
+ * A call yields its turn when its post-hook claims conflict with an unsettled or
5
+ * running call. The stored resolution is only used to prove that conflict — a
6
+ * deferral decision is "wait", so a stale answer executes nothing — while
7
+ * admission always re-resolves, because dynamic resource identities may change
8
+ * across the wait.
9
+ */
10
+ import { conflictsWithUnsettledClaim } from "./tool-dag-scheduler.js";
11
+ /** The frontier's ready queue is already ordered, so a drift check exempts no peer. */
12
+ const NO_READY_PEERS = new Set();
13
+ /** True when the resolution still conflicts with an earlier unsettled or later running call. */
14
+ export function deferredStillConflicts(sourceIndex, resolution, settled, running, resolutions) {
15
+ return conflictsWithUnsettledClaim(sourceIndex, resolution, NO_READY_PEERS, settled, running, resolutions);
16
+ }
17
+ //# sourceMappingURL=tool-dag-deferred.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-dag-deferred.js","sourceRoot":"","sources":["../src/tool-dag-deferred.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAQtE,uFAAuF;AACvF,MAAM,cAAc,GAAwB,IAAI,GAAG,EAAU,CAAC;AAE9D,gGAAgG;AAChG,MAAM,UAAU,sBAAsB,CACrC,WAAmB,EACnB,UAA+B,EAC/B,OAA4B,EAC5B,OAA4B,EAC5B,WAAqD,EAC3C;IACV,OAAO,2BAA2B,CAAC,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AAAA,CAC3G","sourcesContent":["/**\n * Deferred-call bookkeeping for the dag-v2 ready frontier.\n *\n * A call yields its turn when its post-hook claims conflict with an unsettled or\n * running call. The stored resolution is only used to prove that conflict — a\n * deferral decision is \"wait\", so a stale answer executes nothing — while\n * admission always re-resolves, because dynamic resource identities may change\n * across the wait.\n */\n\nimport { conflictsWithUnsettledClaim } from \"./tool-dag-scheduler.ts\";\nimport type { ToolClaimResolution } from \"./tool-resource-claims.ts\";\n\nexport interface DeferredCall<Preparation> {\n\treadonly preparation: Preparation;\n\treadonly resolution: ToolClaimResolution;\n}\n\n/** The frontier's ready queue is already ordered, so a drift check exempts no peer. */\nconst NO_READY_PEERS: ReadonlySet<number> = new Set<number>();\n\n/** True when the resolution still conflicts with an earlier unsettled or later running call. */\nexport function deferredStillConflicts(\n\tsourceIndex: number,\n\tresolution: ToolClaimResolution,\n\tsettled: ReadonlySet<number>,\n\trunning: ReadonlySet<number>,\n\tresolutions: ReadonlyMap<number, ToolClaimResolution>,\n): boolean {\n\treturn conflictsWithUnsettledClaim(sourceIndex, resolution, NO_READY_PEERS, settled, running, resolutions);\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { type EcrafAdmissionsOptions } from "./tool-dag-ecraf.ts";
2
+ /**
3
+ * Offline challenger for the synthetic density gap. Does not replace
4
+ * `planEcrafAdmissions`. A one-drop, two-add exchange is reported only when
5
+ * it fits the same capacities and raises priority. Live scheduling stays greedy.
6
+ */
7
+ export declare function challengeEcrafLocalExchange(options: EcrafAdmissionsOptions): {
8
+ readonly baseline: readonly number[];
9
+ readonly challenger: readonly number[] | null;
10
+ readonly baselinePriority: number;
11
+ readonly challengerPriority: number;
12
+ };
13
+ //# sourceMappingURL=tool-dag-ecraf-exchange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-dag-ecraf-exchange.d.ts","sourceRoot":"","sources":["../src/tool-dag-ecraf-exchange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,sBAAsB,EAA4C,MAAM,qBAAqB,CAAC;AAsB5G;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAC7E,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACpC,CA6CA","sourcesContent":["import { type EcrafAdmissionsOptions, type EcrafCandidate, planEcrafAdmissions } from \"./tool-dag-ecraf.ts\";\n\nfunction fitsExchange(\n\tnode: EcrafCandidate,\n\tused: Map<string, number>,\n\tcapacities: Readonly<Record<string, number>>,\n): boolean {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst capacity = capacities[name];\n\t\tif (capacity === undefined) continue;\n\t\tconst needed = node.resources[name] ?? 0;\n\t\tif ((used.get(name) ?? 0) + needed > capacity) return false;\n\t}\n\treturn true;\n}\n\nfunction reserveExchange(node: EcrafCandidate, used: Map<string, number>): void {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tused.set(name, (used.get(name) ?? 0) + (node.resources[name] ?? 0));\n\t}\n}\n\n/**\n * Offline challenger for the synthetic density gap. Does not replace\n * `planEcrafAdmissions`. A one-drop, two-add exchange is reported only when\n * it fits the same capacities and raises priority. Live scheduling stays greedy.\n */\nexport function challengeEcrafLocalExchange(options: EcrafAdmissionsOptions): {\n\treadonly baseline: readonly number[];\n\treadonly challenger: readonly number[] | null;\n\treadonly baselinePriority: number;\n\treadonly challengerPriority: number;\n} {\n\tconst baseline = planEcrafAdmissions(options);\n\tconst byIndex = new Map(options.candidates.map((node) => [node.sourceIndex, node]));\n\tconst priorityOf = (indexes: readonly number[]) =>\n\t\tindexes.reduce((sum, index) => sum + (byIndex.get(index)?.priority ?? 0), 0);\n\tconst baselinePriority = priorityOf(baseline.admit);\n\tlet best = baseline.admit;\n\tlet bestPriority = baselinePriority;\n\tfor (const dropped of baseline.admit) {\n\t\tconst kept = baseline.admit.filter((index) => index !== dropped);\n\t\tconst additions = baseline.deferred.filter((index) => !kept.includes(index));\n\t\tfor (let left = 0; left < additions.length; left++) {\n\t\t\tfor (let right = left + 1; right < additions.length; right++) {\n\t\t\t\tconst candidate = [...kept, additions[left], additions[right]].filter(\n\t\t\t\t\t(index): index is number => index !== undefined,\n\t\t\t\t);\n\t\t\t\tif (candidate.length > options.slots) continue;\n\t\t\t\tconst nodes = candidate.map((index) => byIndex.get(index)).filter((node) => node !== undefined);\n\t\t\t\tif (nodes.length !== candidate.length) continue;\n\t\t\t\tif (\n\t\t\t\t\toptions.conflicts &&\n\t\t\t\t\tnodes.some((node, index) => nodes.slice(index + 1).some((other) => options.conflicts?.(node, other)))\n\t\t\t\t)\n\t\t\t\t\tcontinue;\n\t\t\t\tconst used = new Map<string, number>(Object.entries(options.runningUsage));\n\t\t\t\tconst fitsAll = nodes.every((node) => {\n\t\t\t\t\tif (!fitsExchange(node, used, options.capacities)) return false;\n\t\t\t\t\treserveExchange(node, used);\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\t\t\t\tif (!fitsAll) continue;\n\t\t\t\tconst priority = priorityOf(candidate);\n\t\t\t\tif (priority > bestPriority) {\n\t\t\t\t\tbest = candidate;\n\t\t\t\t\tbestPriority = priority;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tbaseline: baseline.admit,\n\t\tchallenger: bestPriority > baselinePriority ? best : null,\n\t\tbaselinePriority,\n\t\tchallengerPriority: bestPriority,\n\t};\n}\n"]}
@@ -0,0 +1,68 @@
1
+ import { planEcrafAdmissions } from "./tool-dag-ecraf.js";
2
+ function fitsExchange(node, used, capacities) {
3
+ for (const name of Object.keys(node.resources)) {
4
+ const capacity = capacities[name];
5
+ if (capacity === undefined)
6
+ continue;
7
+ const needed = node.resources[name] ?? 0;
8
+ if ((used.get(name) ?? 0) + needed > capacity)
9
+ return false;
10
+ }
11
+ return true;
12
+ }
13
+ function reserveExchange(node, used) {
14
+ for (const name of Object.keys(node.resources)) {
15
+ used.set(name, (used.get(name) ?? 0) + (node.resources[name] ?? 0));
16
+ }
17
+ }
18
+ /**
19
+ * Offline challenger for the synthetic density gap. Does not replace
20
+ * `planEcrafAdmissions`. A one-drop, two-add exchange is reported only when
21
+ * it fits the same capacities and raises priority. Live scheduling stays greedy.
22
+ */
23
+ export function challengeEcrafLocalExchange(options) {
24
+ const baseline = planEcrafAdmissions(options);
25
+ const byIndex = new Map(options.candidates.map((node) => [node.sourceIndex, node]));
26
+ const priorityOf = (indexes) => indexes.reduce((sum, index) => sum + (byIndex.get(index)?.priority ?? 0), 0);
27
+ const baselinePriority = priorityOf(baseline.admit);
28
+ let best = baseline.admit;
29
+ let bestPriority = baselinePriority;
30
+ for (const dropped of baseline.admit) {
31
+ const kept = baseline.admit.filter((index) => index !== dropped);
32
+ const additions = baseline.deferred.filter((index) => !kept.includes(index));
33
+ for (let left = 0; left < additions.length; left++) {
34
+ for (let right = left + 1; right < additions.length; right++) {
35
+ const candidate = [...kept, additions[left], additions[right]].filter((index) => index !== undefined);
36
+ if (candidate.length > options.slots)
37
+ continue;
38
+ const nodes = candidate.map((index) => byIndex.get(index)).filter((node) => node !== undefined);
39
+ if (nodes.length !== candidate.length)
40
+ continue;
41
+ if (options.conflicts &&
42
+ nodes.some((node, index) => nodes.slice(index + 1).some((other) => options.conflicts?.(node, other))))
43
+ continue;
44
+ const used = new Map(Object.entries(options.runningUsage));
45
+ const fitsAll = nodes.every((node) => {
46
+ if (!fitsExchange(node, used, options.capacities))
47
+ return false;
48
+ reserveExchange(node, used);
49
+ return true;
50
+ });
51
+ if (!fitsAll)
52
+ continue;
53
+ const priority = priorityOf(candidate);
54
+ if (priority > bestPriority) {
55
+ best = candidate;
56
+ bestPriority = priority;
57
+ }
58
+ }
59
+ }
60
+ }
61
+ return {
62
+ baseline: baseline.admit,
63
+ challenger: bestPriority > baselinePriority ? best : null,
64
+ baselinePriority,
65
+ challengerPriority: bestPriority,
66
+ };
67
+ }
68
+ //# sourceMappingURL=tool-dag-ecraf-exchange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-dag-ecraf-exchange.js","sourceRoot":"","sources":["../src/tool-dag-ecraf-exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import { type EcrafAdmissionsOptions, type EcrafCandidate, planEcrafAdmissions } from \"./tool-dag-ecraf.ts\";\n\nfunction fitsExchange(\n\tnode: EcrafCandidate,\n\tused: Map<string, number>,\n\tcapacities: Readonly<Record<string, number>>,\n): boolean {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst capacity = capacities[name];\n\t\tif (capacity === undefined) continue;\n\t\tconst needed = node.resources[name] ?? 0;\n\t\tif ((used.get(name) ?? 0) + needed > capacity) return false;\n\t}\n\treturn true;\n}\n\nfunction reserveExchange(node: EcrafCandidate, used: Map<string, number>): void {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tused.set(name, (used.get(name) ?? 0) + (node.resources[name] ?? 0));\n\t}\n}\n\n/**\n * Offline challenger for the synthetic density gap. Does not replace\n * `planEcrafAdmissions`. A one-drop, two-add exchange is reported only when\n * it fits the same capacities and raises priority. Live scheduling stays greedy.\n */\nexport function challengeEcrafLocalExchange(options: EcrafAdmissionsOptions): {\n\treadonly baseline: readonly number[];\n\treadonly challenger: readonly number[] | null;\n\treadonly baselinePriority: number;\n\treadonly challengerPriority: number;\n} {\n\tconst baseline = planEcrafAdmissions(options);\n\tconst byIndex = new Map(options.candidates.map((node) => [node.sourceIndex, node]));\n\tconst priorityOf = (indexes: readonly number[]) =>\n\t\tindexes.reduce((sum, index) => sum + (byIndex.get(index)?.priority ?? 0), 0);\n\tconst baselinePriority = priorityOf(baseline.admit);\n\tlet best = baseline.admit;\n\tlet bestPriority = baselinePriority;\n\tfor (const dropped of baseline.admit) {\n\t\tconst kept = baseline.admit.filter((index) => index !== dropped);\n\t\tconst additions = baseline.deferred.filter((index) => !kept.includes(index));\n\t\tfor (let left = 0; left < additions.length; left++) {\n\t\t\tfor (let right = left + 1; right < additions.length; right++) {\n\t\t\t\tconst candidate = [...kept, additions[left], additions[right]].filter(\n\t\t\t\t\t(index): index is number => index !== undefined,\n\t\t\t\t);\n\t\t\t\tif (candidate.length > options.slots) continue;\n\t\t\t\tconst nodes = candidate.map((index) => byIndex.get(index)).filter((node) => node !== undefined);\n\t\t\t\tif (nodes.length !== candidate.length) continue;\n\t\t\t\tif (\n\t\t\t\t\toptions.conflicts &&\n\t\t\t\t\tnodes.some((node, index) => nodes.slice(index + 1).some((other) => options.conflicts?.(node, other)))\n\t\t\t\t)\n\t\t\t\t\tcontinue;\n\t\t\t\tconst used = new Map<string, number>(Object.entries(options.runningUsage));\n\t\t\t\tconst fitsAll = nodes.every((node) => {\n\t\t\t\t\tif (!fitsExchange(node, used, options.capacities)) return false;\n\t\t\t\t\treserveExchange(node, used);\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\t\t\t\tif (!fitsAll) continue;\n\t\t\t\tconst priority = priorityOf(candidate);\n\t\t\t\tif (priority > bestPriority) {\n\t\t\t\t\tbest = candidate;\n\t\t\t\t\tbestPriority = priority;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tbaseline: baseline.admit,\n\t\tchallenger: bestPriority > baselinePriority ? best : null,\n\t\tbaselinePriority,\n\t\tchallengerPriority: bestPriority,\n\t};\n}\n"]}
@@ -14,7 +14,7 @@ export declare const DAG_SCHEDULE_CACHE_LIMIT = 64;
14
14
  * Schedule with a per-run memo. Identical batches (provider retries, stubborn
15
15
  * re-emissions) re-resolve path identities and custom claims; the plan is a
16
16
  * pure function of the canonical inputs, so replaying it is safe. Returns
17
- * `null` when the underlying schedule was aborted. Cached levels are handed
17
+ * `null` on cancellation, including cache hits before key serialization. Cached levels are handed
18
18
  * out as copies because callers append to and reorder them.
19
19
  */
20
20
  export declare function scheduleDagLevelsMemo(toolCalls: readonly ClaimableToolCall[], options: ScheduleDagLevelsOptions, signal: AbortSignal | undefined, cache: DagScheduleCache): Promise<DagSchedulePlan | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-dag-memo.d.ts","sourceRoot":"","sources":["../src/tool-dag-memo.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,wBAAwB,EAAqB,MAAM,yBAAyB,CAAC;AAEjH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,8CAA8C;AAC9C,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE5D,eAAO,MAAM,wBAAwB,KAAK,CAAC;AA4B3C;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAC1C,SAAS,EAAE,SAAS,iBAAiB,EAAE,EACvC,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,KAAK,EAAE,gBAAgB,GACrB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAmCjC","sourcesContent":["/**\n * Per-run memo for DAG schedules. A plan is a pure function of the keyed\n * inputs, so replaying it is safe — but only while every input the key cannot\n * fingerprint stays stable. A custom `resourceKeyResolver` or any tool whose\n * `resourceClaims` is a function closure can answer differently on identical\n * call shapes, so those batches bypass the memo entirely (audit §9).\n */\n\nimport { type DagSchedulePlan, type ScheduleDagLevelsOptions, scheduleDagLevels } from \"./tool-dag-scheduler.ts\";\nimport { awaitWithAbort } from \"./tool-execution-boundary.ts\";\nimport type { ClaimableToolCall } from \"./tool-resource-claims.ts\";\n\n/** Bounded per-run memo for DAG schedules. */\nexport type DagScheduleCache = Map<string, DagSchedulePlan>;\n\nexport const DAG_SCHEDULE_CACHE_LIMIT = 64;\n\n/**\n * Canonical key covering every input claim resolution depends on. A custom\n * `resourceKeyResolver` function cannot be fingerprinted, so callers skip the\n * memo entirely when one is configured. Within a run, tool definitions (and\n * their `resourceClaims` closures) are stable, so name/mode/claims-presence\n * fingerprints are sufficient.\n */\nfunction dagScheduleCacheKey(toolCalls: readonly ClaimableToolCall[], options: ScheduleDagLevelsOptions): string {\n\tconst policies = [...(options.toolPolicies?.entries() ?? [])].sort(([left], [right]) =>\n\t\tleft < right ? -1 : left > right ? 1 : 0,\n\t);\n\tconst registered = (options.registeredTools ?? []).map((tool) => [\n\t\ttool.name,\n\t\ttool.executionMode ?? \"\",\n\t\ttypeof tool.resourceClaims === \"function\" ? \"1\" : \"0\",\n\t]);\n\treturn JSON.stringify([\n\t\ttoolCalls.map((call) => [call.name, call.arguments ?? null]),\n\t\toptions.cwd,\n\t\toptions.strictExtensionClaims === true,\n\t\toptions.maxConcurrency ?? null,\n\t\tpolicies,\n\t\tregistered,\n\t]);\n}\n\n/**\n * Schedule with a per-run memo. Identical batches (provider retries, stubborn\n * re-emissions) re-resolve path identities and custom claims; the plan is a\n * pure function of the canonical inputs, so replaying it is safe. Returns\n * `null` when the underlying schedule was aborted. Cached levels are handed\n * out as copies because callers append to and reorder them.\n */\nexport async function scheduleDagLevelsMemo(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ScheduleDagLevelsOptions,\n\tsignal: AbortSignal | undefined,\n\tcache: DagScheduleCache,\n): Promise<DagSchedulePlan | null> {\n\t// Skip the memo whenever resolution can depend on state the key cannot\n\t// fingerprint: a custom resourceKeyResolver, or any tool whose resourceClaims\n\t// is a function closure — its return value may change between identical\n\t// calls, and a stale cached plan would silently reuse its old claims.\n\tif (\n\t\toptions.resourceKeyResolver ||\n\t\toptions.registeredTools?.some((tool) => typeof tool.resourceClaims === \"function\")\n\t) {\n\t\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\t\treturn scheduled.kind === \"aborted\" ? null : scheduled.value;\n\t}\n\tconst key = dagScheduleCacheKey(toolCalls, options);\n\tconst cached = cache.get(key);\n\tif (cached) {\n\t\tcache.delete(key);\n\t\tcache.set(key, cached);\n\t\treturn { levels: cached.levels.map((level) => level.slice()), planKey: cached.planKey, entries: cached.entries };\n\t}\n\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\tif (scheduled.kind === \"aborted\") {\n\t\treturn null;\n\t}\n\tif (cache.size >= DAG_SCHEDULE_CACHE_LIMIT) {\n\t\tconst oldest = cache.keys().next();\n\t\tif (!oldest.done) {\n\t\t\tcache.delete(oldest.value);\n\t\t}\n\t}\n\tcache.set(key, {\n\t\tlevels: scheduled.value.levels.map((level) => level.slice()),\n\t\tplanKey: scheduled.value.planKey,\n\t\tentries: scheduled.value.entries,\n\t});\n\treturn scheduled.value;\n}\n"]}
1
+ {"version":3,"file":"tool-dag-memo.d.ts","sourceRoot":"","sources":["../src/tool-dag-memo.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,wBAAwB,EAAqB,MAAM,yBAAyB,CAAC;AAEjH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,8CAA8C;AAC9C,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE5D,eAAO,MAAM,wBAAwB,KAAK,CAAC;AA4B3C;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAC1C,SAAS,EAAE,SAAS,iBAAiB,EAAE,EACvC,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,KAAK,EAAE,gBAAgB,GACrB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAoCjC","sourcesContent":["/**\n * Per-run memo for DAG schedules. A plan is a pure function of the keyed\n * inputs, so replaying it is safe — but only while every input the key cannot\n * fingerprint stays stable. A custom `resourceKeyResolver` or any tool whose\n * `resourceClaims` is a function closure can answer differently on identical\n * call shapes, so those batches bypass the memo entirely (audit §9).\n */\n\nimport { type DagSchedulePlan, type ScheduleDagLevelsOptions, scheduleDagLevels } from \"./tool-dag-scheduler.ts\";\nimport { awaitWithAbort } from \"./tool-execution-boundary.ts\";\nimport type { ClaimableToolCall } from \"./tool-resource-claims.ts\";\n\n/** Bounded per-run memo for DAG schedules. */\nexport type DagScheduleCache = Map<string, DagSchedulePlan>;\n\nexport const DAG_SCHEDULE_CACHE_LIMIT = 64;\n\n/**\n * Canonical key covering every input claim resolution depends on. A custom\n * `resourceKeyResolver` function cannot be fingerprinted, so callers skip the\n * memo entirely when one is configured. Within a run, tool definitions (and\n * their `resourceClaims` closures) are stable, so name/mode/claims-presence\n * fingerprints are sufficient.\n */\nfunction dagScheduleCacheKey(toolCalls: readonly ClaimableToolCall[], options: ScheduleDagLevelsOptions): string {\n\tconst policies = [...(options.toolPolicies?.entries() ?? [])].sort(([left], [right]) =>\n\t\tleft < right ? -1 : left > right ? 1 : 0,\n\t);\n\tconst registered = (options.registeredTools ?? []).map((tool) => [\n\t\ttool.name,\n\t\ttool.executionMode ?? \"\",\n\t\ttypeof tool.resourceClaims === \"function\" ? \"1\" : \"0\",\n\t]);\n\treturn JSON.stringify([\n\t\ttoolCalls.map((call) => [call.name, call.arguments ?? null]),\n\t\toptions.cwd,\n\t\toptions.strictExtensionClaims === true,\n\t\toptions.maxConcurrency ?? null,\n\t\tpolicies,\n\t\tregistered,\n\t]);\n}\n\n/**\n * Schedule with a per-run memo. Identical batches (provider retries, stubborn\n * re-emissions) re-resolve path identities and custom claims; the plan is a\n * pure function of the canonical inputs, so replaying it is safe. Returns\n * `null` on cancellation, including cache hits before key serialization. Cached levels are handed\n * out as copies because callers append to and reorder them.\n */\nexport async function scheduleDagLevelsMemo(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ScheduleDagLevelsOptions,\n\tsignal: AbortSignal | undefined,\n\tcache: DagScheduleCache,\n): Promise<DagSchedulePlan | null> {\n\tif (signal?.aborted) return null;\n\t// Skip the memo whenever resolution can depend on state the key cannot\n\t// fingerprint: a custom resourceKeyResolver, or any tool whose resourceClaims\n\t// is a function closure — its return value may change between identical\n\t// calls, and a stale cached plan would silently reuse its old claims.\n\tif (\n\t\toptions.resourceKeyResolver ||\n\t\toptions.registeredTools?.some((tool) => typeof tool.resourceClaims === \"function\")\n\t) {\n\t\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\t\treturn scheduled.kind === \"aborted\" ? null : scheduled.value;\n\t}\n\tconst key = dagScheduleCacheKey(toolCalls, options);\n\tconst cached = cache.get(key);\n\tif (cached) {\n\t\tcache.delete(key);\n\t\tcache.set(key, cached);\n\t\treturn { levels: cached.levels.map((level) => level.slice()), planKey: cached.planKey, entries: cached.entries };\n\t}\n\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\tif (scheduled.kind === \"aborted\") {\n\t\treturn null;\n\t}\n\tif (cache.size >= DAG_SCHEDULE_CACHE_LIMIT) {\n\t\tconst oldest = cache.keys().next();\n\t\tif (!oldest.done) {\n\t\t\tcache.delete(oldest.value);\n\t\t}\n\t}\n\tcache.set(key, {\n\t\tlevels: scheduled.value.levels.map((level) => level.slice()),\n\t\tplanKey: scheduled.value.planKey,\n\t\tentries: scheduled.value.entries,\n\t});\n\treturn scheduled.value;\n}\n"]}
@@ -35,10 +35,12 @@ function dagScheduleCacheKey(toolCalls, options) {
35
35
  * Schedule with a per-run memo. Identical batches (provider retries, stubborn
36
36
  * re-emissions) re-resolve path identities and custom claims; the plan is a
37
37
  * pure function of the canonical inputs, so replaying it is safe. Returns
38
- * `null` when the underlying schedule was aborted. Cached levels are handed
38
+ * `null` on cancellation, including cache hits before key serialization. Cached levels are handed
39
39
  * out as copies because callers append to and reorder them.
40
40
  */
41
41
  export async function scheduleDagLevelsMemo(toolCalls, options, signal, cache) {
42
+ if (signal?.aborted)
43
+ return null;
42
44
  // Skip the memo whenever resolution can depend on state the key cannot
43
45
  // fingerprint: a custom resourceKeyResolver, or any tool whose resourceClaims
44
46
  // is a function closure — its return value may change between identical
@@ -1 +1 @@
1
- {"version":3,"file":"tool-dag-memo.js","sourceRoot":"","sources":["../src/tool-dag-memo.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Per-run memo for DAG schedules. A plan is a pure function of the keyed\n * inputs, so replaying it is safe — but only while every input the key cannot\n * fingerprint stays stable. A custom `resourceKeyResolver` or any tool whose\n * `resourceClaims` is a function closure can answer differently on identical\n * call shapes, so those batches bypass the memo entirely (audit §9).\n */\n\nimport { type DagSchedulePlan, type ScheduleDagLevelsOptions, scheduleDagLevels } from \"./tool-dag-scheduler.ts\";\nimport { awaitWithAbort } from \"./tool-execution-boundary.ts\";\nimport type { ClaimableToolCall } from \"./tool-resource-claims.ts\";\n\n/** Bounded per-run memo for DAG schedules. */\nexport type DagScheduleCache = Map<string, DagSchedulePlan>;\n\nexport const DAG_SCHEDULE_CACHE_LIMIT = 64;\n\n/**\n * Canonical key covering every input claim resolution depends on. A custom\n * `resourceKeyResolver` function cannot be fingerprinted, so callers skip the\n * memo entirely when one is configured. Within a run, tool definitions (and\n * their `resourceClaims` closures) are stable, so name/mode/claims-presence\n * fingerprints are sufficient.\n */\nfunction dagScheduleCacheKey(toolCalls: readonly ClaimableToolCall[], options: ScheduleDagLevelsOptions): string {\n\tconst policies = [...(options.toolPolicies?.entries() ?? [])].sort(([left], [right]) =>\n\t\tleft < right ? -1 : left > right ? 1 : 0,\n\t);\n\tconst registered = (options.registeredTools ?? []).map((tool) => [\n\t\ttool.name,\n\t\ttool.executionMode ?? \"\",\n\t\ttypeof tool.resourceClaims === \"function\" ? \"1\" : \"0\",\n\t]);\n\treturn JSON.stringify([\n\t\ttoolCalls.map((call) => [call.name, call.arguments ?? null]),\n\t\toptions.cwd,\n\t\toptions.strictExtensionClaims === true,\n\t\toptions.maxConcurrency ?? null,\n\t\tpolicies,\n\t\tregistered,\n\t]);\n}\n\n/**\n * Schedule with a per-run memo. Identical batches (provider retries, stubborn\n * re-emissions) re-resolve path identities and custom claims; the plan is a\n * pure function of the canonical inputs, so replaying it is safe. Returns\n * `null` when the underlying schedule was aborted. Cached levels are handed\n * out as copies because callers append to and reorder them.\n */\nexport async function scheduleDagLevelsMemo(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ScheduleDagLevelsOptions,\n\tsignal: AbortSignal | undefined,\n\tcache: DagScheduleCache,\n): Promise<DagSchedulePlan | null> {\n\t// Skip the memo whenever resolution can depend on state the key cannot\n\t// fingerprint: a custom resourceKeyResolver, or any tool whose resourceClaims\n\t// is a function closure — its return value may change between identical\n\t// calls, and a stale cached plan would silently reuse its old claims.\n\tif (\n\t\toptions.resourceKeyResolver ||\n\t\toptions.registeredTools?.some((tool) => typeof tool.resourceClaims === \"function\")\n\t) {\n\t\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\t\treturn scheduled.kind === \"aborted\" ? null : scheduled.value;\n\t}\n\tconst key = dagScheduleCacheKey(toolCalls, options);\n\tconst cached = cache.get(key);\n\tif (cached) {\n\t\tcache.delete(key);\n\t\tcache.set(key, cached);\n\t\treturn { levels: cached.levels.map((level) => level.slice()), planKey: cached.planKey, entries: cached.entries };\n\t}\n\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\tif (scheduled.kind === \"aborted\") {\n\t\treturn null;\n\t}\n\tif (cache.size >= DAG_SCHEDULE_CACHE_LIMIT) {\n\t\tconst oldest = cache.keys().next();\n\t\tif (!oldest.done) {\n\t\t\tcache.delete(oldest.value);\n\t\t}\n\t}\n\tcache.set(key, {\n\t\tlevels: scheduled.value.levels.map((level) => level.slice()),\n\t\tplanKey: scheduled.value.planKey,\n\t\tentries: scheduled.value.entries,\n\t});\n\treturn scheduled.value;\n}\n"]}
1
+ {"version":3,"file":"tool-dag-memo.js","sourceRoot":"","sources":["../src/tool-dag-memo.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Per-run memo for DAG schedules. A plan is a pure function of the keyed\n * inputs, so replaying it is safe — but only while every input the key cannot\n * fingerprint stays stable. A custom `resourceKeyResolver` or any tool whose\n * `resourceClaims` is a function closure can answer differently on identical\n * call shapes, so those batches bypass the memo entirely (audit §9).\n */\n\nimport { type DagSchedulePlan, type ScheduleDagLevelsOptions, scheduleDagLevels } from \"./tool-dag-scheduler.ts\";\nimport { awaitWithAbort } from \"./tool-execution-boundary.ts\";\nimport type { ClaimableToolCall } from \"./tool-resource-claims.ts\";\n\n/** Bounded per-run memo for DAG schedules. */\nexport type DagScheduleCache = Map<string, DagSchedulePlan>;\n\nexport const DAG_SCHEDULE_CACHE_LIMIT = 64;\n\n/**\n * Canonical key covering every input claim resolution depends on. A custom\n * `resourceKeyResolver` function cannot be fingerprinted, so callers skip the\n * memo entirely when one is configured. Within a run, tool definitions (and\n * their `resourceClaims` closures) are stable, so name/mode/claims-presence\n * fingerprints are sufficient.\n */\nfunction dagScheduleCacheKey(toolCalls: readonly ClaimableToolCall[], options: ScheduleDagLevelsOptions): string {\n\tconst policies = [...(options.toolPolicies?.entries() ?? [])].sort(([left], [right]) =>\n\t\tleft < right ? -1 : left > right ? 1 : 0,\n\t);\n\tconst registered = (options.registeredTools ?? []).map((tool) => [\n\t\ttool.name,\n\t\ttool.executionMode ?? \"\",\n\t\ttypeof tool.resourceClaims === \"function\" ? \"1\" : \"0\",\n\t]);\n\treturn JSON.stringify([\n\t\ttoolCalls.map((call) => [call.name, call.arguments ?? null]),\n\t\toptions.cwd,\n\t\toptions.strictExtensionClaims === true,\n\t\toptions.maxConcurrency ?? null,\n\t\tpolicies,\n\t\tregistered,\n\t]);\n}\n\n/**\n * Schedule with a per-run memo. Identical batches (provider retries, stubborn\n * re-emissions) re-resolve path identities and custom claims; the plan is a\n * pure function of the canonical inputs, so replaying it is safe. Returns\n * `null` on cancellation, including cache hits before key serialization. Cached levels are handed\n * out as copies because callers append to and reorder them.\n */\nexport async function scheduleDagLevelsMemo(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ScheduleDagLevelsOptions,\n\tsignal: AbortSignal | undefined,\n\tcache: DagScheduleCache,\n): Promise<DagSchedulePlan | null> {\n\tif (signal?.aborted) return null;\n\t// Skip the memo whenever resolution can depend on state the key cannot\n\t// fingerprint: a custom resourceKeyResolver, or any tool whose resourceClaims\n\t// is a function closure — its return value may change between identical\n\t// calls, and a stale cached plan would silently reuse its old claims.\n\tif (\n\t\toptions.resourceKeyResolver ||\n\t\toptions.registeredTools?.some((tool) => typeof tool.resourceClaims === \"function\")\n\t) {\n\t\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\t\treturn scheduled.kind === \"aborted\" ? null : scheduled.value;\n\t}\n\tconst key = dagScheduleCacheKey(toolCalls, options);\n\tconst cached = cache.get(key);\n\tif (cached) {\n\t\tcache.delete(key);\n\t\tcache.set(key, cached);\n\t\treturn { levels: cached.levels.map((level) => level.slice()), planKey: cached.planKey, entries: cached.entries };\n\t}\n\tconst scheduled = await awaitWithAbort(() => scheduleDagLevels(toolCalls, options), signal);\n\tif (scheduled.kind === \"aborted\") {\n\t\treturn null;\n\t}\n\tif (cache.size >= DAG_SCHEDULE_CACHE_LIMIT) {\n\t\tconst oldest = cache.keys().next();\n\t\tif (!oldest.done) {\n\t\t\tcache.delete(oldest.value);\n\t\t}\n\t}\n\tcache.set(key, {\n\t\tlevels: scheduled.value.levels.map((level) => level.slice()),\n\t\tplanKey: scheduled.value.planKey,\n\t\tentries: scheduled.value.entries,\n\t});\n\treturn scheduled.value;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-dag-scheduler.d.ts","sourceRoot":"","sources":["../src/tool-dag-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EACN,KAAK,iBAAiB,EAGtB,KAAK,wBAAwB,EAG7B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,MAAM,2BAA2B,CAAC;AAEnC,sDAAsD;AACtD,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACzE;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC/B,4FAA4F;IAC5F,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;IACnB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACvC;AAED,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,mBAAmB,CAAC;IAChC,eAAe,EAAE,iBAAiB,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACvC,SAAS,EAAE,SAAS,iBAAiB,EAAE,EACvC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAQ/B;AAqDD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,EAAE,EAAE,CA6BlF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,EAAE,EAAE,CAYxF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,EAAE,CAgBpG;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAU7E;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACtC,SAAS,EAAE,SAAS,iBAAiB,EAAE,EACvC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAK1B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAC1C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,mBAAmB,EACpC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,GACnD,OAAO,CAYT","sourcesContent":["/**\n * Pure, browser-safe deterministic resource-claim DAG scheduler.\n *\n * Given a source-ordered batch of tool calls and their resolved resource\n * claims, this module assigns each call after every earlier call it conflicts\n * with. Levels run in source order; calls inside one level are mutually\n * conflict-free and may execute concurrently. A positive `maxConcurrency`\n * width cap splits each level into deterministic contiguous source-ordered\n * chunks.\n *\n * Determinism contract:\n * - The level assignment is a pure function of the source-ordered input\n * claims. The canonical example is the head-of-line example\n * `write x, write x, write y`, which schedules as `[[0, 2], [1]]`: the second\n * write to `x` is pushed to level 1, but the independent write to `y` is not\n * blocked and joins level 0.\n * - Reordering claims *within* a single call does not change the plan: claims\n * are canonicalized (sorted, fixed property order) before comparison.\n * - {@link DagSchedulePlan.planKey} is a canonical serialization of the\n * resolved claim sequence (canonical claim data only — never execution\n * timing or outcomes). It is collision-free for distinct canonical claim\n * sequences.\n *\n * This module uses no platform APIs (no `process`, fs, `node:path`, or timers).\n */\n\nimport {\n\ttype ClaimableToolCall,\n\tcanonicalizeClaims,\n\tclaimsConflict,\n\ttype ResolveToolClaimsOptions,\n\tresolutionsConflict,\n\tresolveToolClaimsForCall,\n\ttype ToolClaimResolution,\n\ttype ToolResourceClaim,\n} from \"./tool-resource-claims.ts\";\n\n/** Options for scheduling a batch into DAG levels. */\nexport interface ScheduleDagLevelsOptions extends ResolveToolClaimsOptions {\n\t/**\n\t * Optional positive width cap. When set, each level is split into contiguous\n\t * source-ordered chunks of at most this many calls so a wide conflict-free\n\t * level does not fan out unbounded. Absent, non-finite, or non-positive\n\t * values leave each level whole. Does not affect `planKey`.\n\t */\n\tmaxConcurrency?: number;\n}\n\n/** A scheduled plan: ordered levels of source indices plus a canonical key. */\nexport interface DagSchedulePlan {\n\t/** Levels in execution order; each level holds source indices that may run concurrently. */\n\tlevels: number[][];\n\t/**\n\t * Canonical deterministic key over the resolved claim sequence only (never\n\t * execution timing/outcomes). Stable under claim reordering within a call.\n\t */\n\tplanKey: string;\n\t/**\n\t * The resolved, canonicalized claim entries the plan was built from. Callers\n\t * that re-resolve claims after argument mutation (e.g. authorization hooks)\n\t * compare against these to detect scope drift. Read-only for consumers.\n\t */\n\tentries: readonly ResolvedClaimEntry[];\n}\n\n/** One tool call's resolved claim data, canonicalized for stable planning. */\nexport interface ResolvedClaimEntry {\n\tsourceIndex: number;\n\tresolution: ToolClaimResolution;\n\tcanonicalClaims: ToolResourceClaim[];\n}\n\n/**\n * Resolve and canonicalize claims for a whole batch, preserving source order.\n * Registered custom resolvers are awaited one call at a time in source order,\n * and every resolution completes before a schedule is constructed.\n */\nexport async function resolveBatchClaims(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ResolveToolClaimsOptions,\n): Promise<ResolvedClaimEntry[]> {\n\tconst entries: ResolvedClaimEntry[] = [];\n\tfor (let index = 0; index < toolCalls.length; index++) {\n\t\tconst resolution = await resolveToolClaimsForCall(toolCalls[index], options);\n\t\tconst canonicalClaims = resolution.kind === \"claims\" ? canonicalizeClaims(resolution.claims) : [];\n\t\tentries.push({ sourceIndex: index, resolution, canonicalClaims });\n\t}\n\treturn entries;\n}\n\ninterface DagLevel {\n\tindices: number[];\n\t/** Write claims currently placed in this level (for fast read-vs-write checks). */\n\twriteClaims: ToolResourceClaim[];\n\t/** Read claims currently placed in this level (for fast write-vs-read checks). */\n\treadClaims: ToolResourceClaim[];\n\t/** True once an exclusive call is placed here; such a level accepts no more. */\n\thasExclusive: boolean;\n}\n\nfunction claimConflictsAny(claim: ToolResourceClaim, candidates: readonly ToolResourceClaim[]): boolean {\n\tfor (const candidate of candidates) {\n\t\tif (claimsConflict(claim, candidate)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * True when `resolution` cannot join `level`. Equivalent to the full pairwise\n * `resolutionsConflict` check, optimized so read/read never triggers a scan:\n * a read claim only needs to scan the level's writes, and a write claim scans\n * both writes and reads. An exclusive resolution, or a level that already holds\n * an exclusive call, conflicts unconditionally.\n */\nfunction resolutionConflictsLevel(resolution: ToolClaimResolution, level: DagLevel): boolean {\n\tif (level.hasExclusive) {\n\t\treturn true;\n\t}\n\tif (resolution.kind === \"exclusive\") {\n\t\treturn true;\n\t}\n\tfor (const claim of resolution.claims) {\n\t\tif (claim.access === \"exclusive\") {\n\t\t\treturn true;\n\t\t}\n\t\tif (claim.access === \"write\") {\n\t\t\tif (claimConflictsAny(claim, level.writeClaims)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (claimConflictsAny(claim, level.readClaims)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (claimConflictsAny(claim, level.writeClaims)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Assign each source-ordered claim entry one level after its latest earlier\n * conflict. Deterministic and stable: equal inputs (including claim reordering\n * within a call, which is canonicalized away) always produce equal levels, and\n * every directed conflict edge advances at least one level.\n */\nexport function assignDagLevels(entries: readonly ResolvedClaimEntry[]): number[][] {\n\tconst levels: DagLevel[] = [];\n\tfor (const entry of entries) {\n\t\tconst resolution = entry.resolution;\n\t\tlet targetIndex = 0;\n\t\tfor (let levelIndex = 0; levelIndex < levels.length; levelIndex++) {\n\t\t\tif (resolutionConflictsLevel(resolution, levels[levelIndex])) {\n\t\t\t\ttargetIndex = levelIndex + 1;\n\t\t\t}\n\t\t}\n\t\tlet target = levels[targetIndex];\n\t\tif (!target) {\n\t\t\ttarget = { indices: [], writeClaims: [], readClaims: [], hasExclusive: false };\n\t\t\tlevels.push(target);\n\t\t}\n\t\ttarget.indices.push(entry.sourceIndex);\n\t\tif (resolution.kind === \"exclusive\" || entry.canonicalClaims.some((claim) => claim.access === \"exclusive\")) {\n\t\t\ttarget.hasExclusive = true;\n\t\t} else {\n\t\t\tfor (const claim of entry.canonicalClaims) {\n\t\t\t\tif (claim.access === \"write\") {\n\t\t\t\t\ttarget.writeClaims.push(claim);\n\t\t\t\t} else {\n\t\t\t\t\ttarget.readClaims.push(claim);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn levels.map((level) => level.indices);\n}\n\n/**\n * Direct conflicting predecessors for each source-ordered entry: `result[i]`\n * lists every earlier position `i` must wait for.\n *\n * This is the precedence graph that {@link assignDagLevels} approximates with a\n * barrier schedule. Levels force every call in level N+1 to wait for ALL of\n * level N, so one slow unrelated call in a level delays the whole next level.\n * Dependency edges only connect calls that actually conflict, so a consumer can\n * start each call as soon as its own predecessors settle.\n *\n * Deterministic and stable: the result is a pure function of the source-ordered\n * canonicalized claims, and every list is ascending and strictly earlier-only.\n * Transitively-implied edges are kept rather than reduced — waiting on an\n * already-finished ancestor costs nothing and keeps this a simple pure scan.\n *\n * The graph is never deeper than the barrier schedule: for any `j` in\n * `result[i]`, `i` conflicts with an entry in level `j`, so\n * `level(i) >= level(j) + 1`, and depth follows by induction.\n */\nexport function assignDagDependencies(entries: readonly ResolvedClaimEntry[]): number[][] {\n\tconst dependencies: number[][] = [];\n\tfor (let index = 0; index < entries.length; index++) {\n\t\tconst blockers: number[] = [];\n\t\tfor (let earlier = 0; earlier < index; earlier++) {\n\t\t\tif (resolutionsConflict(entries[earlier].resolution, entries[index].resolution)) {\n\t\t\t\tblockers.push(earlier);\n\t\t\t}\n\t\t}\n\t\tdependencies.push(blockers);\n\t}\n\treturn dependencies;\n}\n\n/**\n * Split each level into contiguous source-ordered chunks of at most `cap` calls.\n * Absent/non-finite/non-positive `cap` returns the levels unchanged.\n */\nexport function applyConcurrencyCap(levels: readonly number[][], cap: number | undefined): number[][] {\n\tif (typeof cap !== \"number\" || !Number.isFinite(cap) || cap <= 0) {\n\t\treturn levels.map((level) => level.slice());\n\t}\n\tconst integerCap = Math.max(1, Math.floor(cap));\n\tconst chunked: number[][] = [];\n\tfor (const level of levels) {\n\t\tif (level.length <= integerCap) {\n\t\t\tchunked.push(level.slice());\n\t\t\tcontinue;\n\t\t}\n\t\tfor (let start = 0; start < level.length; start += integerCap) {\n\t\t\tchunked.push(level.slice(start, start + integerCap));\n\t\t}\n\t}\n\treturn chunked;\n}\n\n/**\n * Canonical deterministic key over the resolved claim sequence. Uses\n * `JSON.stringify` of each call's canonicalized claims (fixed property order,\n * sorted) with an `\"E\"`/`\"C\"` discriminator, so it is collision-free for\n * distinct canonical claim sequences and stable under claim reordering within a\n * call. Contains no execution timing or outcomes.\n */\nexport function computePlanKey(entries: readonly ResolvedClaimEntry[]): string {\n\tlet key = \"\";\n\tfor (const entry of entries) {\n\t\tif (entry.resolution.kind === \"exclusive\") {\n\t\t\tkey += \"E,\";\n\t\t} else {\n\t\t\tkey += `C${JSON.stringify(entry.canonicalClaims)},`;\n\t\t}\n\t}\n\treturn key;\n}\n\n/**\n * Schedule a source-ordered tool-call batch into deterministic DAG levels.\n * Resolves default claims, computes source-directed dependency levels, applies\n * the optional width cap, and computes the canonical plan key. Pure and\n * deterministic.\n */\nexport async function scheduleDagLevels(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ScheduleDagLevelsOptions,\n): Promise<DagSchedulePlan> {\n\tconst entries = await resolveBatchClaims(toolCalls, options);\n\tconst baseLevels = assignDagLevels(entries);\n\tconst levels = applyConcurrencyCap(baseLevels, options.maxConcurrency);\n\treturn { levels, planKey: computePlanKey(entries), entries };\n}\n\n/**\n * True when executing `sourceIndex` now would overlap an unsettled call whose\n * known claims conflict with `finalResolution`.\n *\n * Two distinct violations are covered:\n * - Earlier-source unsettled calls: the initial plan already ordered that\n * pair, so only post-hook scope drift can create the situation; the caller\n * defers the call instead of silently reversing the conflict pair.\n * - Later-source calls that are already running (present in `running`): a\n * hook that expands this call's scope onto their claims must defer — the\n * running call cannot be un-started. Later-source calls that are merely\n * pending keep source order: they may not overlap this call once it runs.\n *\n * Earlier-source calls inside `ready` (this same re-plan) are excluded — the\n * sub-level packing orders them.\n */\nexport function conflictsWithUnsettledClaim(\n\tsourceIndex: number,\n\tfinalResolution: ToolClaimResolution,\n\tready: ReadonlySet<number>,\n\tsettled: ReadonlySet<number>,\n\trunning: ReadonlySet<number>,\n\tresolutions: ReadonlyMap<number, ToolClaimResolution>,\n): boolean {\n\tfor (const [otherIndex, resolution] of resolutions) {\n\t\tif (otherIndex === sourceIndex || settled.has(otherIndex)) continue;\n\t\tif (otherIndex < sourceIndex) {\n\t\t\tif (ready.has(otherIndex)) continue;\n\t\t} else if (!running.has(otherIndex)) {\n\t\t\t// Later-source and not running: source order wins, no constraint.\n\t\t\tcontinue;\n\t\t}\n\t\tif (resolutionsConflict(resolution, finalResolution)) return true;\n\t}\n\treturn false;\n}\n"]}
1
+ {"version":3,"file":"tool-dag-scheduler.d.ts","sourceRoot":"","sources":["../src/tool-dag-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EACN,KAAK,iBAAiB,EAGtB,KAAK,wBAAwB,EAG7B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,MAAM,2BAA2B,CAAC;AAEnC,sDAAsD;AACtD,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACzE;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC/B,4FAA4F;IAC5F,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;IACnB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACvC;AAED,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,mBAAmB,CAAC;IAChC,eAAe,EAAE,iBAAiB,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACvC,SAAS,EAAE,SAAS,iBAAiB,EAAE,EACvC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAQ/B;AAqDD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,EAAE,EAAE,CA6BlF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,EAAE,EAAE,CAoBxF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,EAAE,CAgBpG;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAU7E;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACtC,SAAS,EAAE,SAAS,iBAAiB,EAAE,EACvC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAK1B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAC1C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,mBAAmB,EACpC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,GACnD,OAAO,CAYT","sourcesContent":["/**\n * Pure, browser-safe deterministic resource-claim DAG scheduler.\n *\n * Given a source-ordered batch of tool calls and their resolved resource\n * claims, this module assigns each call after every earlier call it conflicts\n * with. Levels run in source order; calls inside one level are mutually\n * conflict-free and may execute concurrently. A positive `maxConcurrency`\n * width cap splits each level into deterministic contiguous source-ordered\n * chunks.\n *\n * Determinism contract:\n * - The level assignment is a pure function of the source-ordered input\n * claims. The canonical example is the head-of-line example\n * `write x, write x, write y`, which schedules as `[[0, 2], [1]]`: the second\n * write to `x` is pushed to level 1, but the independent write to `y` is not\n * blocked and joins level 0.\n * - Reordering claims *within* a single call does not change the plan: claims\n * are canonicalized (sorted, fixed property order) before comparison.\n * - {@link DagSchedulePlan.planKey} is a canonical serialization of the\n * resolved claim sequence (canonical claim data only — never execution\n * timing or outcomes). It is collision-free for distinct canonical claim\n * sequences.\n *\n * This module uses no platform APIs (no `process`, fs, `node:path`, or timers).\n */\n\nimport {\n\ttype ClaimableToolCall,\n\tcanonicalizeClaims,\n\tclaimsConflict,\n\ttype ResolveToolClaimsOptions,\n\tresolutionsConflict,\n\tresolveToolClaimsForCall,\n\ttype ToolClaimResolution,\n\ttype ToolResourceClaim,\n} from \"./tool-resource-claims.ts\";\n\n/** Options for scheduling a batch into DAG levels. */\nexport interface ScheduleDagLevelsOptions extends ResolveToolClaimsOptions {\n\t/**\n\t * Optional positive width cap. When set, each level is split into contiguous\n\t * source-ordered chunks of at most this many calls so a wide conflict-free\n\t * level does not fan out unbounded. Absent, non-finite, or non-positive\n\t * values leave each level whole. Does not affect `planKey`.\n\t */\n\tmaxConcurrency?: number;\n}\n\n/** A scheduled plan: ordered levels of source indices plus a canonical key. */\nexport interface DagSchedulePlan {\n\t/** Levels in execution order; each level holds source indices that may run concurrently. */\n\tlevels: number[][];\n\t/**\n\t * Canonical deterministic key over the resolved claim sequence only (never\n\t * execution timing/outcomes). Stable under claim reordering within a call.\n\t */\n\tplanKey: string;\n\t/**\n\t * The resolved, canonicalized claim entries the plan was built from. Callers\n\t * that re-resolve claims after argument mutation (e.g. authorization hooks)\n\t * compare against these to detect scope drift. Read-only for consumers.\n\t */\n\tentries: readonly ResolvedClaimEntry[];\n}\n\n/** One tool call's resolved claim data, canonicalized for stable planning. */\nexport interface ResolvedClaimEntry {\n\tsourceIndex: number;\n\tresolution: ToolClaimResolution;\n\tcanonicalClaims: ToolResourceClaim[];\n}\n\n/**\n * Resolve and canonicalize claims for a whole batch, preserving source order.\n * Registered custom resolvers are awaited one call at a time in source order,\n * and every resolution completes before a schedule is constructed.\n */\nexport async function resolveBatchClaims(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ResolveToolClaimsOptions,\n): Promise<ResolvedClaimEntry[]> {\n\tconst entries: ResolvedClaimEntry[] = [];\n\tfor (let index = 0; index < toolCalls.length; index++) {\n\t\tconst resolution = await resolveToolClaimsForCall(toolCalls[index], options);\n\t\tconst canonicalClaims = resolution.kind === \"claims\" ? canonicalizeClaims(resolution.claims) : [];\n\t\tentries.push({ sourceIndex: index, resolution, canonicalClaims });\n\t}\n\treturn entries;\n}\n\ninterface DagLevel {\n\tindices: number[];\n\t/** Write claims currently placed in this level (for fast read-vs-write checks). */\n\twriteClaims: ToolResourceClaim[];\n\t/** Read claims currently placed in this level (for fast write-vs-read checks). */\n\treadClaims: ToolResourceClaim[];\n\t/** True once an exclusive call is placed here; such a level accepts no more. */\n\thasExclusive: boolean;\n}\n\nfunction claimConflictsAny(claim: ToolResourceClaim, candidates: readonly ToolResourceClaim[]): boolean {\n\tfor (const candidate of candidates) {\n\t\tif (claimsConflict(claim, candidate)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * True when `resolution` cannot join `level`. Equivalent to the full pairwise\n * `resolutionsConflict` check, optimized so read/read never triggers a scan:\n * a read claim only needs to scan the level's writes, and a write claim scans\n * both writes and reads. An exclusive resolution, or a level that already holds\n * an exclusive call, conflicts unconditionally.\n */\nfunction resolutionConflictsLevel(resolution: ToolClaimResolution, level: DagLevel): boolean {\n\tif (level.hasExclusive) {\n\t\treturn true;\n\t}\n\tif (resolution.kind === \"exclusive\") {\n\t\treturn true;\n\t}\n\tfor (const claim of resolution.claims) {\n\t\tif (claim.access === \"exclusive\") {\n\t\t\treturn true;\n\t\t}\n\t\tif (claim.access === \"write\") {\n\t\t\tif (claimConflictsAny(claim, level.writeClaims)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (claimConflictsAny(claim, level.readClaims)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (claimConflictsAny(claim, level.writeClaims)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Assign each source-ordered claim entry one level after its latest earlier\n * conflict. Deterministic and stable: equal inputs (including claim reordering\n * within a call, which is canonicalized away) always produce equal levels, and\n * every directed conflict edge advances at least one level.\n */\nexport function assignDagLevels(entries: readonly ResolvedClaimEntry[]): number[][] {\n\tconst levels: DagLevel[] = [];\n\tfor (const entry of entries) {\n\t\tconst resolution = entry.resolution;\n\t\tlet targetIndex = 0;\n\t\tfor (let levelIndex = 0; levelIndex < levels.length; levelIndex++) {\n\t\t\tif (resolutionConflictsLevel(resolution, levels[levelIndex])) {\n\t\t\t\ttargetIndex = levelIndex + 1;\n\t\t\t}\n\t\t}\n\t\tlet target = levels[targetIndex];\n\t\tif (!target) {\n\t\t\ttarget = { indices: [], writeClaims: [], readClaims: [], hasExclusive: false };\n\t\t\tlevels.push(target);\n\t\t}\n\t\ttarget.indices.push(entry.sourceIndex);\n\t\tif (resolution.kind === \"exclusive\" || entry.canonicalClaims.some((claim) => claim.access === \"exclusive\")) {\n\t\t\ttarget.hasExclusive = true;\n\t\t} else {\n\t\t\tfor (const claim of entry.canonicalClaims) {\n\t\t\t\tif (claim.access === \"write\") {\n\t\t\t\t\ttarget.writeClaims.push(claim);\n\t\t\t\t} else {\n\t\t\t\t\ttarget.readClaims.push(claim);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn levels.map((level) => level.indices);\n}\n\n/**\n * Direct conflicting predecessors for each source-ordered entry: `result[i]`\n * lists every earlier position `i` must wait for.\n *\n * This is the precedence graph that {@link assignDagLevels} approximates with a\n * barrier schedule. Levels force every call in level N+1 to wait for ALL of\n * level N, so one slow unrelated call in a level delays the whole next level.\n * Dependency edges only connect calls that actually conflict, so a consumer can\n * start each call as soon as its own predecessors settle.\n *\n * Deterministic and stable: the result is a pure function of the source-ordered\n * canonicalized claims, and every list is ascending and strictly earlier-only.\n * Transitively-implied edges are kept rather than reduced — waiting on an\n * already-finished ancestor costs nothing and keeps this a simple pure scan.\n *\n * The graph is never deeper than the barrier schedule: for any `j` in\n * `result[i]`, `i` conflicts with an entry in level `j`, so\n * `level(i) >= level(j) + 1`, and depth follows by induction.\n */\nexport function assignDagDependencies(entries: readonly ResolvedClaimEntry[]): number[][] {\n\t// No edge can exist when every claim is read-only; avoid scanning every pair.\n\tif (\n\t\tentries.every(\n\t\t\t({ resolution }) =>\n\t\t\t\tresolution.kind === \"claims\" && resolution.claims.every((claim) => claim.access === \"read\"),\n\t\t)\n\t)\n\t\treturn entries.map(() => []);\n\tconst dependencies: number[][] = [];\n\tfor (let index = 0; index < entries.length; index++) {\n\t\tconst blockers: number[] = [];\n\t\tfor (let earlier = 0; earlier < index; earlier++) {\n\t\t\tif (resolutionsConflict(entries[earlier].resolution, entries[index].resolution)) {\n\t\t\t\tblockers.push(earlier);\n\t\t\t}\n\t\t}\n\t\tdependencies.push(blockers);\n\t}\n\treturn dependencies;\n}\n\n/**\n * Split each level into contiguous source-ordered chunks of at most `cap` calls.\n * Absent/non-finite/non-positive `cap` returns the levels unchanged.\n */\nexport function applyConcurrencyCap(levels: readonly number[][], cap: number | undefined): number[][] {\n\tif (typeof cap !== \"number\" || !Number.isFinite(cap) || cap <= 0) {\n\t\treturn levels.map((level) => level.slice());\n\t}\n\tconst integerCap = Math.max(1, Math.floor(cap));\n\tconst chunked: number[][] = [];\n\tfor (const level of levels) {\n\t\tif (level.length <= integerCap) {\n\t\t\tchunked.push(level.slice());\n\t\t\tcontinue;\n\t\t}\n\t\tfor (let start = 0; start < level.length; start += integerCap) {\n\t\t\tchunked.push(level.slice(start, start + integerCap));\n\t\t}\n\t}\n\treturn chunked;\n}\n\n/**\n * Canonical deterministic key over the resolved claim sequence. Uses\n * `JSON.stringify` of each call's canonicalized claims (fixed property order,\n * sorted) with an `\"E\"`/`\"C\"` discriminator, so it is collision-free for\n * distinct canonical claim sequences and stable under claim reordering within a\n * call. Contains no execution timing or outcomes.\n */\nexport function computePlanKey(entries: readonly ResolvedClaimEntry[]): string {\n\tlet key = \"\";\n\tfor (const entry of entries) {\n\t\tif (entry.resolution.kind === \"exclusive\") {\n\t\t\tkey += \"E,\";\n\t\t} else {\n\t\t\tkey += `C${JSON.stringify(entry.canonicalClaims)},`;\n\t\t}\n\t}\n\treturn key;\n}\n\n/**\n * Schedule a source-ordered tool-call batch into deterministic DAG levels.\n * Resolves default claims, computes source-directed dependency levels, applies\n * the optional width cap, and computes the canonical plan key. Pure and\n * deterministic.\n */\nexport async function scheduleDagLevels(\n\ttoolCalls: readonly ClaimableToolCall[],\n\toptions: ScheduleDagLevelsOptions,\n): Promise<DagSchedulePlan> {\n\tconst entries = await resolveBatchClaims(toolCalls, options);\n\tconst baseLevels = assignDagLevels(entries);\n\tconst levels = applyConcurrencyCap(baseLevels, options.maxConcurrency);\n\treturn { levels, planKey: computePlanKey(entries), entries };\n}\n\n/**\n * True when executing `sourceIndex` now would overlap an unsettled call whose\n * known claims conflict with `finalResolution`.\n *\n * Two distinct violations are covered:\n * - Earlier-source unsettled calls: the initial plan already ordered that\n * pair, so only post-hook scope drift can create the situation; the caller\n * defers the call instead of silently reversing the conflict pair.\n * - Later-source calls that are already running (present in `running`): a\n * hook that expands this call's scope onto their claims must defer — the\n * running call cannot be un-started. Later-source calls that are merely\n * pending keep source order: they may not overlap this call once it runs.\n *\n * Earlier-source calls inside `ready` (this same re-plan) are excluded — the\n * sub-level packing orders them.\n */\nexport function conflictsWithUnsettledClaim(\n\tsourceIndex: number,\n\tfinalResolution: ToolClaimResolution,\n\tready: ReadonlySet<number>,\n\tsettled: ReadonlySet<number>,\n\trunning: ReadonlySet<number>,\n\tresolutions: ReadonlyMap<number, ToolClaimResolution>,\n): boolean {\n\tfor (const [otherIndex, resolution] of resolutions) {\n\t\tif (otherIndex === sourceIndex || settled.has(otherIndex)) continue;\n\t\tif (otherIndex < sourceIndex) {\n\t\t\tif (ready.has(otherIndex)) continue;\n\t\t} else if (!running.has(otherIndex)) {\n\t\t\t// Later-source and not running: source order wins, no constraint.\n\t\t\tcontinue;\n\t\t}\n\t\tif (resolutionsConflict(resolution, finalResolution)) return true;\n\t}\n\treturn false;\n}\n"]}
@@ -136,6 +136,9 @@ export function assignDagLevels(entries) {
136
136
  * `level(i) >= level(j) + 1`, and depth follows by induction.
137
137
  */
138
138
  export function assignDagDependencies(entries) {
139
+ // No edge can exist when every claim is read-only; avoid scanning every pair.
140
+ if (entries.every(({ resolution }) => resolution.kind === "claims" && resolution.claims.every((claim) => claim.access === "read")))
141
+ return entries.map(() => []);
139
142
  const dependencies = [];
140
143
  for (let index = 0; index < entries.length; index++) {
141
144
  const blockers = [];