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":"tool-dag-scheduler.js","sourceRoot":"","sources":["../src/tool-dag-scheduler.ts"],"names":[],"mappings":"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","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.js","sourceRoot":"","sources":["../src/tool-dag-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAEN,kBAAkB,EAClB,cAAc,EAEd,mBAAmB,EACnB,wBAAwB,GAGxB,MAAM,2BAA2B,CAAC;AAqCnC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,SAAuC,EACvC,OAAiC,EACD;IAChC,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACvD,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAC7E,MAAM,eAAe,GAAG,UAAU,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClG,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAYD,SAAS,iBAAiB,CAAC,KAAwB,EAAE,UAAwC,EAAW;IACvG,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,IAAI,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;;;;;GAMG;AACH,SAAS,wBAAwB,CAAC,UAA+B,EAAE,KAAe,EAAW;IAC5F,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC9B,IAAI,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;gBACjD,OAAO,IAAI,CAAC;YACb,CAAC;YACD,IAAI,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChD,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;aAAM,IAAI,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAsC,EAAc;IACnF,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QACpC,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC;YACnE,IAAI,wBAAwB,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;gBAC9D,WAAW,GAAG,UAAU,GAAG,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QACD,IAAI,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;YAC/E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACvC,IAAI,UAAU,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC,EAAE,CAAC;YAC5G,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC;QAC5B,CAAC;aAAM,CAAC;YACP,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBAC9B,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACP,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC/B,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAAA,CAC5C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAsC,EAAc;IACzF,8EAA8E;IAC9E,IACC,OAAO,CAAC,KAAK,CACZ,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAClB,UAAU,CAAC,IAAI,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAC5F;QAED,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,YAAY,GAAe,EAAE,CAAC;IACpC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACrD,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YAClD,IAAI,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;gBACjF,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxB,CAAC;QACF,CAAC;QACD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,YAAY,CAAC;AAAA,CACpB;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAA2B,EAAE,GAAuB,EAAc;IACrG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QAClE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAC5B,SAAS;QACV,CAAC;QACD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC;QACtD,CAAC;IACF,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAAsC,EAAU;IAC9E,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC3C,GAAG,IAAI,IAAI,CAAC;QACb,CAAC;aAAM,CAAC;YACP,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC;QACrD,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,SAAuC,EACvC,OAAiC,EACN;IAC3B,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACvE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;AAAA,CAC7D;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,2BAA2B,CAC1C,WAAmB,EACnB,eAAoC,EACpC,KAA0B,EAC1B,OAA4B,EAC5B,OAA4B,EAC5B,WAAqD,EAC3C;IACV,KAAK,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,IAAI,WAAW,EAAE,CAAC;QACpD,IAAI,UAAU,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,SAAS;QACpE,IAAI,UAAU,GAAG,WAAW,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,SAAS;QACrC,CAAC;aAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,kEAAkE;YAClE,SAAS;QACV,CAAC;QACD,IAAI,mBAAmB,CAAC,UAAU,EAAE,eAAe,CAAC;YAAE,OAAO,IAAI,CAAC;IACnE,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omk-agent-core",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
4
4
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "prepublishOnly": "npm run clean && npm run build"
31
31
  },
32
32
  "dependencies": {
33
- "omk-ai": "^1.2.0",
33
+ "omk-ai": "^1.2.3",
34
34
  "ignore": "7.0.6",
35
35
  "typebox": "1.3.11",
36
36
  "yaml": "2.9.0"