@tyvm/knowhow 0.0.105 → 0.0.107
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.
- package/CONFIG.md +8 -5
- package/package.json +3 -2
- package/scripts/check-model-pricing.ts +509 -0
- package/scripts/compare-openrouter-coverage.ts +576 -0
- package/src/agents/base/base.ts +169 -5
- package/src/agents/tools/execCommand.ts +4 -0
- package/src/agents/tools/executeScript/definition.ts +1 -1
- package/src/agents/tools/index.ts +0 -1
- package/src/agents/tools/list.ts +3 -43
- package/src/agents/tools/writeFile.ts +1 -1
- package/src/auth/browserLogin.ts +9 -4
- package/src/chat/modules/RemoteSyncModule.ts +3 -0
- package/src/cli.ts +31 -1
- package/src/clients/anthropic.ts +8 -2
- package/src/clients/cerebras.ts +10 -0
- package/src/clients/contextLimits.ts +7 -2
- package/src/clients/copilot.ts +23 -0
- package/src/clients/deepseek.ts +16 -0
- package/src/clients/fireworks.ts +15 -0
- package/src/clients/gemini.ts +59 -4
- package/src/clients/github.ts +16 -0
- package/src/clients/groq.ts +15 -0
- package/src/clients/http.ts +194 -6
- package/src/clients/index.ts +116 -4
- package/src/clients/llama.ts +16 -0
- package/src/clients/mistral.ts +16 -0
- package/src/clients/nvidia.ts +16 -0
- package/src/clients/openai.ts +53 -12
- package/src/clients/openrouter.ts +17 -0
- package/src/clients/pricing/anthropic.ts +105 -78
- package/src/clients/pricing/cerebras.ts +11 -0
- package/src/clients/pricing/copilot.ts +60 -0
- package/src/clients/pricing/deepseek.ts +15 -0
- package/src/clients/pricing/fireworks.ts +32 -0
- package/src/clients/pricing/github.ts +69 -0
- package/src/clients/pricing/google.ts +245 -206
- package/src/clients/pricing/groq.ts +56 -0
- package/src/clients/pricing/index.ts +42 -5
- package/src/clients/pricing/llama.ts +18 -0
- package/src/clients/pricing/mistral.ts +34 -0
- package/src/clients/pricing/models.ts +7 -236
- package/src/clients/pricing/nvidia.ts +102 -0
- package/src/clients/pricing/openai.ts +348 -171
- package/src/clients/pricing/openrouter.ts +36 -0
- package/src/clients/pricing/types.ts +83 -2
- package/src/clients/pricing/xai.ts +121 -65
- package/src/clients/types.ts +28 -1
- package/src/clients/xai.ts +161 -1
- package/src/fileSync.ts +8 -2
- package/src/login.ts +11 -3
- package/src/services/AgentSyncFs.ts +36 -12
- package/src/services/KnowhowClient.ts +11 -0
- package/src/services/LazyToolsService.ts +6 -0
- package/src/services/S3.ts +0 -7
- package/src/services/modules/index.ts +11 -2
- package/src/types.ts +56 -279
- package/src/worker.ts +174 -0
- package/tests/clients/AIClient.test.ts +1 -1
- package/tests/clients/anthropic.test.ts +202 -0
- package/tests/clients/pricing.test.ts +37 -0
- package/tests/manual/clients/completions.json +838 -226
- package/tests/manual/clients/completions.test.ts +46 -31
- package/ts_build/package.json +3 -2
- package/ts_build/src/agents/base/base.d.ts +18 -1
- package/ts_build/src/agents/base/base.js +111 -4
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/execCommand.js +3 -0
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/executeScript/definition.js +1 -1
- package/ts_build/src/agents/tools/executeScript/definition.js.map +1 -1
- package/ts_build/src/agents/tools/index.d.ts +0 -1
- package/ts_build/src/agents/tools/index.js +0 -1
- package/ts_build/src/agents/tools/index.js.map +1 -1
- package/ts_build/src/agents/tools/list.js +3 -38
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
- package/ts_build/src/agents/tools/writeFile.js +1 -1
- package/ts_build/src/agents/tools/writeFile.js.map +1 -1
- package/ts_build/src/ai.d.ts +1 -1
- package/ts_build/src/auth/browserLogin.d.ts +2 -1
- package/ts_build/src/auth/browserLogin.js +10 -3
- package/ts_build/src/auth/browserLogin.js.map +1 -1
- package/ts_build/src/chat/modules/RemoteSyncModule.js +1 -0
- package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
- package/ts_build/src/cli.js +19 -0
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.d.ts +1 -82
- package/ts_build/src/clients/anthropic.js +8 -2
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/cerebras.d.ts +4 -0
- package/ts_build/src/clients/cerebras.js +14 -0
- package/ts_build/src/clients/cerebras.js.map +1 -0
- package/ts_build/src/clients/contextLimits.js +7 -2
- package/ts_build/src/clients/contextLimits.js.map +1 -1
- package/ts_build/src/clients/copilot.d.ts +4 -0
- package/ts_build/src/clients/copilot.js +15 -0
- package/ts_build/src/clients/copilot.js.map +1 -0
- package/ts_build/src/clients/deepseek.d.ts +4 -0
- package/ts_build/src/clients/deepseek.js +15 -0
- package/ts_build/src/clients/deepseek.js.map +1 -0
- package/ts_build/src/clients/fireworks.d.ts +4 -0
- package/ts_build/src/clients/fireworks.js +15 -0
- package/ts_build/src/clients/fireworks.js.map +1 -0
- package/ts_build/src/clients/gemini.d.ts +1 -0
- package/ts_build/src/clients/gemini.js +38 -2
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/github.d.ts +4 -0
- package/ts_build/src/clients/github.js +15 -0
- package/ts_build/src/clients/github.js.map +1 -0
- package/ts_build/src/clients/groq.d.ts +4 -0
- package/ts_build/src/clients/groq.js +15 -0
- package/ts_build/src/clients/groq.js.map +1 -0
- package/ts_build/src/clients/http.d.ts +22 -1
- package/ts_build/src/clients/http.js +135 -7
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/index.d.ts +14 -0
- package/ts_build/src/clients/index.js +94 -4
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/llama.d.ts +4 -0
- package/ts_build/src/clients/llama.js +15 -0
- package/ts_build/src/clients/llama.js.map +1 -0
- package/ts_build/src/clients/mistral.d.ts +4 -0
- package/ts_build/src/clients/mistral.js +15 -0
- package/ts_build/src/clients/mistral.js.map +1 -0
- package/ts_build/src/clients/nvidia.d.ts +4 -0
- package/ts_build/src/clients/nvidia.js +15 -0
- package/ts_build/src/clients/nvidia.js.map +1 -0
- package/ts_build/src/clients/openai.d.ts +4 -206
- package/ts_build/src/clients/openai.js +38 -10
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/openrouter.d.ts +4 -0
- package/ts_build/src/clients/openrouter.js +15 -0
- package/ts_build/src/clients/openrouter.js.map +1 -0
- package/ts_build/src/clients/pricing/anthropic.d.ts +26 -78
- package/ts_build/src/clients/pricing/anthropic.js +75 -78
- package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
- package/ts_build/src/clients/pricing/cerebras.d.ts +4 -0
- package/ts_build/src/clients/pricing/cerebras.js +11 -0
- package/ts_build/src/clients/pricing/cerebras.js.map +1 -0
- package/ts_build/src/clients/pricing/copilot.d.ts +5 -0
- package/ts_build/src/clients/pricing/copilot.js +35 -0
- package/ts_build/src/clients/pricing/copilot.js.map +1 -0
- package/ts_build/src/clients/pricing/deepseek.d.ts +5 -0
- package/ts_build/src/clients/pricing/deepseek.js +10 -0
- package/ts_build/src/clients/pricing/deepseek.js.map +1 -0
- package/ts_build/src/clients/pricing/fireworks.d.ts +5 -0
- package/ts_build/src/clients/pricing/fireworks.js +21 -0
- package/ts_build/src/clients/pricing/fireworks.js.map +1 -0
- package/ts_build/src/clients/pricing/github.d.ts +4 -0
- package/ts_build/src/clients/pricing/github.js +58 -0
- package/ts_build/src/clients/pricing/github.js.map +1 -0
- package/ts_build/src/clients/pricing/google.d.ts +59 -6
- package/ts_build/src/clients/pricing/google.js +214 -167
- package/ts_build/src/clients/pricing/google.js.map +1 -1
- package/ts_build/src/clients/pricing/groq.d.ts +5 -0
- package/ts_build/src/clients/pricing/groq.js +41 -0
- package/ts_build/src/clients/pricing/groq.js.map +1 -0
- package/ts_build/src/clients/pricing/index.d.ts +16 -5
- package/ts_build/src/clients/pricing/index.js +62 -7
- package/ts_build/src/clients/pricing/index.js.map +1 -1
- package/ts_build/src/clients/pricing/llama.d.ts +4 -0
- package/ts_build/src/clients/pricing/llama.js +14 -0
- package/ts_build/src/clients/pricing/llama.js.map +1 -0
- package/ts_build/src/clients/pricing/mistral.d.ts +5 -0
- package/ts_build/src/clients/pricing/mistral.js +23 -0
- package/ts_build/src/clients/pricing/mistral.js.map +1 -0
- package/ts_build/src/clients/pricing/models.d.ts +5 -4
- package/ts_build/src/clients/pricing/models.js +8 -162
- package/ts_build/src/clients/pricing/models.js.map +1 -1
- package/ts_build/src/clients/pricing/nvidia.d.ts +8 -0
- package/ts_build/src/clients/pricing/nvidia.js +96 -0
- package/ts_build/src/clients/pricing/nvidia.js.map +1 -0
- package/ts_build/src/clients/pricing/openai.d.ts +86 -197
- package/ts_build/src/clients/pricing/openai.js +295 -168
- package/ts_build/src/clients/pricing/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/openrouter.d.ts +4 -0
- package/ts_build/src/clients/pricing/openrouter.js +29 -0
- package/ts_build/src/clients/pricing/openrouter.js.map +1 -0
- package/ts_build/src/clients/pricing/types.d.ts +27 -2
- package/ts_build/src/clients/pricing/types.js +46 -0
- package/ts_build/src/clients/pricing/types.js.map +1 -1
- package/ts_build/src/clients/pricing/xai.d.ts +37 -57
- package/ts_build/src/clients/pricing/xai.js +92 -59
- package/ts_build/src/clients/pricing/xai.js.map +1 -1
- package/ts_build/src/clients/types.d.ts +12 -1
- package/ts_build/src/clients/xai.d.ts +2 -62
- package/ts_build/src/clients/xai.js +132 -1
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/fileSync.js +7 -2
- package/ts_build/src/fileSync.js.map +1 -1
- package/ts_build/src/login.js +8 -2
- package/ts_build/src/login.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.js +1 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +1 -0
- package/ts_build/src/services/KnowhowClient.js +7 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/LazyToolsService.d.ts +1 -0
- package/ts_build/src/services/LazyToolsService.js +3 -0
- package/ts_build/src/services/LazyToolsService.js.map +1 -1
- package/ts_build/src/services/S3.js +0 -7
- package/ts_build/src/services/S3.js.map +1 -1
- package/ts_build/src/services/modules/index.js +41 -1
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/types.d.ts +163 -124
- package/ts_build/src/types.js +33 -213
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/worker.d.ts +4 -0
- package/ts_build/src/worker.js +140 -0
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/clients/AIClient.test.js +1 -1
- package/ts_build/tests/clients/AIClient.test.js.map +1 -1
- package/ts_build/tests/clients/anthropic.test.d.ts +1 -0
- package/ts_build/tests/clients/anthropic.test.js +159 -0
- package/ts_build/tests/clients/anthropic.test.js.map +1 -0
- package/ts_build/tests/clients/pricing.test.js +21 -0
- package/ts_build/tests/clients/pricing.test.js.map +1 -1
- package/ts_build/tests/manual/clients/completions.test.js +27 -24
- package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
package/src/agents/base/base.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from "events"; // kept for reference; agentEvents now uses EventService
|
|
2
2
|
import {
|
|
3
|
+
CompletionResponse,
|
|
3
4
|
GenericClient,
|
|
4
5
|
Message,
|
|
5
6
|
MessageContent,
|
|
@@ -59,6 +60,10 @@ export abstract class BaseAgent implements IAgent {
|
|
|
59
60
|
protected turnCount = 0;
|
|
60
61
|
protected totalCostUsd = 0;
|
|
61
62
|
protected currentThread = 0;
|
|
63
|
+
protected totalInputTokens = 0;
|
|
64
|
+
protected totalOutputTokens = 0;
|
|
65
|
+
protected totalCacheReadTokens = 0;
|
|
66
|
+
protected totalCacheWriteTokens = 0;
|
|
62
67
|
|
|
63
68
|
protected compressThreshold = 30000;
|
|
64
69
|
protected compressMinMessages = 30;
|
|
@@ -95,6 +100,7 @@ export abstract class BaseAgent implements IAgent {
|
|
|
95
100
|
agentSay: "agent:say",
|
|
96
101
|
agentNewTask: "agent:newTask",
|
|
97
102
|
agentTaskComplete: "agent:taskComplete",
|
|
103
|
+
tokenUsage: "agent:tokenUsage",
|
|
98
104
|
};
|
|
99
105
|
|
|
100
106
|
public tools: ToolsService;
|
|
@@ -194,6 +200,10 @@ export abstract class BaseAgent implements IAgent {
|
|
|
194
200
|
this.taskBreakdown = "";
|
|
195
201
|
this.summaries = [];
|
|
196
202
|
this.totalCostUsd = 0;
|
|
203
|
+
this.totalInputTokens = 0;
|
|
204
|
+
this.totalOutputTokens = 0;
|
|
205
|
+
this.totalCacheReadTokens = 0;
|
|
206
|
+
this.totalCacheWriteTokens = 0;
|
|
197
207
|
this.status = this.eventTypes.inProgress;
|
|
198
208
|
this.turnCount = 0;
|
|
199
209
|
this.startTimeMs = Date.now();
|
|
@@ -283,6 +293,33 @@ export abstract class BaseAgent implements IAgent {
|
|
|
283
293
|
this.easyFinalAnswer = value;
|
|
284
294
|
}
|
|
285
295
|
|
|
296
|
+
/**
|
|
297
|
+
* Detect if the model's response is a termination signal (e.g. "Done", "Complete", "Finished", "finalAnswer")
|
|
298
|
+
* This handles the case where an agent refuses to call finalAnswer and just says a short termination word.
|
|
299
|
+
*/
|
|
300
|
+
protected isTerminationResponse(content: string): boolean {
|
|
301
|
+
const trimmed = content.trim();
|
|
302
|
+
// Short response (≤ 3 words) that matches a termination word/phrase exactly
|
|
303
|
+
const wordCount = trimmed.split(/\s+/).filter(Boolean).length;
|
|
304
|
+
if (wordCount <= 3) {
|
|
305
|
+
const terminationPattern = /^(done|complete|completed|finished|final\s*answer|task\s*complete|all\s*done|that'?s\s*(all|it)|ok(ay)?|yes)[.!]*$/i;
|
|
306
|
+
if (terminationPattern.test(trimmed)) return true;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Check if the first 1-3 words indicate task completion (for longer responses)
|
|
310
|
+
// e.g. "Task complete: ...", "All done.", "No further changes needed.", "Confirmed complete."
|
|
311
|
+
const firstWords = trimmed.split(/\s+/).slice(0, 3).join(" ");
|
|
312
|
+
const firstWordPattern = /^(task\s*(complete|completed|done|finished)|all\s*done|no\s*(further|more|additional|changes|action)|confirmed?\s*(complete|done|finished|one\s*last)|nothing\s*(more|further|else)|standing\s*by|everything\s*is|still\s*confirmed|acknowledged|done\s*and|complete\s*(and|\.)|completed\s*successfully|no\s*additional|verified\s*and)/i;
|
|
313
|
+
if (firstWordPattern.test(firstWords)) return true;
|
|
314
|
+
|
|
315
|
+
// If easyFinalAnswer mode is on, also match response starting with "✅" or numbered confirmation lists
|
|
316
|
+
if (this.easyFinalAnswer) {
|
|
317
|
+
if (trimmed.startsWith("✅") || /^[\d\.\-\*]/.test(trimmed)) return true;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
|
|
286
323
|
getEnabledTools() {
|
|
287
324
|
return this.tools
|
|
288
325
|
.getTools()
|
|
@@ -369,6 +406,44 @@ export abstract class BaseAgent implements IAgent {
|
|
|
369
406
|
return this.totalCostUsd;
|
|
370
407
|
}
|
|
371
408
|
|
|
409
|
+
adjustTokenUsage(usage: any) {
|
|
410
|
+
if (!usage) return;
|
|
411
|
+
// Support both OpenAI-style (prompt_tokens/completion_tokens) and Anthropic-style (input_tokens/output_tokens)
|
|
412
|
+
const inputTokens = usage.input_tokens ?? usage.prompt_tokens ?? 0;
|
|
413
|
+
const outputTokens = usage.output_tokens ?? usage.completion_tokens ?? 0;
|
|
414
|
+
|
|
415
|
+
const cacheReadTokens =
|
|
416
|
+
usage.cache_read_input_tokens ?? usage.cache_read_tokens ??
|
|
417
|
+
usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
418
|
+
const cacheWriteTokens =
|
|
419
|
+
usage.cache_creation_input_tokens ?? usage.cache_write_tokens ?? 0;
|
|
420
|
+
|
|
421
|
+
this.totalInputTokens += inputTokens;
|
|
422
|
+
this.totalOutputTokens += outputTokens;
|
|
423
|
+
this.totalCacheReadTokens += cacheReadTokens;
|
|
424
|
+
this.totalCacheWriteTokens += cacheWriteTokens;
|
|
425
|
+
|
|
426
|
+
this.agentEvents.emit(this.eventTypes.tokenUsage, {
|
|
427
|
+
inputTokens,
|
|
428
|
+
outputTokens,
|
|
429
|
+
cacheReadTokens,
|
|
430
|
+
cacheWriteTokens,
|
|
431
|
+
totalInputTokens: this.totalInputTokens,
|
|
432
|
+
totalOutputTokens: this.totalOutputTokens,
|
|
433
|
+
totalCacheReadTokens: this.totalCacheReadTokens,
|
|
434
|
+
totalCacheWriteTokens: this.totalCacheWriteTokens,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
getTokenUsage() {
|
|
439
|
+
return {
|
|
440
|
+
totalInputTokens: this.totalInputTokens,
|
|
441
|
+
totalOutputTokens: this.totalOutputTokens,
|
|
442
|
+
totalCacheReadTokens: this.totalCacheReadTokens,
|
|
443
|
+
totalCacheWriteTokens: this.totalCacheWriteTokens,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
372
447
|
startNewThread(messages: Message[]) {
|
|
373
448
|
this.currentThread++;
|
|
374
449
|
this.agentEvents.emit(this.eventTypes.newThread, messages);
|
|
@@ -544,8 +619,14 @@ export abstract class BaseAgent implements IAgent {
|
|
|
544
619
|
|
|
545
620
|
async kill() {
|
|
546
621
|
this.log("Killing agent");
|
|
547
|
-
if (
|
|
548
|
-
this.
|
|
622
|
+
if (
|
|
623
|
+
this.status === this.eventTypes.kill ||
|
|
624
|
+
this.status === this.eventTypes.done
|
|
625
|
+
) {
|
|
626
|
+
this.log(
|
|
627
|
+
"Agent is already being killed or done, ignoring duplicate kill()",
|
|
628
|
+
"warn"
|
|
629
|
+
);
|
|
549
630
|
return;
|
|
550
631
|
}
|
|
551
632
|
this.agentEvents.emit(this.eventTypes.kill, this);
|
|
@@ -651,15 +732,22 @@ export abstract class BaseAgent implements IAgent {
|
|
|
651
732
|
"warn"
|
|
652
733
|
);
|
|
653
734
|
const error = response as any;
|
|
654
|
-
if ("response" in error && "data" in error.response) {
|
|
735
|
+
if (error != null && "response" in error && "data" in error.response) {
|
|
655
736
|
this.log(
|
|
656
737
|
`Response data: ${JSON.stringify(error.response.data, null, 2)}`,
|
|
657
738
|
"warn"
|
|
658
739
|
);
|
|
659
740
|
}
|
|
741
|
+
if (!response?.choices) {
|
|
742
|
+
const errMsg =
|
|
743
|
+
(error?.error?.message ?? error?.message) ||
|
|
744
|
+
JSON.stringify(response);
|
|
745
|
+
throw new Error(`AI response error: ${errMsg}`);
|
|
746
|
+
}
|
|
660
747
|
}
|
|
661
748
|
|
|
662
749
|
this.adjustTotalCostUsd(response?.usd_cost);
|
|
750
|
+
this.adjustTokenUsage(response?.usage);
|
|
663
751
|
this.log("agent response cost: " + response?.usd_cost);
|
|
664
752
|
|
|
665
753
|
// Typically, there's only one choice in the array, but you could have many
|
|
@@ -687,6 +775,16 @@ export abstract class BaseAgent implements IAgent {
|
|
|
687
775
|
|
|
688
776
|
this.updateCurrentThread(messages);
|
|
689
777
|
|
|
778
|
+
const truncationWarning = this.detectTruncatedToolCalls(
|
|
779
|
+
toolCalls,
|
|
780
|
+
response
|
|
781
|
+
);
|
|
782
|
+
if (truncationWarning) {
|
|
783
|
+
messages.push(truncationWarning as Message);
|
|
784
|
+
this.updateCurrentThread(messages);
|
|
785
|
+
return this.call(userInput, messages);
|
|
786
|
+
}
|
|
787
|
+
|
|
690
788
|
for (const toolCall of toolCalls) {
|
|
691
789
|
if (this.status === this.eventTypes.pause) {
|
|
692
790
|
this.log(
|
|
@@ -755,6 +853,18 @@ export abstract class BaseAgent implements IAgent {
|
|
|
755
853
|
|
|
756
854
|
// Early exit: not required to call tool
|
|
757
855
|
const firstMessage = response.choices[0].message;
|
|
856
|
+
// Auto-detect termination words: if the model is just saying "Done", "Complete", etc.
|
|
857
|
+
if (
|
|
858
|
+
response.choices.length === 1 &&
|
|
859
|
+
firstMessage.content &&
|
|
860
|
+
this.isTerminationResponse(firstMessage.content)
|
|
861
|
+
) {
|
|
862
|
+
this.log(`Termination word detected: "${firstMessage.content.trim()}", treating as finalAnswer`);
|
|
863
|
+
this.status = this.eventTypes.done;
|
|
864
|
+
this.agentEvents.emit(this.eventTypes.done, firstMessage.content);
|
|
865
|
+
return firstMessage.content;
|
|
866
|
+
}
|
|
867
|
+
|
|
758
868
|
if (
|
|
759
869
|
response.choices.length === 1 &&
|
|
760
870
|
firstMessage.content &&
|
|
@@ -808,7 +918,7 @@ export abstract class BaseAgent implements IAgent {
|
|
|
808
918
|
this.logStatus();
|
|
809
919
|
|
|
810
920
|
const continuation = `<Workflow>
|
|
811
|
-
workflow continues until you call one of ${this.requiredToolNames}.\n
|
|
921
|
+
workflow continues until you call one of ${JSON.stringify(this.requiredToolNames)}.\n
|
|
812
922
|
${statusMessage}
|
|
813
923
|
</Workflow>`;
|
|
814
924
|
|
|
@@ -854,7 +964,7 @@ export abstract class BaseAgent implements IAgent {
|
|
|
854
964
|
|
|
855
965
|
this.log(`Agent failed: ${e}`, "error");
|
|
856
966
|
|
|
857
|
-
if ("response" in e && "data" in e.response) {
|
|
967
|
+
if (e != null && typeof e === "object" && "response" in e && "data" in (e as any).response) {
|
|
858
968
|
this.log(
|
|
859
969
|
`Error response data: ${JSON.stringify(e.response.data, null, 2)}`,
|
|
860
970
|
"error"
|
|
@@ -958,6 +1068,60 @@ export abstract class BaseAgent implements IAgent {
|
|
|
958
1068
|
return JSON.stringify(messages).split(" ").length;
|
|
959
1069
|
}
|
|
960
1070
|
|
|
1071
|
+
/**
|
|
1072
|
+
* Detects whether tool call arguments appear truncated due to hitting the output token limit.
|
|
1073
|
+
* Two signals are checked:
|
|
1074
|
+
* 1. Any tool call argument is empty or invalid JSON (hard truncation).
|
|
1075
|
+
* 2. The model reported many output tokens but the total argument content received is tiny
|
|
1076
|
+
* relative to what those tokens should represent (soft/silent truncation).
|
|
1077
|
+
*
|
|
1078
|
+
* Returns a warning system message if truncation is detected, or null otherwise.
|
|
1079
|
+
*/
|
|
1080
|
+
detectTruncatedToolCalls(
|
|
1081
|
+
toolCalls: ToolCall[],
|
|
1082
|
+
response: CompletionResponse
|
|
1083
|
+
): { role: string; content: string } | null {
|
|
1084
|
+
const outputTokens: number = response?.usage?.completion_tokens || 0;
|
|
1085
|
+
const totalArgLength = toolCalls.reduce(
|
|
1086
|
+
(sum, tc) => sum + (tc.function?.arguments?.length || 0),
|
|
1087
|
+
0
|
|
1088
|
+
);
|
|
1089
|
+
|
|
1090
|
+
// Percentage-based heuristic: if actual arg chars are less than ~10% of the
|
|
1091
|
+
// expected chars (outputTokens * 4 chars/token), the output was likely truncated.
|
|
1092
|
+
// Only apply when outputTokens > 1000 to avoid false positives on small responses.
|
|
1093
|
+
const expectedArgChars = outputTokens * 4;
|
|
1094
|
+
const suspiciouslySmallArgs =
|
|
1095
|
+
outputTokens > 1000 && totalArgLength < expectedArgChars * 0.1;
|
|
1096
|
+
|
|
1097
|
+
for (const toolCall of toolCalls) {
|
|
1098
|
+
const args = toolCall.function?.arguments || "";
|
|
1099
|
+
let isInvalidJson = false;
|
|
1100
|
+
try {
|
|
1101
|
+
JSON.parse(args);
|
|
1102
|
+
} catch {
|
|
1103
|
+
isInvalidJson = true;
|
|
1104
|
+
}
|
|
1105
|
+
if (isInvalidJson || args.trim() === "" || suspiciouslySmallArgs) {
|
|
1106
|
+
this.log(
|
|
1107
|
+
`Tool call '${toolCall.function?.name}' has malformed/truncated arguments — likely hit output token limit (outputTokens=${outputTokens}, argLength=${args.length})`,
|
|
1108
|
+
"warn"
|
|
1109
|
+
);
|
|
1110
|
+
return {
|
|
1111
|
+
role: "user",
|
|
1112
|
+
content:
|
|
1113
|
+
"⚠️ Output limit warning: Your last tool call had incomplete or missing arguments, which usually means you exceeded the output token limit mid-response. The model reported " +
|
|
1114
|
+
outputTokens +
|
|
1115
|
+
" output tokens but only " +
|
|
1116
|
+
totalArgLength +
|
|
1117
|
+
" characters of tool call arguments were received. Please write smaller, more concise content in your tool calls. Aim for no more than 4000 tokens of output per response. Break large responses into smaller pieces if needed.",
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
961
1125
|
async getTaskBreakdown(messages: Message[]) {
|
|
962
1126
|
if (this.taskBreakdown) {
|
|
963
1127
|
return this.taskBreakdown;
|
|
@@ -262,6 +262,10 @@ export const execCommand = async (
|
|
|
262
262
|
continueInBackground?: boolean,
|
|
263
263
|
logFileName?: string
|
|
264
264
|
): Promise<string> => {
|
|
265
|
+
if(!command || typeof command !== "string") {
|
|
266
|
+
throw new Error("Invalid command. We received a non-string value. Please ensure you are sending strings of 4k tokens or less.");
|
|
267
|
+
}
|
|
268
|
+
|
|
265
269
|
const { stdout, stderr, timedOut, killed, pid, logPath } =
|
|
266
270
|
await execWithTimeout(command, {
|
|
267
271
|
timeout,
|
|
@@ -53,7 +53,7 @@ export const executeScriptDefinition: Tool = {
|
|
|
53
53
|
properties: {
|
|
54
54
|
script: {
|
|
55
55
|
type: "string",
|
|
56
|
-
description: "The TypeScript code to execute",
|
|
56
|
+
description: "The TypeScript code to execute. 4000 tokens or less",
|
|
57
57
|
},
|
|
58
58
|
maxToolCalls: {
|
|
59
59
|
type: "number",
|
|
@@ -19,7 +19,6 @@ export * from "./language";
|
|
|
19
19
|
export * from "./askHuman";
|
|
20
20
|
export * from "./aiClient";
|
|
21
21
|
export * from "./googleSearch";
|
|
22
|
-
export * from "./loadWebpage";
|
|
23
22
|
export * from "./stringReplace";
|
|
24
23
|
export * from "./executeScript";
|
|
25
24
|
export * from "./startAgentTask";
|
package/src/agents/tools/list.ts
CHANGED
|
@@ -55,7 +55,7 @@ export const includedTools = [
|
|
|
55
55
|
properties: {
|
|
56
56
|
command: {
|
|
57
57
|
type: "string",
|
|
58
|
-
description: "The command to execute",
|
|
58
|
+
description: "The command to execute. 4000 tokens or less",
|
|
59
59
|
},
|
|
60
60
|
timeout: {
|
|
61
61
|
type: "number",
|
|
@@ -346,7 +346,7 @@ export const includedTools = [
|
|
|
346
346
|
function: {
|
|
347
347
|
name: "writeFileChunk",
|
|
348
348
|
description:
|
|
349
|
-
"Update or create files by writing in small chunks of text. Suitable for larger files, this tool allows incremental writing by calling it multiple times.",
|
|
349
|
+
"Update or create files by writing in small chunks of text. Suitable for larger files, this tool allows incremental writing by calling it multiple times. Write chunks of around 4000 tokens",
|
|
350
350
|
parameters: {
|
|
351
351
|
type: "object",
|
|
352
352
|
positional: true,
|
|
@@ -358,7 +358,7 @@ export const includedTools = [
|
|
|
358
358
|
},
|
|
359
359
|
content: {
|
|
360
360
|
type: "string",
|
|
361
|
-
description: "The chunk of content to write to the file",
|
|
361
|
+
description: "The chunk of content to write to the file. 4000 tokens or less",
|
|
362
362
|
},
|
|
363
363
|
isContinuing: {
|
|
364
364
|
type: "boolean",
|
|
@@ -631,46 +631,6 @@ export const includedTools = [
|
|
|
631
631
|
},
|
|
632
632
|
},
|
|
633
633
|
},
|
|
634
|
-
{
|
|
635
|
-
type: "function",
|
|
636
|
-
function: {
|
|
637
|
-
name: "loadWebpage",
|
|
638
|
-
description:
|
|
639
|
-
"Load a webpage using a stealth browser to avoid bot detection. Can return either text content with console logs or a screenshot.",
|
|
640
|
-
parameters: {
|
|
641
|
-
type: "object",
|
|
642
|
-
positional: true,
|
|
643
|
-
properties: {
|
|
644
|
-
url: {
|
|
645
|
-
type: "string",
|
|
646
|
-
description: "The URL of the webpage to load",
|
|
647
|
-
},
|
|
648
|
-
mode: {
|
|
649
|
-
type: "string",
|
|
650
|
-
description:
|
|
651
|
-
"The mode for content extraction: 'text' for text content with console logs, 'screenshot' for a base64 encoded screenshot",
|
|
652
|
-
enum: ["text", "screenshot"],
|
|
653
|
-
},
|
|
654
|
-
waitForSelector: {
|
|
655
|
-
type: "string",
|
|
656
|
-
description:
|
|
657
|
-
"Optional CSS selector to wait for before extracting content",
|
|
658
|
-
},
|
|
659
|
-
timeout: {
|
|
660
|
-
type: "number",
|
|
661
|
-
description:
|
|
662
|
-
"Timeout in milliseconds for page loading (default: 30000)",
|
|
663
|
-
},
|
|
664
|
-
},
|
|
665
|
-
required: ["url"],
|
|
666
|
-
},
|
|
667
|
-
returns: {
|
|
668
|
-
type: "string",
|
|
669
|
-
description:
|
|
670
|
-
"The webpage content as text with console logs, or a base64 encoded screenshot",
|
|
671
|
-
},
|
|
672
|
-
},
|
|
673
|
-
},
|
|
674
634
|
{
|
|
675
635
|
type: "function",
|
|
676
636
|
function: {
|
|
@@ -28,7 +28,7 @@ export async function writeFileChunk(
|
|
|
28
28
|
`File path and content are both required. We received: ${JSON.stringify({
|
|
29
29
|
filePath,
|
|
30
30
|
content,
|
|
31
|
-
})}. Make sure you write small chunks of content, otherwise you will hit output limits, resulting in content being empty.`
|
|
31
|
+
})}. Make sure you write small chunks of content (4k tokens), otherwise you will hit output limits, resulting in content being empty.`
|
|
32
32
|
);
|
|
33
33
|
}
|
|
34
34
|
|
package/src/auth/browserLogin.ts
CHANGED
|
@@ -26,7 +26,7 @@ interface RetrieveTokenResponse {
|
|
|
26
26
|
export class BrowserLoginService {
|
|
27
27
|
private baseUrl: string;
|
|
28
28
|
|
|
29
|
-
constructor(baseUrl: string = KNOWHOW_API_URL) {
|
|
29
|
+
constructor(baseUrl: string = KNOWHOW_API_URL, private orgId?: string) {
|
|
30
30
|
if (!baseUrl) {
|
|
31
31
|
throw new BrowserLoginError(
|
|
32
32
|
"KNOWHOW_API_URL environment variable not set"
|
|
@@ -52,11 +52,16 @@ export class BrowserLoginService {
|
|
|
52
52
|
spinner.start("Opening browser for authentication");
|
|
53
53
|
|
|
54
54
|
// Step 2: Open browser
|
|
55
|
-
|
|
55
|
+
let browserUrl = sessionData.browserUrl;
|
|
56
|
+
// Append orgId as query string so the frontend can pre-select the correct organization
|
|
57
|
+
if (this.orgId) {
|
|
58
|
+
const separator = browserUrl.includes("?") ? "&" : "?";
|
|
59
|
+
browserUrl = `${browserUrl}${separator}orgId=${encodeURIComponent(this.orgId)}`;
|
|
60
|
+
}
|
|
61
|
+
await openBrowser(browserUrl);
|
|
56
62
|
console.log(
|
|
57
|
-
`\nIf the browser didn't open automatically, please visit: ${
|
|
63
|
+
`\nIf the browser didn't open automatically, please visit: ${browserUrl}\n`
|
|
58
64
|
);
|
|
59
|
-
|
|
60
65
|
spinner.stop();
|
|
61
66
|
spinner.start("Waiting for browser authentication");
|
|
62
67
|
|
|
@@ -247,6 +247,9 @@ export class RemoteSyncModule extends BaseChatModule {
|
|
|
247
247
|
const registry = this.agentModule.getTaskRegistry();
|
|
248
248
|
const taskInfo = registry.get(taskId);
|
|
249
249
|
|
|
250
|
+
// Refresh JWT in case it was updated since client was instantiated (e.g. after knowhow login)
|
|
251
|
+
this.client.refreshJwt();
|
|
252
|
+
|
|
250
253
|
if (!taskInfo) {
|
|
251
254
|
console.log(
|
|
252
255
|
`⚠️ Task "${taskId}" not found in registry.`
|
package/src/cli.ts
CHANGED
|
@@ -14,9 +14,10 @@ import { includedTools } from "./agents/tools/list";
|
|
|
14
14
|
import * as allTools from "./agents/tools";
|
|
15
15
|
import { LazyToolsService, services } from "./services";
|
|
16
16
|
import { login } from "./login";
|
|
17
|
-
import { worker } from "./worker";
|
|
17
|
+
import { worker, tunnel } from "./worker";
|
|
18
18
|
import { fileSync } from "./fileSync";
|
|
19
19
|
import { KnowhowSimpleClient } from "./services/KnowhowClient";
|
|
20
|
+
import { ModulesService } from "./services/modules";
|
|
20
21
|
import {
|
|
21
22
|
startAllWorkers,
|
|
22
23
|
listWorkerPaths,
|
|
@@ -56,6 +57,7 @@ async function setupServices() {
|
|
|
56
57
|
const { Agents, Mcp, Clients, Tools: OldTools } = services();
|
|
57
58
|
const Tools = new LazyToolsService(); // eslint-disable-line no-shadow
|
|
58
59
|
|
|
60
|
+
// Load modules from config first so module-provided tools/agents/plugins are available
|
|
59
61
|
// We need to wireup the LazyTools to be connected to the same singletons that are in services()
|
|
60
62
|
Tools.setContext({
|
|
61
63
|
...OldTools.getContext(),
|
|
@@ -100,6 +102,19 @@ async function setupServices() {
|
|
|
100
102
|
await Clients.registerConfiguredModels();
|
|
101
103
|
console.log("✓ Services are set up and ready to go!");
|
|
102
104
|
|
|
105
|
+
// Load modules (tools, plugins, agents) from knowhow.json config
|
|
106
|
+
console.log("📦 Loading modules from config...");
|
|
107
|
+
const modulesService = new ModulesService();
|
|
108
|
+
await modulesService.loadModulesFromConfig({
|
|
109
|
+
Agents,
|
|
110
|
+
Embeddings: services().Embeddings,
|
|
111
|
+
Plugins: services().Plugins,
|
|
112
|
+
Clients,
|
|
113
|
+
// Use LazyToolsService so module-provided tools are visible to agents and scripts
|
|
114
|
+
Tools: Tools as any,
|
|
115
|
+
MediaProcessor: services().MediaProcessor,
|
|
116
|
+
});
|
|
117
|
+
|
|
103
118
|
// Return both LazyToolsService (for agents) and OldTools (plain ToolsService with all tools for scripts)
|
|
104
119
|
return { Tools, Clients, PlainTools: OldTools };
|
|
105
120
|
}
|
|
@@ -527,6 +542,21 @@ async function main() {
|
|
|
527
542
|
}
|
|
528
543
|
});
|
|
529
544
|
|
|
545
|
+
program
|
|
546
|
+
.command("tunnel")
|
|
547
|
+
.description(
|
|
548
|
+
"Start tunnel-only mode: expose local ports to the cloud without registering any tools"
|
|
549
|
+
)
|
|
550
|
+
.option(
|
|
551
|
+
"--share",
|
|
552
|
+
"Share this tunnel with your organization (allows other users to use it)"
|
|
553
|
+
)
|
|
554
|
+
.option("--unshare", "Make this tunnel private (only you can use it)")
|
|
555
|
+
.action(async (options) => {
|
|
556
|
+
await tunnel(options);
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
|
|
530
560
|
program
|
|
531
561
|
.command("script")
|
|
532
562
|
.description("Run a local tool script file using the executeScript sandbox")
|
package/src/clients/anthropic.ts
CHANGED
|
@@ -207,7 +207,7 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
207
207
|
const toolCalls = messages.flatMap((msg) => msg.tool_calls || []);
|
|
208
208
|
const claudeMessages: MessageParam[] = messages
|
|
209
209
|
.filter((msg) => msg.role !== "system")
|
|
210
|
-
.filter((msg) => msg.content)
|
|
210
|
+
.filter((msg) => msg.content || msg.role === "tool")
|
|
211
211
|
.map((msg) => {
|
|
212
212
|
if (msg.role === "tool") {
|
|
213
213
|
const toolCall = toolCalls.find((tc) => tc.id === msg.tool_call_id);
|
|
@@ -412,7 +412,13 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
412
412
|
}),
|
|
413
413
|
|
|
414
414
|
model: options.model,
|
|
415
|
-
usage: response.usage
|
|
415
|
+
usage: response.usage ? {
|
|
416
|
+
prompt_tokens: response.usage.input_tokens ?? 0,
|
|
417
|
+
completion_tokens: response.usage.output_tokens ?? 0,
|
|
418
|
+
total_tokens: (response.usage.input_tokens ?? 0) + (response.usage.output_tokens ?? 0),
|
|
419
|
+
cache_creation_input_tokens: response.usage.cache_creation_input_tokens ?? 0,
|
|
420
|
+
cache_read_input_tokens: response.usage.cache_read_input_tokens ?? 0,
|
|
421
|
+
} : undefined,
|
|
416
422
|
usd_cost: this.calculateCost(options.model, response.usage),
|
|
417
423
|
};
|
|
418
424
|
} catch (err) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HttpClient } from "./http";
|
|
2
|
+
import { CerebrasTextPricing } from "./pricing/cerebras";
|
|
3
|
+
|
|
4
|
+
export class GenericCerebrasClient extends HttpClient {
|
|
5
|
+
constructor(apiKey: string) {
|
|
6
|
+
super("https://api.cerebras.ai");
|
|
7
|
+
this.setJwt(apiKey);
|
|
8
|
+
this.setPrices(CerebrasTextPricing);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -19,8 +19,8 @@ export const ContextLimits: Record<string, number> = {
|
|
|
19
19
|
[Models.openai.GPT_5]: 1_000_000,
|
|
20
20
|
[Models.openai.GPT_5_Mini]: 1_000_000,
|
|
21
21
|
[Models.openai.GPT_5_Nano]: 1_000_000,
|
|
22
|
-
[Models.openai.
|
|
23
|
-
[Models.openai.
|
|
22
|
+
[Models.openai.GPT_51]: 1_000_000,
|
|
23
|
+
[Models.openai.GPT_52]: 1_000_000,
|
|
24
24
|
[Models.openai.GPT_41]: 1_047_576,
|
|
25
25
|
[Models.openai.GPT_41_Mini]: 1_047_576,
|
|
26
26
|
[Models.openai.GPT_41_Nano]: 1_047_576,
|
|
@@ -43,6 +43,7 @@ export const ContextLimits: Record<string, number> = {
|
|
|
43
43
|
|
|
44
44
|
// ─── Anthropic ────────────────────────────────────────────────────────────
|
|
45
45
|
[Models.anthropic.Opus4_6]: 1_000_000,
|
|
46
|
+
[Models.anthropic.Opus4_6Fast]: 1_000_000,
|
|
46
47
|
[Models.anthropic.Sonnet4_6]: 1_000_000,
|
|
47
48
|
[Models.anthropic.Opus4_5]: 1_000_000,
|
|
48
49
|
[Models.anthropic.Opus4]: 200_000,
|
|
@@ -54,6 +55,7 @@ export const ContextLimits: Record<string, number> = {
|
|
|
54
55
|
[Models.anthropic.Sonnet3_5]: 200_000,
|
|
55
56
|
[Models.anthropic.Opus3]: 200_000,
|
|
56
57
|
[Models.anthropic.Haiku3]: 200_000,
|
|
58
|
+
[Models.anthropic.Haiku3_5]: 200_000,
|
|
57
59
|
|
|
58
60
|
// ─── Google ───────────────────────────────────────────────────────────────
|
|
59
61
|
[Models.google.Gemini_31_Pro_Preview]: 1_000_000,
|
|
@@ -82,6 +84,9 @@ export const ContextLimits: Record<string, number> = {
|
|
|
82
84
|
// ─── xAI ──────────────────────────────────────────────────────────────────
|
|
83
85
|
[Models.xai.Grok4_1_Fast_Reasoning]: 2_000_000,
|
|
84
86
|
[Models.xai.Grok4_1_Fast_NonReasoning]: 2_000_000,
|
|
87
|
+
[Models.xai.Grok_4_20_Reasoning]: 131_072,
|
|
88
|
+
[Models.xai.Grok_4_20_NonReasoning]: 131_072,
|
|
89
|
+
[Models.xai.Grok_4_20_MultiAgent]: 2_000_000,
|
|
85
90
|
[Models.xai.GrokCodeFast]: 2_000_000,
|
|
86
91
|
[Models.xai.Grok4]: 131_072,
|
|
87
92
|
[Models.xai.Grok3Beta]: 131_072,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HttpClient } from "./http";
|
|
2
|
+
import { CopilotTextPricing } from "./pricing/copilot";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* GitHub Copilot client — OpenAI-compatible API
|
|
6
|
+
* https://docs.github.com/en/copilot/reference/ai-models/supported-models
|
|
7
|
+
*
|
|
8
|
+
* GitHub Copilot exposes an OpenAI-compatible endpoint at https://api.githubcopilot.com
|
|
9
|
+
* that allows subscribers to use premium models (Claude Opus, GPT-5.x, Gemini, Grok etc.)
|
|
10
|
+
* via their Copilot subscription's premium request allowance — no per-token charges.
|
|
11
|
+
*
|
|
12
|
+
* Authentication: uses a GitHub token (same as GITHUB_TOKEN / a personal access token
|
|
13
|
+
* or OAuth token with copilot scope).
|
|
14
|
+
*
|
|
15
|
+
* Set env var GITHUB_COPILOT_TOKEN (preferred) or GITHUB_TOKEN to enable.
|
|
16
|
+
*/
|
|
17
|
+
export class GitHubCopilotClient extends HttpClient {
|
|
18
|
+
constructor(apiKey = process.env.GITHUB_COPILOT_TOKEN ?? process.env.GITHUB_TOKEN) {
|
|
19
|
+
super("https://api.githubcopilot.com");
|
|
20
|
+
if (apiKey) this.setJwt(apiKey);
|
|
21
|
+
this.setPrices(CopilotTextPricing);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HttpClient } from "./http";
|
|
2
|
+
import { DeepSeekTextPricing } from "./pricing/deepseek";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* DeepSeek client — OpenAI-compatible API
|
|
6
|
+
* https://platform.deepseek.com/api-docs/
|
|
7
|
+
* Industry-leading reasoning (R1) and coding (V3) models at very low cost.
|
|
8
|
+
* Set env var DEEPSEEK_API_KEY to enable.
|
|
9
|
+
*/
|
|
10
|
+
export class GenericDeepSeekClient extends HttpClient {
|
|
11
|
+
constructor(apiKey = process.env.DEEPSEEK_API_KEY) {
|
|
12
|
+
super("https://api.deepseek.com");
|
|
13
|
+
if (apiKey) this.setJwt(apiKey);
|
|
14
|
+
this.setPrices(DeepSeekTextPricing);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HttpClient } from "./http";
|
|
2
|
+
import { FireworksTextPricing } from "./pricing/fireworks";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fireworks AI client — OpenAI-compatible API (fast serverless inference)
|
|
6
|
+
* https://docs.fireworks.ai/api-reference/introduction
|
|
7
|
+
* Set env var FIREWORKS_API_KEY to enable.
|
|
8
|
+
*/
|
|
9
|
+
export class GenericFireworksClient extends HttpClient {
|
|
10
|
+
constructor(apiKey = process.env.FIREWORKS_API_KEY) {
|
|
11
|
+
super("https://api.fireworks.ai/inference");
|
|
12
|
+
if (apiKey) this.setJwt(apiKey);
|
|
13
|
+
this.setPrices(FireworksTextPricing);
|
|
14
|
+
}
|
|
15
|
+
}
|