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,191 +0,0 @@
1
- /**
2
- * ModelCatalog — remote model directory with disk cache + fallback.
3
- *
4
- * Fetches model metadata from models.dev (open community catalog, 4000+ models).
5
- * Aligned with Hermes agent/models_dev.py caching strategy.
6
- *
7
- * Three-layer fallback:
8
- * 1. In-memory cache (process-level, TTL check against disk mtime)
9
- * 2. Disk cache (~/.openclaw/cache/model_catalog.json)
10
- * 3. Remote fetch (https://models.dev/api.json)
11
- * 4. Stale disk cache (if remote fails)
12
- * 5. Empty (caller falls back to builtin-providers.ts hardcoded)
13
- *
14
- * Non-blocking: first startup without cache returns empty immediately,
15
- * triggers background async fetch. Agent uses builtin providers until
16
- * catalog arrives.
17
- */
18
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
19
- import { join } from "node:path";
20
- import { homedir } from "node:os";
21
- // ── Constants ────────────────────────────────────────────────────────────────
22
- const MODELS_DEV_URL = "https://models.dev/api.json";
23
- const FETCH_TIMEOUT_MS = 15_000;
24
- const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
25
- const RETRY_TTL_MS = 5 * 60 * 1000; // 5 min after failure
26
- // ── ModelCatalog class ───────────────────────────────────────────────────────
27
- export class ModelCatalog {
28
- cache = null;
29
- cacheDir;
30
- cacheFile;
31
- ttlMs;
32
- fetching = false;
33
- lastFetchAttempt = 0;
34
- constructor(opts) {
35
- this.cacheDir = opts?.cacheDir ?? join(homedir(), ".openclaw", "cache");
36
- this.cacheFile = join(this.cacheDir, "model_catalog.json");
37
- this.ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
38
- }
39
- /**
40
- * Get models for a provider. Non-blocking: returns whatever is cached.
41
- * Triggers background refresh if stale.
42
- */
43
- getModels(providerId) {
44
- this.ensureLoaded();
45
- const provider = this.cache?.providers.get(providerId);
46
- if (!provider)
47
- return [];
48
- return [...provider.models.values()];
49
- }
50
- /**
51
- * Get a single model by provider + model id.
52
- */
53
- getModel(providerId, modelId) {
54
- this.ensureLoaded();
55
- return this.cache?.providers.get(providerId)?.models.get(modelId);
56
- }
57
- /**
58
- * List all known provider ids from the catalog.
59
- */
60
- listProviderIds() {
61
- this.ensureLoaded();
62
- return this.cache ? [...this.cache.providers.keys()] : [];
63
- }
64
- /**
65
- * Force refresh from remote. Returns true if successful.
66
- */
67
- async refreshCatalog() {
68
- return this.fetchRemote();
69
- }
70
- // ── Internal ──────────────────────────────────────────────────
71
- ensureLoaded() {
72
- if (this.cache && !this.isStale())
73
- return;
74
- // Try disk cache
75
- if (!this.cache) {
76
- this.loadFromDisk();
77
- }
78
- // Trigger background fetch if stale or missing
79
- if (!this.cache || this.isStale()) {
80
- this.backgroundFetch();
81
- }
82
- }
83
- isStale() {
84
- if (!this.cache)
85
- return true;
86
- return Date.now() - this.cache.fetchedAt > this.ttlMs;
87
- }
88
- loadFromDisk() {
89
- try {
90
- if (!existsSync(this.cacheFile))
91
- return;
92
- const raw = readFileSync(this.cacheFile, "utf8");
93
- const parsed = JSON.parse(raw);
94
- if (!parsed.fetchedAt || !parsed.data)
95
- return;
96
- this.cache = {
97
- fetchedAt: parsed.fetchedAt,
98
- providers: parseModelsDevResponse(parsed.data),
99
- };
100
- }
101
- catch {
102
- // Corrupted cache file — ignore
103
- }
104
- }
105
- saveToDisk(data) {
106
- try {
107
- mkdirSync(this.cacheDir, { recursive: true });
108
- const payload = JSON.stringify({ fetchedAt: Date.now(), data }, null, 0);
109
- writeFileSync(this.cacheFile, payload, "utf8");
110
- }
111
- catch {
112
- // Disk write failure — non-fatal
113
- }
114
- }
115
- backgroundFetch() {
116
- if (this.fetching)
117
- return;
118
- // Don't retry too soon after a failure
119
- if (Date.now() - this.lastFetchAttempt < RETRY_TTL_MS)
120
- return;
121
- this.fetching = true;
122
- this.fetchRemote().finally(() => {
123
- this.fetching = false;
124
- });
125
- }
126
- async fetchRemote() {
127
- this.lastFetchAttempt = Date.now();
128
- try {
129
- const response = await fetch(MODELS_DEV_URL, {
130
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
131
- headers: { Accept: "application/json" },
132
- });
133
- if (!response.ok) {
134
- return false;
135
- }
136
- const data = await response.json();
137
- const providers = parseModelsDevResponse(data);
138
- if (providers.size === 0) {
139
- return false;
140
- }
141
- this.cache = { fetchedAt: Date.now(), providers };
142
- this.saveToDisk(data);
143
- return true;
144
- }
145
- catch {
146
- // Network failure — keep stale cache if any
147
- return false;
148
- }
149
- }
150
- }
151
- // ── Parser: models.dev JSON → CatalogProvider map ────────────────────────────
152
- /**
153
- * Parse models.dev api.json response.
154
- * Format: { provider_id: { models: { model_name: { ... } } } }
155
- */
156
- function parseModelsDevResponse(data) {
157
- const providers = new Map();
158
- if (!data || typeof data !== "object")
159
- return providers;
160
- for (const [providerId, providerData] of Object.entries(data)) {
161
- if (!providerData || typeof providerData !== "object")
162
- continue;
163
- const modelsObj = providerData.models;
164
- if (!modelsObj || typeof modelsObj !== "object")
165
- continue;
166
- const models = new Map();
167
- for (const [modelId, modelData] of Object.entries(modelsObj)) {
168
- if (!modelData || typeof modelData !== "object")
169
- continue;
170
- const m = modelData;
171
- const limit = m.limit ?? {};
172
- const modalities = m.modalities ?? {};
173
- const inputMods = Array.isArray(modalities.input) ? modalities.input : [];
174
- models.set(modelId, {
175
- id: modelId,
176
- name: typeof m.name === "string" ? m.name : modelId,
177
- contextWindow: typeof limit.context === "number" ? limit.context : 200_000,
178
- maxOutput: typeof limit.output === "number" ? limit.output : 8_192,
179
- toolCall: m.tool_call === true,
180
- reasoning: m.reasoning === true,
181
- vision: m.attachment === true || inputMods.includes("image"),
182
- costInput: typeof m.cost_input === "number" ? m.cost_input : undefined,
183
- costOutput: typeof m.cost_output === "number" ? m.cost_output : undefined,
184
- });
185
- }
186
- if (models.size > 0) {
187
- providers.set(providerId, { models });
188
- }
189
- }
190
- return providers;
191
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * ProviderDef — defines how to connect to an LLM provider.
3
- *
4
- * Aligned with Hermes `ProviderDef` dataclass pattern:
5
- * id + name + transport type + baseUrl + auth config + model list
6
- *
7
- * Three-layer merge strategy (Layer 3 > Layer 2 > Layer 1):
8
- * Layer 1: builtin-providers.ts hardcoded (fallback)
9
- * Layer 2: model-catalog.ts remote (models.dev)
10
- * Layer 3: user config (from agent.turn.config)
11
- */
12
- export {};
@@ -1,147 +0,0 @@
1
- /**
2
- * ProviderRegistry — three-layer merge registry for LLM providers.
3
- *
4
- * Layer 1: builtin-providers.ts hardcoded (lowest priority, ~20 providers)
5
- * Layer 2: model-catalog.ts remote (models.dev — enriches model metadata)
6
- * Layer 3: user config override (from agent.turn.config — highest priority)
7
- *
8
- * Merge strategy: Layer 3 > Layer 2 > Layer 1 (later layers override same-id fields)
9
- *
10
- * Aligned with Hermes provider_registry.py.
11
- */
12
- import { BUILTIN_PROVIDERS } from "./builtin-providers.js";
13
- import { ModelCatalog } from "./model-catalog.js";
14
- // Provider alias map (Hermes-aligned): common user names → canonical ids
15
- const PROVIDER_ALIASES = {
16
- claude: "anthropic",
17
- gemini: "google",
18
- "x-ai": "xai",
19
- "z-ai": "xai",
20
- silicon: "siliconflow",
21
- "silicon-flow": "siliconflow",
22
- };
23
- export class ProviderRegistry {
24
- /** Layer 1: builtin hardcoded providers */
25
- builtins = new Map();
26
- /** Layer 2: remote model catalog (models.dev) */
27
- catalog;
28
- /** Layer 3: user overrides (from agent.turn.config) */
29
- overrides = new Map();
30
- constructor(opts) {
31
- for (const p of BUILTIN_PROVIDERS) {
32
- this.builtins.set(p.id, p);
33
- }
34
- this.catalog = opts?.catalog ?? new ModelCatalog();
35
- }
36
- /**
37
- * Apply user config override for a provider.
38
- * Typically called when agent.turn.config has baseUrl/apiKey overrides.
39
- */
40
- applyOverride(providerId, override) {
41
- this.overrides.set(providerId, {
42
- ...this.overrides.get(providerId),
43
- ...override,
44
- });
45
- }
46
- /**
47
- * Get merged ProviderDef by id (Layer 3 > Layer 1).
48
- * Returns undefined if provider not found.
49
- * Supports common aliases (e.g., "claude" → "anthropic").
50
- */
51
- getProvider(id) {
52
- const resolvedId = PROVIDER_ALIASES[id] ?? id;
53
- const builtin = this.builtins.get(resolvedId);
54
- const override = this.overrides.get(resolvedId);
55
- if (!builtin && !override)
56
- return undefined;
57
- if (!builtin && override) {
58
- // User defined a custom provider entirely
59
- if (!override.id || !override.transport || !override.baseUrl) {
60
- return undefined;
61
- }
62
- return {
63
- id: override.id,
64
- name: override.name ?? override.id,
65
- transport: override.transport,
66
- baseUrl: override.baseUrl,
67
- apiKeyEnvVars: override.apiKeyEnvVars ?? [],
68
- authType: override.authType ?? "bearer",
69
- isAggregator: override.isAggregator ?? false,
70
- defaultModel: override.defaultModel,
71
- models: override.models,
72
- };
73
- }
74
- if (builtin && !override)
75
- return builtin;
76
- // Merge: override fields take precedence
77
- return {
78
- ...builtin,
79
- ...override,
80
- // Merge models: override models replace if provided
81
- models: override.models ?? builtin.models,
82
- };
83
- }
84
- /**
85
- * List all known provider ids.
86
- */
87
- listProviders() {
88
- const all = new Map();
89
- for (const [id, p] of this.builtins) {
90
- all.set(id, p);
91
- }
92
- // Override/custom providers
93
- for (const [id] of this.overrides) {
94
- const merged = this.getProvider(id);
95
- if (merged)
96
- all.set(id, merged);
97
- }
98
- return [...all.values()];
99
- }
100
- /**
101
- * List models for a specific provider.
102
- * Merges: Layer 3 override > Layer 1 builtin > Layer 2 catalog enrichment.
103
- */
104
- listModels(providerId) {
105
- const provider = this.getProvider(providerId);
106
- const builtinModels = provider?.models ?? [];
107
- // Enrich with catalog data (Layer 2): catalog provides updated context windows,
108
- // costs, and capability flags; builtin models take precedence for known fields.
109
- const catalogModels = this.catalog.getModels(providerId);
110
- if (catalogModels.length === 0)
111
- return builtinModels;
112
- // Build merged model list: builtin first, then catalog models not in builtin
113
- const byId = new Map();
114
- for (const cm of catalogModels) {
115
- byId.set(cm.id, cm);
116
- }
117
- for (const bm of builtinModels) {
118
- // Builtin overrides catalog for same id (builtin has curated values)
119
- byId.set(bm.id, bm);
120
- }
121
- return [...byId.values()];
122
- }
123
- /**
124
- * Trigger background refresh of the remote model catalog.
125
- */
126
- async refreshCatalog() {
127
- return this.catalog.refreshCatalog();
128
- }
129
- /**
130
- * Resolve API key for a provider:
131
- * 1. Explicit key (from agent.turn.config)
132
- * 2. Environment variables (ProviderDef.apiKeyEnvVars)
133
- */
134
- resolveApiKey(providerId, explicitKey) {
135
- if (explicitKey)
136
- return explicitKey;
137
- const provider = this.getProvider(providerId);
138
- if (!provider)
139
- return undefined;
140
- for (const envVar of provider.apiKeyEnvVars) {
141
- const value = process.env[envVar];
142
- if (value?.trim())
143
- return value.trim();
144
- }
145
- return undefined;
146
- }
147
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * LLMTransport — abstract interface for LLM inference calls.
3
- *
4
- * Aligned with Hermes `ProviderTransport` ABC:
5
- * stream(request, apiKey, signal) → AsyncGenerator<LLMChunk>
6
- *
7
- * Two concrete implementations:
8
- * - OpenAI Chat Completions (covers 95% of providers)
9
- * - Anthropic Messages API
10
- */
11
- // ── Convenience: aggregate chunks to tool calls ──────────────────────────────
12
- /**
13
- * Accumulate tool_call_delta chunks into complete ToolCall objects.
14
- * Modeled after admin-infer-proxy-client's Map<index, toolCall> accumulator.
15
- */
16
- export function accumulateToolCalls(accumulator, chunk) {
17
- let tc = accumulator.get(chunk.index);
18
- if (!tc) {
19
- tc = { id: "", name: "", arguments: "" };
20
- accumulator.set(chunk.index, tc);
21
- }
22
- if (chunk.id)
23
- tc.id = chunk.id;
24
- if (chunk.name)
25
- tc.name += chunk.name;
26
- tc.arguments += chunk.arguments;
27
- }
@@ -1,293 +0,0 @@
1
- /**
2
- * Anthropic Messages Transport — SSE streaming for Claude API.
3
- *
4
- * POST {baseUrl}/v1/messages with stream: true
5
- * Auth: x-api-key: {apiKey} + anthropic-version header
6
- *
7
- * SSE event types:
8
- * message_start, content_block_start, content_block_delta,
9
- * content_block_stop, message_delta, message_stop
10
- *
11
- * Tool use is via content blocks with type "tool_use" + "input_json_delta".
12
- *
13
- * Aligned with Hermes anthropic_messages.py transport.
14
- */
15
- export class AnthropicMessagesTransport {
16
- baseUrl;
17
- apiVersion;
18
- timeoutMs;
19
- constructor(config) {
20
- this.baseUrl = config.baseUrl.replace(/\/+$/, "");
21
- this.apiVersion = config.apiVersion ?? "2023-06-01";
22
- this.timeoutMs = config.timeoutMs ?? 180_000;
23
- }
24
- async *stream(request, apiKey, signal) {
25
- const url = `${this.baseUrl}/v1/messages`;
26
- // Convert OpenAI-style messages → Anthropic format
27
- const { system, messages } = convertMessages(request.messages);
28
- const body = {
29
- model: request.model,
30
- messages,
31
- max_tokens: request.maxTokens ?? 8192,
32
- stream: true,
33
- };
34
- if (system)
35
- body.system = system;
36
- if (request.tools && request.tools.length > 0) {
37
- body.tools = request.tools.map(convertToolDef);
38
- if (request.toolChoice) {
39
- body.tool_choice =
40
- request.toolChoice === "auto"
41
- ? { type: "auto" }
42
- : request.toolChoice === "required"
43
- ? { type: "any" }
44
- : { type: "none" };
45
- }
46
- }
47
- if (request.temperature !== undefined)
48
- body.temperature = request.temperature;
49
- if (request.reasoning) {
50
- body.thinking = {
51
- type: "enabled",
52
- budget_tokens: mapReasoningEffortToBudget(request.reasoning.effort),
53
- };
54
- }
55
- const timeoutSignal = AbortSignal.timeout(this.timeoutMs);
56
- const combinedSignal = signal
57
- ? AbortSignal.any([signal, timeoutSignal])
58
- : timeoutSignal;
59
- const response = await fetch(url, {
60
- method: "POST",
61
- headers: {
62
- "Content-Type": "application/json",
63
- "x-api-key": apiKey,
64
- "anthropic-version": this.apiVersion,
65
- },
66
- body: JSON.stringify(body),
67
- signal: combinedSignal,
68
- });
69
- if (!response.ok) {
70
- const errorBody = await response.text().catch(() => "");
71
- throw new Error(`Anthropic API error ${response.status}: ${errorBody.slice(0, 500)}`);
72
- }
73
- if (!response.body) {
74
- throw new Error("Anthropic API returned no response body");
75
- }
76
- yield* this.parseSSEStream(response.body);
77
- }
78
- async *parseSSEStream(body) {
79
- const decoder = new TextDecoder();
80
- let buffer = "";
81
- let currentEvent = "";
82
- // Track active content blocks for tool_use accumulation
83
- const blocks = new Map();
84
- for await (const raw of body) {
85
- buffer += decoder.decode(raw, { stream: true });
86
- let newlineIdx;
87
- while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
88
- const line = buffer.slice(0, newlineIdx).trim();
89
- buffer = buffer.slice(newlineIdx + 1);
90
- if (!line) {
91
- currentEvent = "";
92
- continue;
93
- }
94
- if (line.startsWith("event: ")) {
95
- currentEvent = line.slice(7).trim();
96
- continue;
97
- }
98
- if (!line.startsWith("data: "))
99
- continue;
100
- const data = line.slice(6);
101
- let parsed;
102
- try {
103
- parsed = JSON.parse(data);
104
- }
105
- catch {
106
- continue;
107
- }
108
- yield* this.mapEvent(currentEvent, parsed, blocks);
109
- }
110
- }
111
- }
112
- *mapEvent(event, data, blocks) {
113
- switch (event) {
114
- case "message_start": {
115
- // Extract usage from message_start
116
- const msg = data.message;
117
- const usage = msg?.usage;
118
- if (usage?.input_tokens) {
119
- yield {
120
- type: "usage",
121
- promptTokens: usage.input_tokens ?? 0,
122
- completionTokens: usage.output_tokens ?? 0,
123
- };
124
- }
125
- break;
126
- }
127
- case "content_block_start": {
128
- const index = data.index;
129
- const block = data.content_block;
130
- if (!block)
131
- break;
132
- const blockType = block.type;
133
- blocks.set(index, {
134
- type: blockType,
135
- id: block.id,
136
- name: block.name,
137
- });
138
- if (blockType === "tool_use") {
139
- yield {
140
- type: "tool_call_delta",
141
- index,
142
- id: block.id,
143
- name: block.name,
144
- arguments: "",
145
- };
146
- }
147
- else if (blockType === "thinking") {
148
- // Thinking block start — no chunk needed
149
- }
150
- break;
151
- }
152
- case "content_block_delta": {
153
- const index = data.index;
154
- const delta = data.delta;
155
- if (!delta)
156
- break;
157
- const deltaType = delta.type;
158
- if (deltaType === "text_delta") {
159
- yield { type: "delta", text: delta.text };
160
- }
161
- else if (deltaType === "input_json_delta") {
162
- yield {
163
- type: "tool_call_delta",
164
- index,
165
- arguments: delta.partial_json,
166
- };
167
- }
168
- else if (deltaType === "thinking_delta") {
169
- yield {
170
- type: "reasoning_delta",
171
- text: delta.thinking,
172
- };
173
- }
174
- break;
175
- }
176
- case "content_block_stop": {
177
- const index = data.index;
178
- blocks.delete(index);
179
- break;
180
- }
181
- case "message_delta": {
182
- const delta = data.delta;
183
- const usage = data.usage;
184
- if (usage) {
185
- yield {
186
- type: "usage",
187
- promptTokens: 0,
188
- completionTokens: usage.output_tokens ?? 0,
189
- };
190
- }
191
- if (delta?.stop_reason) {
192
- yield { type: "done", finishReason: mapAnthropicStopReason(delta.stop_reason) };
193
- }
194
- break;
195
- }
196
- case "message_stop":
197
- // Final event, no data needed
198
- break;
199
- case "error": {
200
- const error = data.error;
201
- throw new Error(`Anthropic stream error: ${error?.message ?? JSON.stringify(data)}`);
202
- }
203
- }
204
- }
205
- }
206
- // ── Stop reason normalization (Anthropic → OpenAI standard) ──────────────────
207
- function mapAnthropicStopReason(reason) {
208
- switch (reason) {
209
- case "end_turn":
210
- case "stop_sequence":
211
- return "stop";
212
- case "tool_use":
213
- return "tool_calls";
214
- case "max_tokens":
215
- return "length";
216
- default:
217
- return reason;
218
- }
219
- }
220
- // ── Reasoning effort → thinking budget (Hermes-aligned) ─────────────────────
221
- const THINKING_BUDGET = {
222
- xhigh: 32000,
223
- high: 16000,
224
- medium: 8000,
225
- low: 4000,
226
- };
227
- function mapReasoningEffortToBudget(effort) {
228
- return THINKING_BUDGET[effort] ?? THINKING_BUDGET.high;
229
- }
230
- // ── Message format conversion (OpenAI → Anthropic) ───────────────────────────
231
- function convertMessages(messages) {
232
- let system;
233
- const out = [];
234
- for (const msg of messages) {
235
- if (msg.role === "system") {
236
- // Anthropic requires system as a top-level param, not a message
237
- system = system ? `${system}\n\n${msg.content ?? ""}` : (msg.content ?? "");
238
- continue;
239
- }
240
- if (msg.role === "user") {
241
- out.push({ role: "user", content: msg.content ?? "" });
242
- }
243
- else if (msg.role === "assistant") {
244
- if (msg.tool_calls && msg.tool_calls.length > 0) {
245
- // Assistant message with tool calls
246
- const content = [];
247
- if (msg.content) {
248
- content.push({ type: "text", text: msg.content });
249
- }
250
- for (const tc of msg.tool_calls) {
251
- let input;
252
- try {
253
- input = JSON.parse(tc.function.arguments);
254
- }
255
- catch {
256
- input = {};
257
- }
258
- content.push({
259
- type: "tool_use",
260
- id: tc.id,
261
- name: tc.function.name,
262
- input,
263
- });
264
- }
265
- out.push({ role: "assistant", content });
266
- }
267
- else {
268
- out.push({ role: "assistant", content: msg.content ?? "" });
269
- }
270
- }
271
- else if (msg.role === "tool") {
272
- // Tool result → Anthropic user message with tool_result content blocks
273
- out.push({
274
- role: "user",
275
- content: [
276
- {
277
- type: "tool_result",
278
- tool_use_id: msg.tool_call_id ?? "",
279
- content: msg.content ?? "",
280
- },
281
- ],
282
- });
283
- }
284
- }
285
- return { system, messages: out };
286
- }
287
- function convertToolDef(tool) {
288
- return {
289
- name: tool.function.name,
290
- description: tool.function.description,
291
- input_schema: tool.function.parameters ?? { type: "object", properties: {} },
292
- };
293
- }