qlogicagent 0.2.1 → 0.3.0

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 (229) hide show
  1. package/dist/agent.js +1 -0
  2. package/dist/cli.js +9 -0
  3. package/dist/contracts.js +1 -0
  4. package/dist/index.js +5 -15
  5. package/dist/orchestration.js +118 -0
  6. package/package.json +56 -42
  7. package/dist/agent/agent.js +0 -113
  8. package/dist/agent/tool-loop.js +0 -575
  9. package/dist/agent/types.js +0 -14
  10. package/dist/cli/main.js +0 -23
  11. package/dist/cli/stdio-server.js +0 -463
  12. package/dist/config/config.js +0 -21
  13. package/dist/contracts/hooks.js +0 -7
  14. package/dist/contracts/index.js +0 -10
  15. package/dist/contracts/planner.js +0 -2
  16. package/dist/contracts/skill-candidate.js +0 -195
  17. package/dist/contracts/todo.js +0 -9
  18. package/dist/llm/builtin-providers.js +0 -531
  19. package/dist/llm/index.js +0 -14
  20. package/dist/llm/llm-client.js +0 -67
  21. package/dist/llm/model-catalog.js +0 -191
  22. package/dist/llm/provider-def.js +0 -12
  23. package/dist/llm/provider-registry.js +0 -147
  24. package/dist/llm/transport.js +0 -27
  25. package/dist/llm/transports/anthropic-messages.js +0 -293
  26. package/dist/llm/transports/openai-chat.js +0 -165
  27. package/dist/orchestration/agent-registry.js +0 -116
  28. package/dist/orchestration/approval-aware-tool-plan.js +0 -87
  29. package/dist/orchestration/context-compression.js +0 -583
  30. package/dist/orchestration/conversation-repair.js +0 -429
  31. package/dist/orchestration/curator-scheduler.js +0 -135
  32. package/dist/orchestration/embedded-failover-policy.js +0 -168
  33. package/dist/orchestration/error-classification.js +0 -77
  34. package/dist/orchestration/failover-classification.js +0 -381
  35. package/dist/orchestration/failover-error.js +0 -198
  36. package/dist/orchestration/fork-subagent.js +0 -98
  37. package/dist/orchestration/index.js +0 -267
  38. package/dist/orchestration/memory-flush-policy.js +0 -85
  39. package/dist/orchestration/memory-provider.js +0 -2
  40. package/dist/orchestration/parallel-tool-calls.js +0 -59
  41. package/dist/orchestration/prompt-cache-strategy.js +0 -228
  42. package/dist/orchestration/reactive-compact.js +0 -78
  43. package/dist/orchestration/retry-loop.js +0 -24
  44. package/dist/orchestration/skill-candidate.js +0 -141
  45. package/dist/orchestration/skill-consolidation.js +0 -220
  46. package/dist/orchestration/skill-improvement.js +0 -66
  47. package/dist/orchestration/skill-similarity.js +0 -131
  48. package/dist/orchestration/streaming-tool-executor.js +0 -96
  49. package/dist/orchestration/team-orchestration.js +0 -369
  50. package/dist/orchestration/team-tool-loop-wiring.js +0 -147
  51. package/dist/orchestration/tool-choice-policy.js +0 -164
  52. package/dist/orchestration/tool-loop-state.js +0 -133
  53. package/dist/orchestration/tool-schema.js +0 -297
  54. package/dist/orchestration/transcript-repair.js +0 -426
  55. package/dist/orchestration/turn-loop-guard.js +0 -92
  56. package/dist/orchestration/web-browser-policy.js +0 -39
  57. package/dist/runtime/context-compression.js +0 -274
  58. package/dist/runtime/hook-registry.js +0 -53
  59. package/dist/runtime/memory-hooks.js +0 -65
  60. package/dist/runtime/tool-eligibility.js +0 -111
  61. package/dist/skills/index.js +0 -82
  62. package/dist/skills/memory-extractor.js +0 -173
  63. package/dist/skills/memory-query-tool.js +0 -127
  64. package/dist/skills/memory-store.js +0 -228
  65. package/dist/skills/memory-tool.js +0 -192
  66. package/dist/skills/portable-tool.js +0 -14
  67. package/dist/skills/qmemory-adapter.js +0 -165
  68. package/dist/skills/skill-frontmatter.js +0 -344
  69. package/dist/skills/skill-guard.js +0 -229
  70. package/dist/skills/skill-loader.js +0 -303
  71. package/dist/skills/skill-source.js +0 -126
  72. package/dist/skills/skill-types.js +0 -6
  73. package/dist/skills/think-tool.js +0 -59
  74. package/dist/skills/todo-tool.js +0 -114
  75. package/dist/skills/tools/agent-tool.js +0 -142
  76. package/dist/skills/tools/apply-patch-tool.js +0 -184
  77. package/dist/skills/tools/ask-user-tool.js +0 -121
  78. package/dist/skills/tools/brief-tool.js +0 -95
  79. package/dist/skills/tools/browser-tool.js +0 -155
  80. package/dist/skills/tools/checkpoint-tool.js +0 -102
  81. package/dist/skills/tools/config-tool.js +0 -143
  82. package/dist/skills/tools/cron-tool.js +0 -175
  83. package/dist/skills/tools/edit-tool.js +0 -70
  84. package/dist/skills/tools/exec-tool.js +0 -133
  85. package/dist/skills/tools/image-generate-tool.js +0 -67
  86. package/dist/skills/tools/instructions-tool.js +0 -187
  87. package/dist/skills/tools/lsp-tool.js +0 -227
  88. package/dist/skills/tools/mcp-client-types.js +0 -53
  89. package/dist/skills/tools/mcp-tool.js +0 -503
  90. package/dist/skills/tools/memory-tool.js +0 -88
  91. package/dist/skills/tools/monitor-tool.js +0 -131
  92. package/dist/skills/tools/music-generate-tool.js +0 -62
  93. package/dist/skills/tools/notify-tool.js +0 -62
  94. package/dist/skills/tools/patch-tool.js +0 -505
  95. package/dist/skills/tools/pdf-tool.js +0 -88
  96. package/dist/skills/tools/plan-mode-tool.js +0 -122
  97. package/dist/skills/tools/read-tool.js +0 -84
  98. package/dist/skills/tools/repl-tool.js +0 -69
  99. package/dist/skills/tools/search-tool.js +0 -225
  100. package/dist/skills/tools/send-message-tool.js +0 -76
  101. package/dist/skills/tools/skill-list-tool.js +0 -54
  102. package/dist/skills/tools/skill-manage-tool.js +0 -153
  103. package/dist/skills/tools/skill-view-tool.js +0 -72
  104. package/dist/skills/tools/sleep-tool.js +0 -81
  105. package/dist/skills/tools/structured-output-tool.js +0 -176
  106. package/dist/skills/tools/task-tool.js +0 -161
  107. package/dist/skills/tools/team-tool.js +0 -105
  108. package/dist/skills/tools/tool-search-tool.js +0 -110
  109. package/dist/skills/tools/tts-tool.js +0 -45
  110. package/dist/skills/tools/video-edit-tool.js +0 -74
  111. package/dist/skills/tools/video-generate-tool.js +0 -66
  112. package/dist/skills/tools/video-merge-tool.js +0 -92
  113. package/dist/skills/tools/video-upscale-tool.js +0 -52
  114. package/dist/skills/tools/web-fetch-tool.js +0 -92
  115. package/dist/skills/tools/web-search-tool.js +0 -86
  116. package/dist/skills/tools/worktree-tool.js +0 -147
  117. package/dist/skills/tools/write-tool.js +0 -81
  118. /package/dist/{agent → types/agent}/agent.d.ts +0 -0
  119. /package/dist/{agent → types/agent}/tool-loop.d.ts +0 -0
  120. /package/dist/{agent → types/agent}/types.d.ts +0 -0
  121. /package/dist/{cli → types/cli}/main.d.ts +0 -0
  122. /package/dist/{cli → types/cli}/stdio-server.d.ts +0 -0
  123. /package/dist/{config → types/config}/config.d.ts +0 -0
  124. /package/dist/{contracts → types/contracts}/hooks.d.ts +0 -0
  125. /package/dist/{contracts → types/contracts}/index.d.ts +0 -0
  126. /package/dist/{contracts → types/contracts}/planner.d.ts +0 -0
  127. /package/dist/{contracts → types/contracts}/skill-candidate.d.ts +0 -0
  128. /package/dist/{contracts → types/contracts}/todo.d.ts +0 -0
  129. /package/dist/{index.d.ts → types/index.d.ts} +0 -0
  130. /package/dist/{llm → types/llm}/builtin-providers.d.ts +0 -0
  131. /package/dist/{llm → types/llm}/index.d.ts +0 -0
  132. /package/dist/{llm → types/llm}/llm-client.d.ts +0 -0
  133. /package/dist/{llm → types/llm}/model-catalog.d.ts +0 -0
  134. /package/dist/{llm → types/llm}/provider-def.d.ts +0 -0
  135. /package/dist/{llm → types/llm}/provider-registry.d.ts +0 -0
  136. /package/dist/{llm → types/llm}/transport.d.ts +0 -0
  137. /package/dist/{llm → types/llm}/transports/anthropic-messages.d.ts +0 -0
  138. /package/dist/{llm → types/llm}/transports/openai-chat.d.ts +0 -0
  139. /package/dist/{orchestration → types/orchestration}/agent-registry.d.ts +0 -0
  140. /package/dist/{orchestration → types/orchestration}/approval-aware-tool-plan.d.ts +0 -0
  141. /package/dist/{orchestration → types/orchestration}/context-compression.d.ts +0 -0
  142. /package/dist/{orchestration → types/orchestration}/conversation-repair.d.ts +0 -0
  143. /package/dist/{orchestration → types/orchestration}/curator-scheduler.d.ts +0 -0
  144. /package/dist/{orchestration → types/orchestration}/embedded-failover-policy.d.ts +0 -0
  145. /package/dist/{orchestration → types/orchestration}/error-classification.d.ts +0 -0
  146. /package/dist/{orchestration → types/orchestration}/failover-classification.d.ts +0 -0
  147. /package/dist/{orchestration → types/orchestration}/failover-error.d.ts +0 -0
  148. /package/dist/{orchestration → types/orchestration}/fork-subagent.d.ts +0 -0
  149. /package/dist/{orchestration → types/orchestration}/index.d.ts +0 -0
  150. /package/dist/{orchestration → types/orchestration}/memory-flush-policy.d.ts +0 -0
  151. /package/dist/{orchestration → types/orchestration}/memory-provider.d.ts +0 -0
  152. /package/dist/{orchestration → types/orchestration}/parallel-tool-calls.d.ts +0 -0
  153. /package/dist/{orchestration → types/orchestration}/prompt-cache-strategy.d.ts +0 -0
  154. /package/dist/{orchestration → types/orchestration}/reactive-compact.d.ts +0 -0
  155. /package/dist/{orchestration → types/orchestration}/retry-loop.d.ts +0 -0
  156. /package/dist/{orchestration → types/orchestration}/skill-candidate.d.ts +0 -0
  157. /package/dist/{orchestration → types/orchestration}/skill-consolidation.d.ts +0 -0
  158. /package/dist/{orchestration → types/orchestration}/skill-improvement.d.ts +0 -0
  159. /package/dist/{orchestration → types/orchestration}/skill-similarity.d.ts +0 -0
  160. /package/dist/{orchestration → types/orchestration}/streaming-tool-executor.d.ts +0 -0
  161. /package/dist/{orchestration → types/orchestration}/team-orchestration.d.ts +0 -0
  162. /package/dist/{orchestration → types/orchestration}/team-tool-loop-wiring.d.ts +0 -0
  163. /package/dist/{orchestration → types/orchestration}/tool-choice-policy.d.ts +0 -0
  164. /package/dist/{orchestration → types/orchestration}/tool-loop-state.d.ts +0 -0
  165. /package/dist/{orchestration → types/orchestration}/tool-schema.d.ts +0 -0
  166. /package/dist/{orchestration → types/orchestration}/transcript-repair.d.ts +0 -0
  167. /package/dist/{orchestration → types/orchestration}/turn-loop-guard.d.ts +0 -0
  168. /package/dist/{orchestration → types/orchestration}/web-browser-policy.d.ts +0 -0
  169. /package/dist/{runtime → types/runtime}/context-compression.d.ts +0 -0
  170. /package/dist/{runtime → types/runtime}/hook-registry.d.ts +0 -0
  171. /package/dist/{runtime → types/runtime}/memory-hooks.d.ts +0 -0
  172. /package/dist/{runtime → types/runtime}/tool-eligibility.d.ts +0 -0
  173. /package/dist/{skills → types/skills}/index.d.ts +0 -0
  174. /package/dist/{skills → types/skills}/memory-extractor.d.ts +0 -0
  175. /package/dist/{skills → types/skills}/memory-query-tool.d.ts +0 -0
  176. /package/dist/{skills → types/skills}/memory-store.d.ts +0 -0
  177. /package/dist/{skills → types/skills}/memory-tool.d.ts +0 -0
  178. /package/dist/{skills → types/skills}/portable-tool.d.ts +0 -0
  179. /package/dist/{skills → types/skills}/qmemory-adapter.d.ts +0 -0
  180. /package/dist/{skills → types/skills}/skill-frontmatter.d.ts +0 -0
  181. /package/dist/{skills → types/skills}/skill-guard.d.ts +0 -0
  182. /package/dist/{skills → types/skills}/skill-loader.d.ts +0 -0
  183. /package/dist/{skills → types/skills}/skill-source.d.ts +0 -0
  184. /package/dist/{skills → types/skills}/skill-types.d.ts +0 -0
  185. /package/dist/{skills → types/skills}/think-tool.d.ts +0 -0
  186. /package/dist/{skills → types/skills}/todo-tool.d.ts +0 -0
  187. /package/dist/{skills → types/skills}/tools/agent-tool.d.ts +0 -0
  188. /package/dist/{skills → types/skills}/tools/apply-patch-tool.d.ts +0 -0
  189. /package/dist/{skills → types/skills}/tools/ask-user-tool.d.ts +0 -0
  190. /package/dist/{skills → types/skills}/tools/brief-tool.d.ts +0 -0
  191. /package/dist/{skills → types/skills}/tools/browser-tool.d.ts +0 -0
  192. /package/dist/{skills → types/skills}/tools/checkpoint-tool.d.ts +0 -0
  193. /package/dist/{skills → types/skills}/tools/config-tool.d.ts +0 -0
  194. /package/dist/{skills → types/skills}/tools/cron-tool.d.ts +0 -0
  195. /package/dist/{skills → types/skills}/tools/edit-tool.d.ts +0 -0
  196. /package/dist/{skills → types/skills}/tools/exec-tool.d.ts +0 -0
  197. /package/dist/{skills → types/skills}/tools/image-generate-tool.d.ts +0 -0
  198. /package/dist/{skills → types/skills}/tools/instructions-tool.d.ts +0 -0
  199. /package/dist/{skills → types/skills}/tools/lsp-tool.d.ts +0 -0
  200. /package/dist/{skills → types/skills}/tools/mcp-client-types.d.ts +0 -0
  201. /package/dist/{skills → types/skills}/tools/mcp-tool.d.ts +0 -0
  202. /package/dist/{skills → types/skills}/tools/memory-tool.d.ts +0 -0
  203. /package/dist/{skills → types/skills}/tools/monitor-tool.d.ts +0 -0
  204. /package/dist/{skills → types/skills}/tools/music-generate-tool.d.ts +0 -0
  205. /package/dist/{skills → types/skills}/tools/notify-tool.d.ts +0 -0
  206. /package/dist/{skills → types/skills}/tools/patch-tool.d.ts +0 -0
  207. /package/dist/{skills → types/skills}/tools/pdf-tool.d.ts +0 -0
  208. /package/dist/{skills → types/skills}/tools/plan-mode-tool.d.ts +0 -0
  209. /package/dist/{skills → types/skills}/tools/read-tool.d.ts +0 -0
  210. /package/dist/{skills → types/skills}/tools/repl-tool.d.ts +0 -0
  211. /package/dist/{skills → types/skills}/tools/search-tool.d.ts +0 -0
  212. /package/dist/{skills → types/skills}/tools/send-message-tool.d.ts +0 -0
  213. /package/dist/{skills → types/skills}/tools/skill-list-tool.d.ts +0 -0
  214. /package/dist/{skills → types/skills}/tools/skill-manage-tool.d.ts +0 -0
  215. /package/dist/{skills → types/skills}/tools/skill-view-tool.d.ts +0 -0
  216. /package/dist/{skills → types/skills}/tools/sleep-tool.d.ts +0 -0
  217. /package/dist/{skills → types/skills}/tools/structured-output-tool.d.ts +0 -0
  218. /package/dist/{skills → types/skills}/tools/task-tool.d.ts +0 -0
  219. /package/dist/{skills → types/skills}/tools/team-tool.d.ts +0 -0
  220. /package/dist/{skills → types/skills}/tools/tool-search-tool.d.ts +0 -0
  221. /package/dist/{skills → types/skills}/tools/tts-tool.d.ts +0 -0
  222. /package/dist/{skills → types/skills}/tools/video-edit-tool.d.ts +0 -0
  223. /package/dist/{skills → types/skills}/tools/video-generate-tool.d.ts +0 -0
  224. /package/dist/{skills → types/skills}/tools/video-merge-tool.d.ts +0 -0
  225. /package/dist/{skills → types/skills}/tools/video-upscale-tool.d.ts +0 -0
  226. /package/dist/{skills → types/skills}/tools/web-fetch-tool.d.ts +0 -0
  227. /package/dist/{skills → types/skills}/tools/web-search-tool.d.ts +0 -0
  228. /package/dist/{skills → types/skills}/tools/worktree-tool.d.ts +0 -0
  229. /package/dist/{skills → types/skills}/tools/write-tool.d.ts +0 -0
@@ -1,59 +0,0 @@
1
- export function normalizeParallelToolCallsPreference(rawValue) {
2
- if (rawValue === undefined) {
3
- return undefined;
4
- }
5
- if (typeof rawValue === "boolean") {
6
- return { kind: "enabled", enabled: rawValue };
7
- }
8
- if (rawValue === null) {
9
- return { kind: "suppressed" };
10
- }
11
- return {
12
- kind: "invalid",
13
- summary: typeof rawValue === "string" ? rawValue : typeof rawValue,
14
- };
15
- }
16
- export function resolveParallelToolCallScheduling(params) {
17
- const warnings = [];
18
- const preference = normalizeParallelToolCallsPreference(params.requestedPreference);
19
- const capabilityMap = new Map((params.toolCapabilities ?? []).map((capability) => [capability.name, capability]));
20
- let enabled = params.providerSupportsParallel !== false;
21
- if (preference?.kind === "enabled") {
22
- enabled = preference.enabled && params.providerSupportsParallel !== false;
23
- }
24
- else if (preference?.kind === "suppressed") {
25
- enabled = false;
26
- }
27
- else if (preference?.kind === "invalid") {
28
- warnings.push(`ignoring invalid parallel_tool_calls param: ${preference.summary}`);
29
- }
30
- if (enabled && params.providerSupportsParallel === false) {
31
- warnings.push("provider does not support parallel tool calls; downgraded to serial execution.");
32
- }
33
- const batches = [];
34
- let currentParallelBatch = [];
35
- const flushParallelBatch = () => {
36
- if (currentParallelBatch.length === 0) {
37
- return;
38
- }
39
- batches.push({ mode: "parallel", calls: currentParallelBatch });
40
- currentParallelBatch = [];
41
- };
42
- for (const toolCall of params.toolCalls) {
43
- const capability = capabilityMap.get(toolCall.function.name);
44
- const mustSerialize = !enabled || capability?.requiresApproval === true || capability?.serialOnly === true || capability?.parallelSafe === false || capability?.approvalMode === "user-confirm";
45
- if (mustSerialize) {
46
- flushParallelBatch();
47
- batches.push({ mode: "serial", calls: [toolCall] });
48
- continue;
49
- }
50
- currentParallelBatch.push(toolCall);
51
- }
52
- flushParallelBatch();
53
- return {
54
- enabled,
55
- mode: batches.some((batch) => batch.mode === "parallel" && batch.calls.length > 1) ? "parallel" : "serial",
56
- batches,
57
- warnings,
58
- };
59
- }
@@ -1,228 +0,0 @@
1
- // ============================================================
2
- // Prompt cache marking strategy — identify optimal breakpoints
3
- // in a message array for provider-level prefix caching.
4
- //
5
- // Providers like Anthropic cache message prefixes: if consecutive
6
- // requests share identical leading messages, the cached portion
7
- // skips re-tokenization and re-processing. The strategy here
8
- // decides WHERE to place cache breakpoints (up to maxBreakpoints)
9
- // to maximise prefix reuse across turns.
10
- // ============================================================
11
- // ── Defaults ────────────────────────────────────────────────
12
- export const DEFAULT_PROMPT_CACHE_POLICY = {
13
- maxBreakpoints: 4,
14
- retention: "short",
15
- minSegmentTokens: 256,
16
- recentTailCount: 2,
17
- markToolDefinitions: true,
18
- };
19
- // ── Core strategy ───────────────────────────────────────────
20
- /**
21
- * Analyse a message array and return recommended cache breakpoints.
22
- *
23
- * The algorithm:
24
- * 1. Classify each message into segments (system / tool-def / conversation / recent).
25
- * 2. Identify segment boundaries where the classification changes.
26
- * 3. Rank boundaries by estimated token cost (heaviest first).
27
- * 4. Select the top `maxBreakpoints` that meet `minSegmentTokens`.
28
- *
29
- * @param messages The conversation message array (in order).
30
- * @param estimateTokens Optional per-message token estimator. Falls back to
31
- * character-length heuristic (1 token ≈ 4 chars).
32
- * @param policy Cache marking policy (uses defaults if omitted).
33
- */
34
- export function computeCacheBreakpoints(messages, estimateTokens, policy = {}) {
35
- const p = { ...DEFAULT_PROMPT_CACHE_POLICY, ...policy };
36
- const estimate = estimateTokens ?? defaultTokenEstimator;
37
- if (p.retention === "none" || messages.length === 0) {
38
- return { breakpoints: [], estimatedCacheableTokens: 0, retention: p.retention };
39
- }
40
- // Classify every message
41
- const recentStart = Math.max(0, messages.length - p.recentTailCount);
42
- const classified = messages.map((msg, i) => ({
43
- index: i,
44
- kind: i >= recentStart ? "recent" : classifyMessage(msg, p),
45
- tokens: estimate(msg),
46
- }));
47
- // Build contiguous segments by kind
48
- const segments = [];
49
- let current;
50
- for (const entry of classified) {
51
- if (!current || current.kind !== entry.kind) {
52
- if (current)
53
- segments.push(current);
54
- current = { kind: entry.kind, startIndex: entry.index, endIndex: entry.index, tokens: entry.tokens };
55
- }
56
- else {
57
- current.endIndex = entry.index;
58
- current.tokens += entry.tokens;
59
- }
60
- }
61
- if (current)
62
- segments.push(current);
63
- // Candidate breakpoints: end of each non-recent segment meeting the threshold
64
- const candidates = [];
65
- for (const seg of segments) {
66
- if (seg.kind === "recent")
67
- continue;
68
- if (seg.tokens < p.minSegmentTokens)
69
- continue;
70
- candidates.push({
71
- index: seg.endIndex,
72
- segment: seg.kind,
73
- estimatedTokens: seg.tokens,
74
- });
75
- }
76
- // Rank by tokens descending, pick top N
77
- candidates.sort((a, b) => (b.estimatedTokens ?? 0) - (a.estimatedTokens ?? 0));
78
- const selected = candidates.slice(0, p.maxBreakpoints);
79
- // Re-sort by index ascending for stable output
80
- selected.sort((a, b) => a.index - b.index);
81
- const estimatedCacheableTokens = selected.reduce((sum, bp) => sum + (bp.estimatedTokens ?? 0), 0);
82
- return { breakpoints: selected, estimatedCacheableTokens, retention: p.retention };
83
- }
84
- /**
85
- * Apply cache_control markers to a mutable message array based on breakpoints.
86
- *
87
- * For each breakpoint index, the last content block of that message gets a
88
- * `cache_control: { type: "ephemeral" }` annotation (Anthropic format).
89
- * String content is promoted to a text content block array.
90
- *
91
- * This is a pure transform — it returns a new array with shallow-cloned messages.
92
- */
93
- export function applyCacheMarkers(messages, breakpoints) {
94
- const bpSet = new Set(breakpoints.map((bp) => bp.index));
95
- return messages.map((msg, i) => {
96
- if (!bpSet.has(i))
97
- return msg;
98
- return injectCacheControl(msg);
99
- });
100
- }
101
- /**
102
- * Estimate the cache savings ratio for a turn.
103
- *
104
- * @param totalTokens Total input tokens for the turn.
105
- * @param cacheableTokens Tokens covered by cache breakpoints.
106
- * @param cacheHitRatio Fraction of cacheable tokens actually served from cache (0–1).
107
- * @returns Estimated fraction of input tokens saved (0–1).
108
- */
109
- export function estimateCacheSavingsRatio(totalTokens, cacheableTokens, cacheHitRatio = 1) {
110
- if (totalTokens <= 0 || cacheableTokens <= 0)
111
- return 0;
112
- return Math.min(1, (cacheableTokens * Math.max(0, Math.min(1, cacheHitRatio))) / totalTokens);
113
- }
114
- // ── Helpers ─────────────────────────────────────────────────
115
- function classifyMessage(msg, policy) {
116
- const role = msg.role;
117
- if (role === "system" || role === "developer")
118
- return "system";
119
- if (policy.markToolDefinitions && role === "tool")
120
- return "conversation";
121
- // Tool-call results are part of conversation flow
122
- if (msg.tool_call_id)
123
- return "conversation";
124
- return "conversation";
125
- }
126
- function defaultTokenEstimator(msg) {
127
- const content = msg.content;
128
- if (typeof content === "string")
129
- return Math.ceil(content.length / 4);
130
- if (Array.isArray(content)) {
131
- let chars = 0;
132
- for (const part of content) {
133
- if (typeof part === "string")
134
- chars += part.length;
135
- else if (part && typeof part === "object" && "text" in part) {
136
- chars += typeof part.text === "string"
137
- ? (part.text).length
138
- : 0;
139
- }
140
- }
141
- return Math.ceil(chars / 4);
142
- }
143
- return 0;
144
- }
145
- function injectCacheControl(msg) {
146
- const clone = { ...msg };
147
- const content = clone.content;
148
- if (typeof content === "string") {
149
- // Promote string to text content block with cache_control
150
- clone.content = [
151
- { type: "text", text: content, cache_control: { type: "ephemeral" } },
152
- ];
153
- }
154
- else if (Array.isArray(content) && content.length > 0) {
155
- const newContent = content.map((part, idx) => {
156
- if (idx !== content.length - 1)
157
- return part;
158
- if (part && typeof part === "object") {
159
- return { ...part, cache_control: { type: "ephemeral" } };
160
- }
161
- return part;
162
- });
163
- clone.content = newContent;
164
- }
165
- return clone;
166
- }
167
- // ── CC-aligned Fork Prefix Cache ────────────────────────────
168
- /**
169
- * Determine the optimal cache marker position for fork scenarios.
170
- *
171
- * CC pattern:
172
- * - Normal request: marker on messages[length - 1] (last message)
173
- * - Fork (skipCacheWrite): marker on messages[length - 2] (shared prefix point)
174
- *
175
- * This ensures all fork children produce byte-identical API request prefix up to
176
- * the marker, maximising cache reuse.
177
- */
178
- export function resolveForkCacheMarkerIndex(messagesLength, options = {}) {
179
- if (messagesLength <= 0)
180
- return -1;
181
- if (options.skipCacheWrite || options.isForkChild) {
182
- // Fork children: marker goes on the shared prefix (second-to-last message)
183
- return Math.max(0, messagesLength - 2);
184
- }
185
- // Normal: marker on last message
186
- return messagesLength - 1;
187
- }
188
- export function createCacheBreakDetectionState() {
189
- return { systemHash: null, toolsHash: null, modelId: null, thinkingEnabled: null };
190
- }
191
- /**
192
- * Detect if a cache break has occurred by comparing current request properties
193
- * against the last known state.
194
- *
195
- * Returns the list of fields that changed (empty = no break).
196
- */
197
- export function detectCacheBreaks(state, current) {
198
- const events = [];
199
- if (state.systemHash !== null && state.systemHash !== current.systemHash) {
200
- events.push({ field: "system", previousHash: state.systemHash, currentHash: current.systemHash });
201
- }
202
- if (state.toolsHash !== null && state.toolsHash !== current.toolsHash) {
203
- events.push({ field: "tools", previousHash: state.toolsHash, currentHash: current.toolsHash });
204
- }
205
- if (state.modelId !== null && state.modelId !== current.modelId) {
206
- events.push({ field: "model", previousHash: state.modelId, currentHash: current.modelId });
207
- }
208
- if (state.thinkingEnabled !== null && state.thinkingEnabled !== current.thinkingEnabled) {
209
- events.push({ field: "thinking", previousHash: String(state.thinkingEnabled), currentHash: String(current.thinkingEnabled) });
210
- }
211
- // Update state
212
- state.systemHash = current.systemHash;
213
- state.toolsHash = current.toolsHash;
214
- state.modelId = current.modelId;
215
- state.thinkingEnabled = current.thinkingEnabled;
216
- return events;
217
- }
218
- /**
219
- * Compute a lightweight hash for cache break detection.
220
- * Uses DJB2 algorithm (fast, good distribution for strings).
221
- */
222
- export function quickHash(input) {
223
- let hash = 5381;
224
- for (let i = 0; i < input.length; i++) {
225
- hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0;
226
- }
227
- return (hash >>> 0).toString(36);
228
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * Reactive Compact — Emergency context compression when API returns prompt-too-long.
3
- *
4
- * Aligned with Claude Code's reactive compact chain:
5
- * 1. API 413 → withhold error → attempt reactive compact → retry
6
- * 2. Only one reactive compact attempt per turn (prevent infinite loops)
7
- * 3. Falls back to abort if compact fails
8
- *
9
- * Also handles post-compact restoration:
10
- * - Todo list re-injection
11
- * - Skill context re-injection
12
- * - Tool delta re-injection (new/removed tools since last compact)
13
- */
14
- export const DEFAULT_REACTIVE_COMPACT_CONFIG = {
15
- maxConsecutiveFailures: 3,
16
- minMessagesAfterCompact: 4,
17
- targetUsagePercent: 50,
18
- };
19
- /**
20
- * Build the restoration message to inject after a compact operation.
21
- * This ensures critical state survives context compression.
22
- */
23
- export function buildPostCompactRestorationMessage(payload) {
24
- const sections = [];
25
- if (payload.todoList && payload.todoList.length > 0) {
26
- const todoLines = payload.todoList.map((t) => ` ${t.status === "completed" ? "[x]" : t.status === "in-progress" ? "[~]" : "[ ]"} #${t.id}: ${t.title}`);
27
- sections.push(`## Active Todo List\n${todoLines.join("\n")}`);
28
- }
29
- if (payload.activeSkillContext) {
30
- sections.push(`## Active Skill: ${payload.activeSkillContext.name}\nStep ${payload.activeSkillContext.step}:\n${payload.activeSkillContext.instructions}`);
31
- }
32
- if (payload.toolDelta && (payload.toolDelta.added.length > 0 || payload.toolDelta.removed.length > 0)) {
33
- const lines = [];
34
- if (payload.toolDelta.added.length > 0) {
35
- lines.push(`New tools available: ${payload.toolDelta.added.join(", ")}`);
36
- }
37
- if (payload.toolDelta.removed.length > 0) {
38
- lines.push(`Tools no longer available: ${payload.toolDelta.removed.join(", ")}`);
39
- }
40
- sections.push(`## Tool Changes\n${lines.join("\n")}`);
41
- }
42
- if (payload.customBlocks) {
43
- for (const block of payload.customBlocks) {
44
- sections.push(`## ${block.label}\n${block.content}`);
45
- }
46
- }
47
- if (sections.length === 0)
48
- return null;
49
- return `[Context was compressed. The following state has been restored:]\n\n${sections.join("\n\n")}`;
50
- }
51
- export function createReactiveCompactState() {
52
- return {
53
- consecutiveFailures: 0,
54
- attemptedThisTurn: false,
55
- lastCompactAt: null,
56
- toolsAtLastCompact: [],
57
- };
58
- }
59
- /**
60
- * Determine if reactive compact should be attempted.
61
- */
62
- export function shouldAttemptReactiveCompact(state, config = DEFAULT_REACTIVE_COMPACT_CONFIG) {
63
- if (state.attemptedThisTurn)
64
- return false;
65
- if (state.consecutiveFailures >= config.maxConsecutiveFailures)
66
- return false;
67
- return true;
68
- }
69
- /**
70
- * Calculate the tool delta since last compact.
71
- */
72
- export function computeToolDelta(currentTools, toolsAtLastCompact) {
73
- const currentSet = new Set(currentTools);
74
- const lastSet = new Set(toolsAtLastCompact);
75
- const added = currentTools.filter((t) => !lastSet.has(t));
76
- const removed = toolsAtLastCompact.filter((t) => !currentSet.has(t));
77
- return { added, removed };
78
- }
@@ -1,24 +0,0 @@
1
- export async function executeBoundedRetryLoop(params) {
2
- let iterations = 0;
3
- while (true) {
4
- if (iterations >= params.maxIterations) {
5
- return await params.onRetryLimit({
6
- iterations,
7
- maxIterations: params.maxIterations,
8
- });
9
- }
10
- iterations += 1;
11
- const outcome = await params.executeIteration({ iteration: iterations });
12
- if (outcome.kind === "return") {
13
- return outcome.result;
14
- }
15
- }
16
- }
17
- export function resolveScaledRetryIterations(params) {
18
- const baseIterations = Math.max(0, Math.floor(params.baseIterations ?? 24));
19
- const perCandidateIterations = Math.max(0, Math.floor(params.perCandidateIterations ?? 8));
20
- const minIterations = Math.max(1, Math.floor(params.minIterations ?? 32));
21
- const maxIterations = Math.max(minIterations, Math.floor(params.maxIterations ?? 160));
22
- const scaled = baseIterations + Math.max(1, Math.floor(params.candidateCount)) * perCandidateIterations;
23
- return Math.min(maxIterations, Math.max(minIterations, scaled));
24
- }
@@ -1,141 +0,0 @@
1
- import { coerceSkillCandidateJsonObject, normalizeSkillCandidateAction, normalizeSkillCandidateArtifact, normalizeSkillCandidateEffectiveness, normalizeSkillCandidateEffectivenessPhase, normalizeSkillCandidateSourceExecution, } from "../contracts/skill-candidate.js";
2
- const DEFAULT_SKILL_IMPROVEMENT_POLICY = {
3
- reviewRequired: true,
4
- canaryRequired: true,
5
- autoPromote: false,
6
- minCanarySampleCount: 10,
7
- minSuccessRate: 0.7,
8
- maxRegressionRate: 0.1,
9
- maxCostIncreaseRate: 0.25,
10
- staleAfterHours: 168,
11
- };
12
- function normalizeOptionalBoolean(value, fallback) {
13
- if (typeof value === "boolean") {
14
- return value;
15
- }
16
- if (typeof value === "string") {
17
- const normalized = value.trim().toLowerCase();
18
- if (normalized === "true") {
19
- return true;
20
- }
21
- if (normalized === "false") {
22
- return false;
23
- }
24
- }
25
- return fallback;
26
- }
27
- function normalizeOptionalFiniteNumber(value, fallback) {
28
- if (typeof value === "number" && Number.isFinite(value)) {
29
- return value;
30
- }
31
- if (typeof value === "string") {
32
- const trimmed = value.trim();
33
- if (trimmed) {
34
- const parsed = Number(trimmed);
35
- if (Number.isFinite(parsed)) {
36
- return parsed;
37
- }
38
- }
39
- }
40
- return fallback;
41
- }
42
- function normalizeOptionalStringArray(value) {
43
- return Array.isArray(value)
44
- ? value
45
- .filter((entry) => typeof entry === "string")
46
- .map((entry) => entry.trim())
47
- .filter(Boolean)
48
- : [];
49
- }
50
- export function createDefaultSkillImprovementPolicy(overrides = {}) {
51
- return normalizeSkillImprovementPolicy(overrides, DEFAULT_SKILL_IMPROVEMENT_POLICY);
52
- }
53
- export function normalizeSkillImprovementPolicy(value, fallback = DEFAULT_SKILL_IMPROVEMENT_POLICY) {
54
- const record = coerceSkillCandidateJsonObject(value);
55
- return {
56
- reviewRequired: normalizeOptionalBoolean(record.reviewRequired, fallback.reviewRequired),
57
- canaryRequired: normalizeOptionalBoolean(record.canaryRequired, fallback.canaryRequired),
58
- autoPromote: normalizeOptionalBoolean(record.autoPromote, fallback.autoPromote),
59
- minCanarySampleCount: Math.max(1, Math.floor(normalizeOptionalFiniteNumber(record.minCanarySampleCount, fallback.minCanarySampleCount))),
60
- minSuccessRate: Math.max(0, Math.min(1, normalizeOptionalFiniteNumber(record.minSuccessRate, fallback.minSuccessRate))),
61
- maxRegressionRate: Math.max(0, Math.min(1, normalizeOptionalFiniteNumber(record.maxRegressionRate, fallback.maxRegressionRate))),
62
- maxCostIncreaseRate: Math.max(0, normalizeOptionalFiniteNumber(record.maxCostIncreaseRate, fallback.maxCostIncreaseRate)),
63
- staleAfterHours: Math.max(1, Math.floor(normalizeOptionalFiniteNumber(record.staleAfterHours, fallback.staleAfterHours))),
64
- };
65
- }
66
- export function buildSkillCandidateEvidencePayload(params) {
67
- const evidence = coerceSkillCandidateJsonObject(params.evidence);
68
- const artifact = params.artifact ? normalizeSkillCandidateArtifact(params.artifact) : null;
69
- const sourceExecution = params.sourceExecution
70
- ? normalizeSkillCandidateSourceExecution(params.sourceExecution)
71
- : null;
72
- const sourceSessionKey = typeof params.sourceSessionKey === "string"
73
- ? params.sourceSessionKey.trim()
74
- : "";
75
- return {
76
- ...evidence,
77
- ...(artifact ? { artifact } : {}),
78
- ...(sourceExecution ? { sourceExecution } : {}),
79
- ...(sourceSessionKey ? { sourceSessionKey } : {}),
80
- };
81
- }
82
- export function buildSkillCandidateImprovementEvidenceBundle(params) {
83
- const evidence = buildSkillCandidateEvidencePayload(params);
84
- const diffSummary = typeof params.diffSummary === "string" && params.diffSummary.trim()
85
- ? params.diffSummary.trim()
86
- : "";
87
- const baselineCandidateId = typeof params.baselineCandidateId === "string"
88
- && params.baselineCandidateId.trim()
89
- ? params.baselineCandidateId.trim()
90
- : "";
91
- const rolloutNotes = typeof params.rolloutNotes === "string" && params.rolloutNotes.trim()
92
- ? params.rolloutNotes.trim()
93
- : "";
94
- const validationRefs = normalizeOptionalStringArray(params.validationRefs);
95
- return {
96
- ...evidence,
97
- ...(diffSummary ? { diffSummary } : {}),
98
- ...(baselineCandidateId ? { baselineCandidateId } : {}),
99
- ...(rolloutNotes ? { rolloutNotes } : {}),
100
- ...(validationRefs.length > 0 ? { validationRefs } : {}),
101
- };
102
- }
103
- export function buildSkillCandidateLatestReview(params) {
104
- return {
105
- action: normalizeSkillCandidateAction(params.action) ?? params.action,
106
- actor: typeof params.actor === "string" && params.actor.trim() ? params.actor.trim() : null,
107
- notes: typeof params.notes === "string" && params.notes.trim() ? params.notes.trim() : null,
108
- payload: coerceSkillCandidateJsonObject(params.payload),
109
- createdAt: typeof params.createdAt === "string" && params.createdAt.trim()
110
- ? params.createdAt.trim()
111
- : new Date().toISOString(),
112
- };
113
- }
114
- export function buildSkillCandidateEffectivenessSummary(params) {
115
- const sampleCount = Math.max(0, Math.floor(params.sampleCount ?? 0));
116
- const successCount = Math.max(0, Math.floor(params.successCount ?? 0));
117
- const failureCount = Math.max(0, Math.floor(params.failureCount ?? Math.max(sampleCount - successCount, 0)));
118
- const regressionCount = Math.max(0, Math.floor(params.regressionCount ?? 0));
119
- const successRate = sampleCount > 0 ? successCount / sampleCount : 0;
120
- const regressionRate = sampleCount > 0 ? regressionCount / sampleCount : 0;
121
- const score = typeof params.score === "number" && Number.isFinite(params.score)
122
- ? params.score
123
- : Number((successRate - regressionRate).toFixed(4));
124
- return normalizeSkillCandidateEffectiveness({
125
- phase: normalizeSkillCandidateEffectivenessPhase(params.phase) ?? params.phase,
126
- sampleCount,
127
- successCount,
128
- failureCount,
129
- regressionCount,
130
- successRate,
131
- regressionRate,
132
- avgLatencyMs: params.avgLatencyMs,
133
- avgCostUsd: params.avgCostUsd,
134
- score,
135
- staleReason: params.staleReason,
136
- notes: params.notes,
137
- summary: coerceSkillCandidateJsonObject(params.summary),
138
- lastObservedAt: params.lastObservedAt ?? new Date().toISOString(),
139
- updatedAt: params.updatedAt ?? new Date().toISOString(),
140
- });
141
- }