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,575 +0,0 @@
1
- /**
2
- * Tool loop state machine — faithful port of Hub's semantic-turn-tools.ts.
3
- *
4
- * Replaces Hub infrastructure with DI abstractions:
5
- * - invokeGatewayTool() (WS) → ToolInvoker.invoke()
6
- * - createAdminInferProxyClient().stream() → LLMTransport.stream()
7
- * - SemanticTurnDeps (PG/Redis) → in-memory state
8
- * - sidechain DB depth → in-memory depth counter
9
- * - Hub approval flow → skipped (CLI is local, all tools pre-authorized)
10
- *
11
- * Keeps ALL orchestration strategy calls from Hub:
12
- * - turn-loop-guard (abort, token budget, output escalation)
13
- * - tool-loop-state (advance/settle/recover)
14
- * - parallel/serial tool call scheduling
15
- * - sidechain tool access policy filtering
16
- * - consecutive failure early exit
17
- * - API error recovery
18
- * - message repair
19
- * - skill learning evaluation
20
- *
21
- * Zero imports from express/pg/ioredis/ws.
22
- */
23
- import { accumulateToolCalls } from "../llm/transport.js";
24
- import { advanceToolLoopState, applyToolChoicePolicy, buildAssistantToolCallMessage, buildToolResultMessage, filterToolCallsByAccessPolicy, recoverToolLoopStateFromChatConversation, resolveParallelToolCallScheduling, resolveSidechainToolAccessByType, settleToolLoopState, calculateTokenWarningState, resolveApiErrorRecovery, resolveOutputTokenEscalation, shouldAbortTurn, createTurnLoopGuardState, shouldAttemptReactiveCompact, createReactiveCompactState, classifyError, buildSkillInstruction, } from "../orchestration/index.js";
25
- // ── Budget constants (same as Hub) ───────────────────────────────────────────
26
- const MAX_TOOL_BUDGET_CAP = 100;
27
- const DEFAULT_TOOL_BUDGET = Math.min(Math.max(1, Number(process.env.TOOL_LOOP_DEFAULT_BUDGET) || 25), MAX_TOOL_BUDGET_CAP);
28
- const MAX_CONSECUTIVE_FAILURES = 3;
29
- const MAX_SIDECHAIN_DEPTH = 2;
30
- // ── Helper: resolve budget ───────────────────────────────────────────────────
31
- function resolveToolLoopBudget(requested) {
32
- if (typeof requested === "number" && Number.isFinite(requested) && requested >= 1) {
33
- return Math.min(Math.round(requested), MAX_TOOL_BUDGET_CAP);
34
- }
35
- return DEFAULT_TOOL_BUDGET;
36
- }
37
- // ── Main tool loop ───────────────────────────────────────────────────────────
38
- /**
39
- * Execute the tool loop — faithful port of Hub's orchestrateAgentTurnWithGatewayTools().
40
- *
41
- * Yields TurnEvent stream. The caller (Agent class) wraps this with
42
- * start/end lifecycle and error handling.
43
- *
44
- * Events yielded:
45
- * - delta: streaming text from LLM
46
- * - tool_call: LLM requested a tool call
47
- * - tool_result: tool execution completed
48
- * - skill_instruction: skill learning evaluation result
49
- * - end: turn completed successfully
50
- * - error: unrecoverable error
51
- */
52
- export async function* executeToolLoop(params, transport, toolInvoker, log) {
53
- const { turnId, sessionId, messages: inputMessages, tools, model, apiKey, temperature, hooks, signal, } = params;
54
- const hookCtx = { sessionId, turnId };
55
- // ── Tool eligibility filtering (CC permission-level parity) ────
56
- const { resolveToolEligibility } = await import("../runtime/tool-eligibility.js");
57
- const eligibility = resolveToolEligibility(tools, params.toolEligibilityContext);
58
- const effectiveTools = eligibility.eligibleTools;
59
- // Emit blocked tool events
60
- for (const blocked of eligibility.blockedTools) {
61
- yield { type: "tool_blocked", turnId, callId: "", name: blocked.toolName, reason: "blocked-by-policy" };
62
- }
63
- // ── No tools: single LLM call, no loop ─────────────────────────
64
- if (!effectiveTools.length) {
65
- yield* executeSingleLLMRound(turnId, model, inputMessages, apiKey, temperature, signal, transport, log);
66
- return;
67
- }
68
- // ── Tool loop setup ────────────────────────────────────────────
69
- const toolBudget = resolveToolLoopBudget(params.maxRounds);
70
- const messages = [...inputMessages];
71
- // Recover tool loop state from conversation history
72
- let toolLoopState = recoverToolLoopStateFromChatConversation({
73
- maxRounds: toolBudget,
74
- replayMessages: messages,
75
- }).state;
76
- // Turn-loop-guard config (CC-aligned)
77
- const guardConfig = {
78
- contextWindowTokens: params.contextWindowTokens ?? 128_000,
79
- responseBufferTokens: 13_000,
80
- maxOutputTokens: params.maxOutputTokens ?? 16_384,
81
- abortSignal: signal,
82
- reactiveCompactEnabled: true,
83
- outputEscalationEnabled: true,
84
- };
85
- let guardState = createTurnLoopGuardState(guardConfig);
86
- let reactiveCompactState = createReactiveCompactState();
87
- // In-memory sidechain depth (replaces Hub's PG recursive CTE)
88
- let sidechainStarted = false;
89
- let activeSidechainToolPolicy = null;
90
- const sidechainDepth = (params.parentDepth ?? 0) + 1;
91
- let lastUsage;
92
- let finalText = "";
93
- let consecutiveFailedRounds = 0;
94
- let totalUsage = { prompt: 0, completion: 0 };
95
- // Skill learning metrics
96
- const distinctToolNames = new Set();
97
- let totalToolCallCount = 0;
98
- // ── Main loop ──────────────────────────────────────────────────
99
- for (let round = 0; round < toolBudget; round++) {
100
- // Turn-loop-guard: pre-round abort check (CC-aligned)
101
- if (shouldAbortTurn(guardState, guardConfig)) {
102
- log.info(`turn aborted by guard at round ${round}`);
103
- break;
104
- }
105
- // Turn-loop-guard: token budget pre-check
106
- const tokenWarning = calculateTokenWarningState(guardState, guardConfig);
107
- if (tokenWarning.level === "blocking") {
108
- if (tokenWarning.reason === "prompt_too_long" &&
109
- shouldAttemptReactiveCompact(reactiveCompactState)) {
110
- reactiveCompactState.attemptedThisTurn = true;
111
- guardState.hasAttemptedReactiveCompact = true;
112
- log.info(`token budget blocking (${tokenWarning.reason}), reactive compact needed`);
113
- }
114
- log.info(`token budget blocking (${tokenWarning.reason}), breaking tool loop`);
115
- break;
116
- }
117
- if (tokenWarning.level === "warning") {
118
- log.info(`token budget warning: ${tokenWarning.usagePercent}% used, ${tokenWarning.remainingTokens} remaining`);
119
- }
120
- // Build tool loop request: tool choice policy + state recovery
121
- const toolChoiceResult = applyToolChoicePolicy({
122
- tools: effectiveTools,
123
- toolChoice: params.toolChoice ?? "auto",
124
- });
125
- const repaired = recoverToolLoopStateFromChatConversation({
126
- maxRounds: toolBudget,
127
- replayMessages: messages,
128
- lastStopReason: toolLoopState.lastStopReason,
129
- options: { stopReason: toolLoopState.lastStopReason },
130
- });
131
- const requestMessages = toolChoiceResult.extraSystemPrompt
132
- ? [
133
- { role: "system", content: toolChoiceResult.extraSystemPrompt },
134
- ...repaired.state.replayMessages,
135
- ]
136
- : repaired.state.replayMessages;
137
- if (repaired.recoveryActions.length > 0) {
138
- log.debug(`tool loop recovery: ${repaired.recoveryActions.map((a) => a.detail ?? a.kind).join("; ")}`);
139
- }
140
- log.debug(`round ${round + 1}/${toolBudget}, messages: ${requestMessages.length}`);
141
- // Hook: turn.before_inference
142
- hooks?.invoke("turn.before_inference", { ...hookCtx, model }).catch(() => { });
143
- // ── Streaming LLM round with Hermes delta suppression ───────
144
- let hasToolCalls = false;
145
- const textChunks = [];
146
- const toolCallAccumulator = new Map();
147
- let finishReason = "stop";
148
- let roundUsage;
149
- let streamError = null;
150
- try {
151
- for await (const chunk of transport.stream({
152
- model,
153
- messages: requestMessages,
154
- tools: toolChoiceResult.tools,
155
- toolChoice: toolChoiceResult.normalizedToolChoice ??
156
- "auto",
157
- temperature,
158
- maxTokens: guardState.currentMaxOutputTokens || undefined,
159
- }, apiKey, signal)) {
160
- switch (chunk.type) {
161
- case "delta":
162
- textChunks.push(chunk.text);
163
- // Hermes delta suppression: stop text forwarding once tool_calls detected
164
- if (!hasToolCalls) {
165
- yield { type: "delta", turnId, text: chunk.text };
166
- }
167
- break;
168
- case "tool_call_delta":
169
- hasToolCalls = true;
170
- accumulateToolCalls(toolCallAccumulator, chunk);
171
- break;
172
- case "reasoning_delta":
173
- break;
174
- case "usage":
175
- roundUsage = {
176
- prompt: chunk.promptTokens,
177
- completion: chunk.completionTokens,
178
- reasoning: chunk.reasoningTokens,
179
- };
180
- break;
181
- case "done":
182
- finishReason = chunk.finishReason;
183
- break;
184
- }
185
- }
186
- // Hook: turn.after_inference (success path)
187
- if (!hasToolCalls) {
188
- hooks?.invoke("turn.after_inference", { ...hookCtx, model }).catch(() => { });
189
- }
190
- }
191
- catch (err) {
192
- const message = err instanceof Error ? err.message : String(err);
193
- const status = typeof err?.status === "number"
194
- ? err.status
195
- : undefined;
196
- streamError = { status, message };
197
- }
198
- // Hook: turn.after_inference (error path)
199
- if (streamError) {
200
- hooks?.invoke("turn.after_inference", { ...hookCtx, model, response: { error: streamError.message } }).catch(() => { });
201
- }
202
- // ── Handle LLM errors with turn-loop-guard recovery ────────
203
- if (streamError) {
204
- const recovery = resolveApiErrorRecovery({ status: streamError.status ?? 500, message: streamError.message }, guardState, guardConfig);
205
- if (recovery.action === "reactive_compact" &&
206
- shouldAttemptReactiveCompact(reactiveCompactState)) {
207
- reactiveCompactState.attemptedThisTurn = true;
208
- guardState.hasAttemptedReactiveCompact = true;
209
- yield { type: "recovery", turnId, action: "reactive_compact", detail: `API ${streamError.status ?? 500}: ${streamError.message}` };
210
- }
211
- if (recovery.action === "retry") {
212
- yield { type: "recovery", turnId, action: "retry", detail: recovery.reason };
213
- continue;
214
- }
215
- const category = classifyError(streamError.status, streamError.message);
216
- yield { type: "error", turnId, error: streamError.message, code: category };
217
- return;
218
- }
219
- // Accumulate usage
220
- if (roundUsage) {
221
- totalUsage.prompt += roundUsage.prompt;
222
- totalUsage.completion += roundUsage.completion;
223
- if (roundUsage.reasoning) {
224
- totalUsage.reasoning = (totalUsage.reasoning ?? 0) + roundUsage.reasoning;
225
- }
226
- }
227
- // Turn-loop-guard: update token state from usage feedback
228
- if (roundUsage?.prompt) {
229
- guardState.promptTokens = roundUsage.prompt;
230
- }
231
- // Turn-loop-guard: handle max_tokens truncation → escalate output budget (CC-aligned)
232
- if (finishReason === "length" || finishReason === "max_tokens") {
233
- guardState.consecutiveTruncations += 1;
234
- const modelMaxOutput = params.modelMaxOutputTokens ?? 65_536;
235
- const escalation = resolveOutputTokenEscalation(guardState, guardConfig, modelMaxOutput);
236
- if (escalation.shouldEscalate) {
237
- guardState.currentMaxOutputTokens = escalation.newMax;
238
- yield { type: "recovery", turnId, action: "output_escalation", detail: `${escalation.newMax} tokens` };
239
- }
240
- }
241
- else {
242
- guardState.consecutiveTruncations = 0;
243
- }
244
- lastUsage = roundUsage;
245
- finalText = textChunks.join("");
246
- // Convert accumulated tool call deltas to OpenAiToolCall[]
247
- let toolCalls = [...toolCallAccumulator.values()].map((tc) => ({
248
- id: tc.id || `tc_${turnId}_${round}_${Math.random().toString(36).slice(2, 8)}`,
249
- type: "function",
250
- function: { name: tc.name, arguments: tc.arguments },
251
- }));
252
- // Filter tool_calls against active sidechain policy
253
- if (activeSidechainToolPolicy && toolCalls.length > 0) {
254
- const filterResult = filterToolCallsByAccessPolicy(toolCalls, activeSidechainToolPolicy);
255
- if (filterResult.denied.length > 0) {
256
- log.info(`sidechain policy denied: ${filterResult.denied.map((d) => `${d.toolCall.function.name} (${d.reason})`).join(", ")}`);
257
- }
258
- toolCalls = filterResult.allowed;
259
- }
260
- // ── No tool calls → loop complete ──────────────────────────
261
- if (toolCalls.length === 0) {
262
- toolLoopState = settleToolLoopState(toolLoopState, {
263
- replayMessages: messages,
264
- lastStopReason: "completed",
265
- });
266
- // Sidechain completed event
267
- if (sidechainStarted) {
268
- yield { type: "sidechain_completed", turnId, depth: sidechainDepth, toolCallCount: totalToolCallCount };
269
- }
270
- // Skill learning: evaluate turn for skill instruction
271
- if (totalToolCallCount > 0) {
272
- const skillResult = {
273
- ok: true,
274
- toolCallCount: totalToolCallCount,
275
- distinctToolCount: distinctToolNames.size,
276
- multiStep: totalToolCallCount >= 2,
277
- hasSidechain: sidechainStarted,
278
- feedback: null,
279
- existingSkillName: null,
280
- };
281
- const skillInstruction = buildSkillInstruction(skillResult, {
282
- tools: [...distinctToolNames],
283
- });
284
- if (skillInstruction) {
285
- yield { type: "skill_instruction", turnId, instruction: skillInstruction };
286
- }
287
- }
288
- yield { type: "end", turnId, content: finalText, usage: totalUsage, model };
289
- return;
290
- }
291
- // ── Has tool calls → execute them ──────────────────────────
292
- // Emit tool_call events for the host
293
- for (const tc of toolCalls) {
294
- yield {
295
- type: "tool_call",
296
- turnId,
297
- callId: tc.id,
298
- name: tc.function.name,
299
- arguments: tc.function.arguments,
300
- };
301
- }
302
- // Build assistant message with tool calls
303
- messages.push(buildAssistantToolCallMessage(toolCalls));
304
- // Setup sidechain on first tool calls (in-memory depth tracking)
305
- if (!sidechainStarted) {
306
- if (sidechainDepth > MAX_SIDECHAIN_DEPTH) {
307
- yield {
308
- type: "error",
309
- turnId,
310
- error: `sidechain depth ${sidechainDepth} exceeds max ${MAX_SIDECHAIN_DEPTH}`,
311
- code: "SIDECHAIN_DEPTH_LIMIT",
312
- };
313
- return;
314
- }
315
- sidechainStarted = true;
316
- const sidechainRole = sidechainDepth >= MAX_SIDECHAIN_DEPTH ? "leaf" : "orchestrator";
317
- yield { type: "sidechain_started", turnId, depth: sidechainDepth, role: sidechainRole };
318
- activeSidechainToolPolicy = resolveSidechainToolAccessByType({
319
- type: "planner",
320
- depth: sidechainDepth,
321
- maxDepth: MAX_SIDECHAIN_DEPTH,
322
- role: sidechainDepth >= MAX_SIDECHAIN_DEPTH ? "leaf" : "orchestrator",
323
- toolNames: tools.map((t) => t.function.name),
324
- });
325
- }
326
- // Advance tool loop state
327
- toolLoopState = advanceToolLoopState(toolLoopState, {
328
- replayMessages: messages,
329
- pendingToolCallIds: toolCalls.map((tc) => tc.id),
330
- completedToolCallIds: toolLoopState.completedToolCallIds,
331
- lastStopReason: "tool_calls",
332
- });
333
- // Resolve parallel/serial scheduling
334
- const scheduling = resolveParallelToolCallScheduling({
335
- requestedPreference: undefined,
336
- providerSupportsParallel: true,
337
- toolCalls,
338
- toolCapabilities: effectiveTools.map((t) => ({
339
- name: t.function.name,
340
- requiresApproval: t.meta?.requiresApproval ?? false,
341
- approvalMode: (t.meta?.requiresApproval ? "user-confirm" : "pre-authorized"),
342
- parallelSafe: t.meta?.parallelSafe ?? true,
343
- serialOnly: t.meta?.serialOnly ?? false,
344
- })),
345
- });
346
- // ── Execute tool calls in batches ──────────────────────────
347
- const executedToolCallIds = [];
348
- try {
349
- for (const batch of scheduling.batches) {
350
- if (batch.mode === "parallel") {
351
- const toolCallOpts = { hooks, sessionId };
352
- const batchResults = await Promise.all(batch.calls.map((tc) => executeToolCall(tc, turnId, toolInvoker, signal, log, toolCallOpts)));
353
- for (const r of batchResults) {
354
- if (r.blocked) {
355
- yield { type: "tool_blocked", turnId, callId: r.callId, name: r.toolName, reason: r.blockReason ?? "blocked" };
356
- }
357
- messages.push(r.message);
358
- executedToolCallIds.push(r.callId);
359
- distinctToolNames.add(r.toolName);
360
- totalToolCallCount++;
361
- yield {
362
- type: "tool_result",
363
- turnId,
364
- callId: r.callId,
365
- name: r.toolName,
366
- ok: r.ok,
367
- error: r.error,
368
- };
369
- }
370
- }
371
- else {
372
- for (const tc of batch.calls) {
373
- if (signal?.aborted) {
374
- yield { type: "error", turnId, error: "Turn aborted", code: "ABORTED" };
375
- return;
376
- }
377
- const r = await executeToolCall(tc, turnId, toolInvoker, signal, log, { hooks, sessionId });
378
- if (r.blocked) {
379
- yield { type: "tool_blocked", turnId, callId: r.callId, name: r.toolName, reason: r.blockReason ?? "blocked" };
380
- }
381
- messages.push(r.message);
382
- executedToolCallIds.push(r.callId);
383
- distinctToolNames.add(r.toolName);
384
- totalToolCallCount++;
385
- yield {
386
- type: "tool_result",
387
- turnId,
388
- callId: r.callId,
389
- name: r.toolName,
390
- ok: r.ok,
391
- error: r.error,
392
- };
393
- }
394
- }
395
- }
396
- }
397
- catch (err) {
398
- const message = err instanceof Error ? err.message : String(err);
399
- yield { type: "error", turnId, error: message, code: "TOOL_EXECUTION_ERROR" };
400
- return;
401
- }
402
- // Settle tool loop state
403
- toolLoopState = settleToolLoopState(toolLoopState, {
404
- replayMessages: messages,
405
- completedToolCallIds: [
406
- ...toolLoopState.completedToolCallIds,
407
- ...executedToolCallIds,
408
- ],
409
- lastStopReason: scheduling.mode,
410
- });
411
- // ── Consecutive failure tracking ───────────────────────────
412
- const roundToolResults = messages.slice(-toolCalls.length);
413
- const allFailed = roundToolResults.length > 0 &&
414
- roundToolResults.every((msg) => {
415
- const content = msg?.content;
416
- if (typeof content !== "string")
417
- return false;
418
- try {
419
- return JSON.parse(content)?.ok === false;
420
- }
421
- catch {
422
- return false;
423
- }
424
- });
425
- if (allFailed) {
426
- consecutiveFailedRounds += 1;
427
- if (consecutiveFailedRounds >= MAX_CONSECUTIVE_FAILURES && finalText) {
428
- log.info(`early exit: ${consecutiveFailedRounds} consecutive failed rounds, returning partial response`);
429
- yield { type: "end", turnId, content: finalText, usage: totalUsage };
430
- return;
431
- }
432
- }
433
- else {
434
- consecutiveFailedRounds = 0;
435
- }
436
- }
437
- // ── Budget exhaustion ──────────────────────────────────────────
438
- if (finalText) {
439
- log.info(`tool loop budget exhausted (${toolBudget} rounds), returning partial response`);
440
- // Sidechain completed event (budget exhaustion)
441
- if (sidechainStarted) {
442
- yield { type: "sidechain_completed", turnId, depth: sidechainDepth, toolCallCount: totalToolCallCount };
443
- }
444
- // Skill learning on partial completion
445
- if (totalToolCallCount > 0) {
446
- const skillResult = {
447
- ok: true,
448
- toolCallCount: totalToolCallCount,
449
- distinctToolCount: distinctToolNames.size,
450
- multiStep: totalToolCallCount >= 2,
451
- hasSidechain: sidechainStarted,
452
- feedback: null,
453
- existingSkillName: null,
454
- };
455
- const skillInstruction = buildSkillInstruction(skillResult, {
456
- tools: [...distinctToolNames],
457
- });
458
- if (skillInstruction) {
459
- yield { type: "skill_instruction", turnId, instruction: skillInstruction };
460
- }
461
- }
462
- yield { type: "end", turnId, content: finalText, usage: totalUsage, model };
463
- return;
464
- }
465
- yield {
466
- type: "error",
467
- turnId,
468
- error: `Tool loop exceeded budget (${toolBudget} rounds)`,
469
- code: "TOOL_LOOP_LIMIT",
470
- };
471
- }
472
- async function executeToolCall(toolCall, turnId, toolInvoker, signal, log, options) {
473
- const toolName = toolCall.function.name;
474
- log.debug(`tool_call: ${toolName}`);
475
- const hooks = options?.hooks;
476
- // Hook: tool.before_invoke — can block or mutate input (CC PreToolUse parity)
477
- let effectiveArguments = toolCall.function.arguments;
478
- if (hooks) {
479
- try {
480
- const hookResult = await hooks.invoke("tool.before_invoke", {
481
- sessionId: options?.sessionId ?? "",
482
- turnId,
483
- callId: toolCall.id,
484
- toolName,
485
- arguments: safeParseJsonArgs(toolCall.function.arguments),
486
- });
487
- if (hookResult.action === "abort") {
488
- const reason = hookResult.reason ?? "blocked by policy";
489
- log.info(`tool ${toolName} blocked: ${reason}`);
490
- // Emit approval.requested for blocked tools requiring approval
491
- hooks.invoke("approval.requested", {
492
- sessionId: options?.sessionId ?? "",
493
- turnId,
494
- approvalId: toolCall.id,
495
- callId: toolCall.id,
496
- toolName,
497
- }).catch(() => { });
498
- const message = buildToolResultMessage(toolCall.id, {
499
- ok: false,
500
- error: reason,
501
- });
502
- return { callId: toolCall.id, toolName, ok: false, error: reason, blocked: true, blockReason: reason, message };
503
- }
504
- // CC PreToolUse input mutation: hook can return modified arguments via context
505
- if (hookResult.action === "continue" && hookResult.context?.arguments) {
506
- effectiveArguments = JSON.stringify(hookResult.context.arguments);
507
- log.debug(`tool ${toolName}: input mutated by hook`);
508
- }
509
- }
510
- catch {
511
- // Hook failures are non-blocking — proceed with tool execution
512
- }
513
- }
514
- const invokeResult = await toolInvoker.invoke(turnId, toolName, effectiveArguments, signal);
515
- const ok = !invokeResult.error;
516
- const message = buildToolResultMessage(toolCall.id, {
517
- ok,
518
- payload: invokeResult.result,
519
- error: invokeResult.error,
520
- });
521
- // Hook: tool.after_invoke / tool.invoke_failed (fire-and-forget observability)
522
- hooks?.invoke(ok ? "tool.after_invoke" : "tool.invoke_failed", {
523
- sessionId: options?.sessionId ?? "",
524
- turnId,
525
- callId: toolCall.id,
526
- toolName,
527
- ok,
528
- ...(invokeResult.error ? { error: invokeResult.error } : {}),
529
- }).catch(() => { });
530
- return {
531
- callId: toolCall.id,
532
- toolName,
533
- ok,
534
- error: invokeResult.error,
535
- message,
536
- };
537
- }
538
- function safeParseJsonArgs(raw) {
539
- try {
540
- return JSON.parse(raw);
541
- }
542
- catch {
543
- return undefined;
544
- }
545
- }
546
- // ── Internal: single LLM round (no tools) ───────────────────────────────────
547
- async function* executeSingleLLMRound(turnId, model, messages, apiKey, temperature, signal, transport, log) {
548
- const textChunks = [];
549
- let usage;
550
- log.debug(`single LLM round, messages: ${messages.length}`);
551
- for await (const chunk of transport.stream({ model, messages, temperature }, apiKey, signal)) {
552
- switch (chunk.type) {
553
- case "delta":
554
- textChunks.push(chunk.text);
555
- yield { type: "delta", turnId, text: chunk.text };
556
- break;
557
- case "usage":
558
- usage = {
559
- prompt: chunk.promptTokens,
560
- completion: chunk.completionTokens,
561
- reasoning: chunk.reasoningTokens,
562
- };
563
- break;
564
- case "done":
565
- break;
566
- }
567
- }
568
- yield {
569
- type: "end",
570
- turnId,
571
- content: textChunks.join(""),
572
- usage: usage ?? { prompt: 0, completion: 0 },
573
- model,
574
- };
575
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Pure agent types — zero I/O framework dependencies.
3
- *
4
- * These types define the contract between:
5
- * - CLI stdio layer ↔ Agent class
6
- * - Agent class ↔ LLM Provider
7
- * - Agent class ↔ Tool loop
8
- *
9
- * Ported from Hub semantic-turn-shared.ts / semantic-turn-tools.ts,
10
- * with Hub infrastructure (WS/PG/Redis) replaced by DI interfaces.
11
- *
12
- * No imports from express/pg/ioredis/ws.
13
- */
14
- export {};
package/dist/cli/main.js DELETED
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * qlogicagent CLI — Agent subprocess entry point.
4
- *
5
- * Communicates with openclaw Gateway via JSON-RPC over stdio.
6
- * All log/debug output goes to stderr (never pollutes the stdio protocol).
7
- *
8
- * Usage:
9
- * qlogicagent [--verbose]
10
- */
11
- import { StdioServer } from "./stdio-server.js";
12
- import { parseCliArgs } from "../config/config.js";
13
- const config = parseCliArgs(process.argv);
14
- const server = new StdioServer({ verbose: config.verbose });
15
- // Graceful shutdown
16
- const shutdown = () => {
17
- server.stop();
18
- process.exit(0);
19
- };
20
- process.on("SIGTERM", shutdown);
21
- process.on("SIGINT", shutdown);
22
- // Start the JSON-RPC stdio server
23
- server.start();