@tyvm/knowhow 0.0.153 → 0.0.154
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/package.json +1 -1
- package/src/agents/base/base.ts +31 -5
- package/src/agents/tools/list.ts +31 -28
- package/src/clients/anthropic.ts +3 -1
- package/src/clients/contextLimits.ts +3 -1
- package/src/clients/gemini.ts +16 -4
- package/src/clients/http.ts +8 -5
- package/src/clients/knowhowMcp.ts +2 -2
- package/src/clients/openai.ts +7 -4
- package/src/clients/pricing/google.ts +11 -2
- package/src/clients/pricing/xai.ts +5 -1
- package/src/clients/xai.ts +6 -3
- package/tests/clients/reasoningEffort.test.ts +5 -1
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.d.ts +1 -1
- package/ts_build/src/agents/base/base.js +13 -5
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/list.js +0 -26
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/clients/anthropic.js +3 -1
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/contextLimits.js +2 -0
- package/ts_build/src/clients/contextLimits.js.map +1 -1
- package/ts_build/src/clients/gemini.js +14 -3
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/http.js +8 -5
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/knowhowMcp.js +2 -2
- package/ts_build/src/clients/knowhowMcp.js.map +1 -1
- package/ts_build/src/clients/openai.js +7 -4
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/google.d.ts +1 -0
- package/ts_build/src/clients/pricing/google.js +7 -0
- package/ts_build/src/clients/pricing/google.js.map +1 -1
- package/ts_build/src/clients/pricing/xai.d.ts +1 -0
- package/ts_build/src/clients/pricing/xai.js +4 -0
- package/ts_build/src/clients/pricing/xai.js.map +1 -1
- package/ts_build/src/clients/xai.js +6 -3
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/types.d.ts +2 -0
- package/ts_build/tests/clients/reasoningEffort.test.js +2 -1
- package/ts_build/tests/clients/reasoningEffort.test.js.map +1 -1
package/package.json
CHANGED
package/src/agents/base/base.ts
CHANGED
|
@@ -1107,6 +1107,14 @@ export abstract class BaseAgent implements IAgent {
|
|
|
1107
1107
|
|
|
1108
1108
|
// Typically, there's only one choice in the array, but you could have many
|
|
1109
1109
|
// If you set `n` to more than 1, you will get multiple choices
|
|
1110
|
+
// Collect all tool calls across all choices up front.
|
|
1111
|
+
// This is used by detectTruncatedToolCalls so that the size heuristic
|
|
1112
|
+
// compares the full completion_tokens against ALL argument content,
|
|
1113
|
+
// rather than just the current choice's single tool call (Anthropic maps
|
|
1114
|
+
// each parallel tool_use block to a separate choice).
|
|
1115
|
+
const allResponseToolCalls = response.choices.flatMap(
|
|
1116
|
+
(c) => c.message.tool_calls ?? []
|
|
1117
|
+
);
|
|
1110
1118
|
for (const choice of response.choices) {
|
|
1111
1119
|
messages.push(choice.message);
|
|
1112
1120
|
|
|
@@ -1136,7 +1144,8 @@ export abstract class BaseAgent implements IAgent {
|
|
|
1136
1144
|
|
|
1137
1145
|
const truncationWarning = this.detectTruncatedToolCalls(
|
|
1138
1146
|
toolCalls,
|
|
1139
|
-
response
|
|
1147
|
+
response,
|
|
1148
|
+
allResponseToolCalls
|
|
1140
1149
|
);
|
|
1141
1150
|
if (truncationWarning) {
|
|
1142
1151
|
messages.push(truncationWarning as Message);
|
|
@@ -1589,11 +1598,14 @@ export abstract class BaseAgent implements IAgent {
|
|
|
1589
1598
|
* 2. The model reported many output tokens but the total argument content received is tiny
|
|
1590
1599
|
* relative to what those tokens should represent (soft/silent truncation).
|
|
1591
1600
|
*
|
|
1601
|
+
* @param toolCalls - The tool calls from the CURRENT choice being checked.
|
|
1602
|
+
* @param allToolCalls - ALL tool calls across ALL choices in the response (used for the size heuristic).
|
|
1592
1603
|
* Returns a warning system message if truncation is detected, or null otherwise.
|
|
1593
1604
|
*/
|
|
1594
1605
|
detectTruncatedToolCalls(
|
|
1595
1606
|
toolCalls: ToolCall[],
|
|
1596
|
-
response: CompletionResponse
|
|
1607
|
+
response: CompletionResponse,
|
|
1608
|
+
allToolCalls?: ToolCall[]
|
|
1597
1609
|
): { role: string; content: string } | null {
|
|
1598
1610
|
// Subtract thinking/reasoning tokens — they're billed as output tokens but
|
|
1599
1611
|
// don't produce visible argument content, so including them inflates the heuristic.
|
|
@@ -1602,7 +1614,13 @@ export abstract class BaseAgent implements IAgent {
|
|
|
1602
1614
|
(response?.usage?.output_tokens_details?.thinking_tokens ?? 0) +
|
|
1603
1615
|
(response?.usage?.output_tokens_details?.reasoning_tokens ?? 0);
|
|
1604
1616
|
const outputTokens = Math.max(0, rawOutputTokens - thinkingTokens);
|
|
1605
|
-
|
|
1617
|
+
// Use allToolCalls for the size heuristic so that parallel tool calls from
|
|
1618
|
+
// Anthropic (each mapped to a separate choice) are counted together. Without
|
|
1619
|
+
// this, a response with N parallel tool calls would compare the full
|
|
1620
|
+
// completion_tokens count against only 1/N of the actual argument content,
|
|
1621
|
+
// causing false-positive truncation warnings.
|
|
1622
|
+
const callsForSizeCheck = allToolCalls ?? toolCalls;
|
|
1623
|
+
const totalArgLength = callsForSizeCheck.reduce(
|
|
1606
1624
|
(sum, tc) => sum + (tc.function?.arguments?.length || 0),
|
|
1607
1625
|
0
|
|
1608
1626
|
);
|
|
@@ -1688,9 +1706,13 @@ export abstract class BaseAgent implements IAgent {
|
|
|
1688
1706
|
.filter((s): s is string => typeof s === "string" && s.trim().length > 0)
|
|
1689
1707
|
.join("\n\n");
|
|
1690
1708
|
|
|
1691
|
-
|
|
1709
|
+
if (!breakdownContent) {
|
|
1710
|
+
throw new Error("Compaction task-breakdown request returned no text content");
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
this.taskBreakdown = breakdownContent;
|
|
1692
1714
|
this.log(`task breakdown cost: ${response.usd_cost}`);
|
|
1693
|
-
return this.taskBreakdown
|
|
1715
|
+
return this.taskBreakdown;
|
|
1694
1716
|
}
|
|
1695
1717
|
|
|
1696
1718
|
async compressMessages(messages: Message[]) {
|
|
@@ -1742,6 +1764,10 @@ export abstract class BaseAgent implements IAgent {
|
|
|
1742
1764
|
const summaries = response.choices
|
|
1743
1765
|
.map((c) => c.message.content)
|
|
1744
1766
|
.filter((s): s is string => typeof s === "string" && s.trim().length > 0);
|
|
1767
|
+
if (summaries.length === 0) {
|
|
1768
|
+
throw new Error("Compaction summary request returned no text content");
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1745
1771
|
this.summaries.push(...summaries);
|
|
1746
1772
|
|
|
1747
1773
|
const startMessages = [
|
package/src/agents/tools/list.ts
CHANGED
|
@@ -31,34 +31,37 @@ function getPluginNames(): string {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export const includedTools = [
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
34
|
+
/*
|
|
35
|
+
* This doesn't use messageProcessors etc, needs rewrite
|
|
36
|
+
*{
|
|
37
|
+
* type: "function",
|
|
38
|
+
* function: {
|
|
39
|
+
* name: "agentCall",
|
|
40
|
+
* description:
|
|
41
|
+
* "Run another registered agent in-process as a blocking call and get its final answer back as a string. Unlike a plain llm() call, the target agent can use tools, loop, and maintain its own context. Useful as a graph node that delegates to a specialized agent (e.g. Researcher, Patcher). For long-running / parallel / detached work prefer startAgentTask.",
|
|
42
|
+
* parameters: {
|
|
43
|
+
* type: "object",
|
|
44
|
+
* positional: true,
|
|
45
|
+
* properties: {
|
|
46
|
+
* agentName: {
|
|
47
|
+
* type: "string",
|
|
48
|
+
* description:
|
|
49
|
+
* "The name of the agent to call (e.g. Researcher, Developer, Patcher).",
|
|
50
|
+
* },
|
|
51
|
+
* query: {
|
|
52
|
+
* type: "string",
|
|
53
|
+
* description: "The query / task to send to the agent.",
|
|
54
|
+
* },
|
|
55
|
+
* },
|
|
56
|
+
* required: ["agentName", "query"],
|
|
57
|
+
* },
|
|
58
|
+
* returns: {
|
|
59
|
+
* type: "string",
|
|
60
|
+
* description: "The agent's final answer text.",
|
|
61
|
+
* },
|
|
62
|
+
* },
|
|
63
|
+
*},
|
|
64
|
+
*/
|
|
62
65
|
{
|
|
63
66
|
type: "function",
|
|
64
67
|
function: {
|
package/src/clients/anthropic.ts
CHANGED
|
@@ -472,7 +472,9 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
472
472
|
...(thinkingParam && { thinking: thinkingParam }),
|
|
473
473
|
...(effortOutputConfig && { output_config: effortOutputConfig }),
|
|
474
474
|
...(tools.length && {
|
|
475
|
-
tool_choice: {
|
|
475
|
+
tool_choice: {
|
|
476
|
+
type: options.tool_choice ?? "auto",
|
|
477
|
+
},
|
|
476
478
|
tools,
|
|
477
479
|
}),
|
|
478
480
|
}, { signal: options.signal });
|
|
@@ -123,7 +123,8 @@ export const ContextLimits: Record<string, number> = {
|
|
|
123
123
|
[Models.anthropic.Sonnet4_0]: 200_000,
|
|
124
124
|
|
|
125
125
|
// ─── Google ───────────────────────────────────────────────────────────────
|
|
126
|
-
// Gemini 3.6 / 3.5 (text)
|
|
126
|
+
// Gemini 3.7 / 3.6 / 3.5 (text)
|
|
127
|
+
[Models.google.Gemini_37_Flash]: 1_048_576,
|
|
127
128
|
[Models.google.Gemini_36_Flash]: 1_000_000,
|
|
128
129
|
[Models.google.Gemini_35_Flash]: 1_000_000,
|
|
129
130
|
[Models.google.Gemini_35_Flash_Lite]: 1_000_000,
|
|
@@ -178,6 +179,7 @@ export const ContextLimits: Record<string, number> = {
|
|
|
178
179
|
[Models.google.Gemini_15_Pro]: 2_000_000,
|
|
179
180
|
|
|
180
181
|
// ─── xAI ──────────────────────────────────────────────────────────────────
|
|
182
|
+
[Models.xai.Grok4_6]: 500_000,
|
|
181
183
|
[Models.xai.Grok4_1_Fast_Reasoning]: 2_000_000,
|
|
182
184
|
[Models.xai.Grok4_1_Fast_NonReasoning]: 2_000_000,
|
|
183
185
|
[Models.xai.Grok_4_20_Reasoning]: 131_072,
|
package/src/clients/gemini.ts
CHANGED
|
@@ -420,7 +420,7 @@ export class GenericGeminiClient implements GenericClient {
|
|
|
420
420
|
|
|
421
421
|
/**
|
|
422
422
|
* Builds the thinkingConfig for Gemini models that support it.
|
|
423
|
-
* - Gemini 3.x models use thinkingLevel
|
|
423
|
+
* - Gemini 3.x models use thinkingLevel (supported levels vary by model)
|
|
424
424
|
* - Gemini 2.5 models use thinkingBudget: number (0 = off, -1 = dynamic)
|
|
425
425
|
*
|
|
426
426
|
* Maps CompletionOptions.reasoning_effort to provider-specific values.
|
|
@@ -433,9 +433,11 @@ export class GenericGeminiClient implements GenericClient {
|
|
|
433
433
|
|
|
434
434
|
// Gemini 3.x — use thinkingLevel
|
|
435
435
|
if (GoogleThinkingLevelModels.includes(model)) {
|
|
436
|
+
// Gemini 3.7 Flash rejects "minimal"; low is its least intensive level.
|
|
437
|
+
const minimumLevel = model === Models.google.Gemini_37_Flash ? "low" : "minimal";
|
|
436
438
|
const levelMap: Record<string, string> = {
|
|
437
|
-
none:
|
|
438
|
-
minimal:
|
|
439
|
+
none: minimumLevel,
|
|
440
|
+
minimal: minimumLevel,
|
|
439
441
|
low: "low",
|
|
440
442
|
medium: "medium",
|
|
441
443
|
high: "high",
|
|
@@ -474,6 +476,7 @@ export class GenericGeminiClient implements GenericClient {
|
|
|
474
476
|
const { systemInstruction, contents } = this.transformMessages(
|
|
475
477
|
options.messages
|
|
476
478
|
);
|
|
479
|
+
const tools = this.transformTools(options.tools);
|
|
477
480
|
|
|
478
481
|
try {
|
|
479
482
|
await wait(2000);
|
|
@@ -483,7 +486,16 @@ export class GenericGeminiClient implements GenericClient {
|
|
|
483
486
|
config: {
|
|
484
487
|
systemInstruction,
|
|
485
488
|
thinkingConfig,
|
|
486
|
-
tools
|
|
489
|
+
tools,
|
|
490
|
+
...(tools.length && {
|
|
491
|
+
toolConfig: {
|
|
492
|
+
functionCallingConfig: {
|
|
493
|
+
mode: options.tool_choice === "none"
|
|
494
|
+
? FunctionCallingConfigMode.NONE
|
|
495
|
+
: FunctionCallingConfigMode.AUTO,
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
}),
|
|
487
499
|
maxOutputTokens: options.max_tokens,
|
|
488
500
|
},
|
|
489
501
|
});
|
package/src/clients/http.ts
CHANGED
|
@@ -247,9 +247,9 @@ export class HttpClient implements GenericClient {
|
|
|
247
247
|
max_tokens: options.max_tokens || 4000,
|
|
248
248
|
...this.extra_body,
|
|
249
249
|
|
|
250
|
-
...(options.tools && {
|
|
250
|
+
...(options.tools?.length && {
|
|
251
251
|
tools: options.tools,
|
|
252
|
-
tool_choice: "auto",
|
|
252
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
253
253
|
}),
|
|
254
254
|
};
|
|
255
255
|
|
|
@@ -297,9 +297,9 @@ export class HttpClient implements GenericClient {
|
|
|
297
297
|
...this.extra_body,
|
|
298
298
|
stream: true,
|
|
299
299
|
stream_options: { include_usage: true },
|
|
300
|
-
...(options.tools && {
|
|
300
|
+
...(options.tools?.length && {
|
|
301
301
|
tools: options.tools,
|
|
302
|
-
tool_choice: "auto",
|
|
302
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
303
303
|
}),
|
|
304
304
|
};
|
|
305
305
|
|
|
@@ -442,7 +442,10 @@ export class HttpClient implements GenericClient {
|
|
|
442
442
|
input,
|
|
443
443
|
...(instructions && { instructions }),
|
|
444
444
|
...(options.max_tokens && { max_output_tokens: options.max_tokens }),
|
|
445
|
-
...(tools?.length && {
|
|
445
|
+
...(tools?.length && {
|
|
446
|
+
tools,
|
|
447
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
448
|
+
}),
|
|
446
449
|
// Reasoning persistence: store server-side when requested, otherwise
|
|
447
450
|
// ask the provider to return encrypted reasoning content so we can
|
|
448
451
|
// thread the reasoning items back into the next request ourselves.
|
|
@@ -62,9 +62,9 @@ export class KnowhowMcpClient implements GenericClient {
|
|
|
62
62
|
...options,
|
|
63
63
|
max_tokens: options.max_tokens || 3000,
|
|
64
64
|
|
|
65
|
-
...(options.tools && {
|
|
65
|
+
...(options.tools?.length && {
|
|
66
66
|
tools: options.tools,
|
|
67
|
-
tool_choice: "auto",
|
|
67
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
68
68
|
}),
|
|
69
69
|
},
|
|
70
70
|
}
|
package/src/clients/openai.ts
CHANGED
|
@@ -235,9 +235,9 @@ export class GenericOpenAiClient implements GenericClient {
|
|
|
235
235
|
max_completion_tokens: Math.max(options.max_tokens ?? 0, 16_000),
|
|
236
236
|
reasoning_effort: this.resolveReasoningEffort(options),
|
|
237
237
|
}),
|
|
238
|
-
...(options.tools && {
|
|
238
|
+
...(options.tools?.length && {
|
|
239
239
|
tools: options.tools,
|
|
240
|
-
tool_choice: "auto",
|
|
240
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
241
241
|
}),
|
|
242
242
|
}, { signal: options.signal });
|
|
243
243
|
|
|
@@ -296,7 +296,10 @@ export class GenericOpenAiClient implements GenericClient {
|
|
|
296
296
|
max_tokens: options.max_tokens,
|
|
297
297
|
stream: true,
|
|
298
298
|
stream_options: { include_usage: true },
|
|
299
|
-
...(options.tools && {
|
|
299
|
+
...(options.tools?.length && {
|
|
300
|
+
tools: options.tools,
|
|
301
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
302
|
+
}),
|
|
300
303
|
}, { signal: options.signal });
|
|
301
304
|
|
|
302
305
|
let usage: CompletionResponse['usage'] | undefined;
|
|
@@ -501,7 +504,7 @@ export class GenericOpenAiClient implements GenericClient {
|
|
|
501
504
|
}),
|
|
502
505
|
...(tools?.length && {
|
|
503
506
|
tools,
|
|
504
|
-
tool_choice: "auto",
|
|
507
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
505
508
|
}),
|
|
506
509
|
} as any);
|
|
507
510
|
|
|
@@ -7,7 +7,8 @@ import { completions, embeddings, images, videos, audios, liveApi, ModelCatalogE
|
|
|
7
7
|
// ─── Model IDs ────────────────────────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
export const GoogleModels = {
|
|
10
|
-
// Gemini 3.6 / 3.5
|
|
10
|
+
// Gemini 3.7 / 3.6 / 3.5
|
|
11
|
+
Gemini_37_Flash: "gemini-3.7-flash",
|
|
11
12
|
Gemini_36_Flash: "gemini-3.6-flash",
|
|
12
13
|
Gemini_35_Flash: "gemini-3.5-flash",
|
|
13
14
|
Gemini_35_Flash_Lite: "gemini-3.5-flash-lite",
|
|
@@ -86,6 +87,7 @@ export const GoogleEmbeddingModels: Record<string, string> = {
|
|
|
86
87
|
// ─── Modality arrays ──────────────────────────────────────────────────────────
|
|
87
88
|
|
|
88
89
|
export const GoogleTextModels: string[] = [
|
|
90
|
+
GoogleModels.Gemini_37_Flash,
|
|
89
91
|
GoogleModels.Gemini_36_Flash,
|
|
90
92
|
GoogleModels.Gemini_35_Flash,
|
|
91
93
|
GoogleModels.Gemini_35_Flash_Lite,
|
|
@@ -101,6 +103,7 @@ export const GoogleTextModels: string[] = [
|
|
|
101
103
|
|
|
102
104
|
// Models that support thinkingLevel (Gemini 3.x series)
|
|
103
105
|
export const GoogleThinkingLevelModels: string[] = [
|
|
106
|
+
GoogleModels.Gemini_37_Flash,
|
|
104
107
|
GoogleModels.Gemini_36_Flash,
|
|
105
108
|
GoogleModels.Gemini_35_Flash,
|
|
106
109
|
GoogleModels.Gemini_35_Flash_Lite,
|
|
@@ -214,7 +217,13 @@ export interface GeminiModelPricing extends ModelPricing {
|
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
export const GeminiPricing: Record<string, GeminiModelPricing> = {
|
|
217
|
-
// ── Gemini 3.6 / 3.5
|
|
220
|
+
// ── Gemini 3.7 / 3.6 / 3.5 ────────────────────────────────────────────────
|
|
221
|
+
// Introductory pricing through December 31, 2026. Standard pricing beginning
|
|
222
|
+
// January 1, 2027 is $1.50 input, $7.50 output, and $0.15 cached input.
|
|
223
|
+
[GoogleModels.Gemini_37_Flash]: {
|
|
224
|
+
input: 0.75, output: 3.75,
|
|
225
|
+
context_caching: 0.075, context_caching_storage: 0.5,
|
|
226
|
+
},
|
|
218
227
|
[GoogleModels.Gemini_36_Flash]: {
|
|
219
228
|
input: 1.5, output: 7.5,
|
|
220
229
|
context_caching: 0.15, context_caching_storage: 1.0,
|
|
@@ -7,6 +7,7 @@ import { completions, images, videos, ModelCatalogEntry, ModelPricing } from "./
|
|
|
7
7
|
// ─── Model IDs ────────────────────────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
export const XaiModels = {
|
|
10
|
+
Grok4_6: "grok-4.6",
|
|
10
11
|
Grok_4_20_Reasoning: "grok-4.20-0309-reasoning",
|
|
11
12
|
Grok_4_20_NonReasoning: "grok-4.20-0309-non-reasoning",
|
|
12
13
|
Grok_4_20_MultiAgent: "grok-4.20-multi-agent-0309",
|
|
@@ -42,6 +43,7 @@ export const XaiModels = {
|
|
|
42
43
|
// ─── Modality arrays ──────────────────────────────────────────────────────────
|
|
43
44
|
|
|
44
45
|
export const XaiTextModels: string[] = [
|
|
46
|
+
XaiModels.Grok4_6,
|
|
45
47
|
XaiModels.Grok_4_20_Reasoning, XaiModels.Grok_4_20_NonReasoning,
|
|
46
48
|
XaiModels.Grok_4_20_MultiAgent,
|
|
47
49
|
XaiModels.Grok4_1_Fast_Reasoning, XaiModels.Grok4_1_Fast_NonReasoning,
|
|
@@ -61,8 +63,9 @@ export const XaiResponsesOnlyModels: string[] = [
|
|
|
61
63
|
];
|
|
62
64
|
|
|
63
65
|
// Models that support the reasoning_effort parameter
|
|
64
|
-
//
|
|
66
|
+
// Grok 4.6, Grok 4.20 multi-agent, and grok-3-mini variants support reasoning_effort
|
|
65
67
|
export const XaiReasoningModels: string[] = [
|
|
68
|
+
XaiModels.Grok4_6,
|
|
66
69
|
XaiModels.Grok_4_20_MultiAgent,
|
|
67
70
|
XaiModels.Grok3MiniBeta,
|
|
68
71
|
XaiModels.Grok3MiniFastBeta,
|
|
@@ -84,6 +87,7 @@ export const XaiVideoModels: string[] = [XaiModels.GrokImagineVideo];
|
|
|
84
87
|
// ─── Pricing (USD per 1M tokens / per-image / per-second) ────────────────────
|
|
85
88
|
|
|
86
89
|
export const XaiTextPricing: Record<string, ModelPricing> = {
|
|
90
|
+
[XaiModels.Grok4_6]: { input: 2.0, input_gt_200k: 4.0, cache_hit: 0.50, output: 6.0, output_gt_200k: 12.0, reasoningLevels: ["low", "medium", "high", "xhigh"] },
|
|
87
91
|
[XaiModels.Grok_4_20_Reasoning]: { input: 2.0, cache_hit: 0.20, output: 6.0, useResponsesApi: true },
|
|
88
92
|
[XaiModels.Grok_4_20_NonReasoning]: { input: 2.0, cache_hit: 0.20, output: 6.0, useResponsesApi: true },
|
|
89
93
|
[XaiModels.Grok_4_20_MultiAgent]: { input: 2.0, cache_hit: 0.20, output: 6.0, reasoningLevels: ["low", "medium", "high", "xhigh"], useResponsesApi: true },
|
package/src/clients/xai.ts
CHANGED
|
@@ -90,9 +90,9 @@ export class GenericXAIClient implements GenericClient {
|
|
|
90
90
|
// grok-3-mini models support reasoning_effort: "low" | "medium" | "high"
|
|
91
91
|
reasoning_effort: reasoningEffort,
|
|
92
92
|
}),
|
|
93
|
-
...(options.tools && {
|
|
93
|
+
...(options.tools?.length && {
|
|
94
94
|
tools: options.tools,
|
|
95
|
-
tool_choice: "auto",
|
|
95
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
96
96
|
}),
|
|
97
97
|
});
|
|
98
98
|
|
|
@@ -238,7 +238,10 @@ export class GenericXAIClient implements GenericClient {
|
|
|
238
238
|
...(instructions && { instructions }),
|
|
239
239
|
...(options.max_tokens && { max_output_tokens: Math.max(options.max_tokens, 16_000) }),
|
|
240
240
|
...(reasoningEffort && { reasoning: { effort: reasoningEffort } }),
|
|
241
|
-
...(tools?.length && {
|
|
241
|
+
...(tools?.length && {
|
|
242
|
+
tools,
|
|
243
|
+
tool_choice: options.tool_choice ?? "auto",
|
|
244
|
+
}),
|
|
242
245
|
// Reasoning persistence (same construct as OpenAI's Responses API):
|
|
243
246
|
// - store === true → xAI persists the response; next turn passes
|
|
244
247
|
// previous_response_id to continue the reasoning chain server-side.
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
GoogleThinkingBudgetModels,
|
|
12
12
|
GoogleThinkingLevelModels,
|
|
13
|
+
Models,
|
|
13
14
|
} from "../../src/types";
|
|
14
15
|
import { GenericXAIClient } from "../../src/clients/xai";
|
|
15
16
|
|
|
@@ -46,13 +47,16 @@ describe("reasoning effort values", () => {
|
|
|
46
47
|
|
|
47
48
|
it("maps all values to valid Gemini thinking levels and budgets", () => {
|
|
48
49
|
const client = new GenericGeminiClient("fake-key");
|
|
49
|
-
const levelModel = GoogleThinkingLevelModels
|
|
50
|
+
const levelModel = GoogleThinkingLevelModels.find(
|
|
51
|
+
(model) => model !== Models.google.Gemini_37_Flash
|
|
52
|
+
)!;
|
|
50
53
|
const budgetModel = GoogleThinkingBudgetModels[0];
|
|
51
54
|
|
|
52
55
|
expect(client.buildThinkingConfig(options(levelModel, "none"))).toEqual({ thinkingLevel: "minimal" });
|
|
53
56
|
expect(client.buildThinkingConfig(options(levelModel, "minimal"))).toEqual({ thinkingLevel: "minimal" });
|
|
54
57
|
expect(client.buildThinkingConfig(options(levelModel, "xhigh"))).toEqual({ thinkingLevel: "high" });
|
|
55
58
|
expect(client.buildThinkingConfig(options(levelModel, "max"))).toEqual({ thinkingLevel: "high" });
|
|
59
|
+
expect(client.buildThinkingConfig(options(Models.google.Gemini_37_Flash, "minimal"))).toEqual({ thinkingLevel: "low" });
|
|
56
60
|
expect(client.buildThinkingConfig(options(budgetModel, "none"))).toEqual({ thinkingBudget: 0 });
|
|
57
61
|
expect(client.buildThinkingConfig(options(budgetModel, "minimal"))).toEqual({ thinkingBudget: 512 });
|
|
58
62
|
expect(client.buildThinkingConfig(options(budgetModel, "medium"))).toEqual({ thinkingBudget: 8192 });
|
package/ts_build/package.json
CHANGED
|
@@ -187,7 +187,7 @@ export declare abstract class BaseAgent implements IAgent {
|
|
|
187
187
|
stopObserving(id?: string, reason?: string): string;
|
|
188
188
|
getMessagesLength(messages: Message[]): number;
|
|
189
189
|
getContextTokenCount(messages: Message[]): number;
|
|
190
|
-
detectTruncatedToolCalls(toolCalls: ToolCall[], response: CompletionResponse): {
|
|
190
|
+
detectTruncatedToolCalls(toolCalls: ToolCall[], response: CompletionResponse, allToolCalls?: ToolCall[]): {
|
|
191
191
|
role: string;
|
|
192
192
|
content: string;
|
|
193
193
|
} | null;
|
|
@@ -691,6 +691,7 @@ let BaseAgent = class BaseAgent {
|
|
|
691
691
|
}
|
|
692
692
|
}
|
|
693
693
|
this.log("agent response cost: " + response?.usd_cost);
|
|
694
|
+
const allResponseToolCalls = response.choices.flatMap((c) => c.message.tool_calls ?? []);
|
|
694
695
|
for (const choice of response.choices) {
|
|
695
696
|
messages.push(choice.message);
|
|
696
697
|
messages = await this.messageProcessor.processMessages(messages, "post_call");
|
|
@@ -700,7 +701,7 @@ let BaseAgent = class BaseAgent {
|
|
|
700
701
|
messages = await this.messageProcessor.processMessages(messages, "pre_tools");
|
|
701
702
|
const toolCalls = messages[messages.length - 1].tool_calls;
|
|
702
703
|
this.updateCurrentThread(messages);
|
|
703
|
-
const truncationWarning = this.detectTruncatedToolCalls(toolCalls, response);
|
|
704
|
+
const truncationWarning = this.detectTruncatedToolCalls(toolCalls, response, allResponseToolCalls);
|
|
704
705
|
if (truncationWarning) {
|
|
705
706
|
messages.push(truncationWarning);
|
|
706
707
|
this.updateCurrentThread(messages);
|
|
@@ -984,12 +985,13 @@ let BaseAgent = class BaseAgent {
|
|
|
984
985
|
}
|
|
985
986
|
return this.getMessagesLength(messages);
|
|
986
987
|
}
|
|
987
|
-
detectTruncatedToolCalls(toolCalls, response) {
|
|
988
|
+
detectTruncatedToolCalls(toolCalls, response, allToolCalls) {
|
|
988
989
|
const rawOutputTokens = response?.usage?.completion_tokens || 0;
|
|
989
990
|
const thinkingTokens = (response?.usage?.output_tokens_details?.thinking_tokens ?? 0) +
|
|
990
991
|
(response?.usage?.output_tokens_details?.reasoning_tokens ?? 0);
|
|
991
992
|
const outputTokens = Math.max(0, rawOutputTokens - thinkingTokens);
|
|
992
|
-
const
|
|
993
|
+
const callsForSizeCheck = allToolCalls ?? toolCalls;
|
|
994
|
+
const totalArgLength = callsForSizeCheck.reduce((sum, tc) => sum + (tc.function?.arguments?.length || 0), 0);
|
|
993
995
|
const expectedArgChars = outputTokens * 4;
|
|
994
996
|
const suspiciouslySmallArgs = outputTokens > 1000 && totalArgLength < expectedArgChars * 0.1;
|
|
995
997
|
for (const toolCall of toolCalls) {
|
|
@@ -1052,9 +1054,12 @@ let BaseAgent = class BaseAgent {
|
|
|
1052
1054
|
.map((c) => c.message.content)
|
|
1053
1055
|
.filter((s) => typeof s === "string" && s.trim().length > 0)
|
|
1054
1056
|
.join("\n\n");
|
|
1055
|
-
|
|
1057
|
+
if (!breakdownContent) {
|
|
1058
|
+
throw new Error("Compaction task-breakdown request returned no text content");
|
|
1059
|
+
}
|
|
1060
|
+
this.taskBreakdown = breakdownContent;
|
|
1056
1061
|
this.log(`task breakdown cost: ${response.usd_cost}`);
|
|
1057
|
-
return this.taskBreakdown
|
|
1062
|
+
return this.taskBreakdown;
|
|
1058
1063
|
}
|
|
1059
1064
|
async compressMessages(messages) {
|
|
1060
1065
|
let resumeIndex = messages.length - 1;
|
|
@@ -1094,6 +1099,9 @@ let BaseAgent = class BaseAgent {
|
|
|
1094
1099
|
const summaries = response.choices
|
|
1095
1100
|
.map((c) => c.message.content)
|
|
1096
1101
|
.filter((s) => typeof s === "string" && s.trim().length > 0);
|
|
1102
|
+
if (summaries.length === 0) {
|
|
1103
|
+
throw new Error("Compaction summary request returned no text content");
|
|
1104
|
+
}
|
|
1097
1105
|
this.summaries.push(...summaries);
|
|
1098
1106
|
const startMessages = [
|
|
1099
1107
|
{
|