@pensar/apex 2.6.1 → 2.7.0-canary.21cb83dc
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/build/{agent-yby11zaq.js → agent-68t2wzmc.js} +6 -6
- package/build/agent-jhekpern.js +13 -0
- package/build/{agent-ayreaj6z.js → agent-qvreg8a4.js} +5 -5
- package/build/{agent-runs-g37vkrjr.js → agent-runs-30dvbvmm.js} +18 -18
- package/build/agent-vybw255f.js +13 -0
- package/build/{apps-xn6km9yn.js → apps-na0y0992.js} +13 -13
- package/build/{auth-d105wc64.js → auth-dz2c5thx.js} +13 -13
- package/build/{blackboxAgent-s56sgx9b.js → blackboxAgent-2mwvaajb.js} +6 -6
- package/build/{blackboxPentest-ps78v3w7.js → blackboxPentest-s2mfze9p.js} +17 -12
- package/build/{cli-kb21qhvm.js → cli-1pmfnz1a.js} +4 -3
- package/build/{cli-ae8jqxqr.js → cli-563yntrb.js} +2 -2
- package/build/{cli-7eea4e2y.js → cli-5ab346kd.js} +6 -6
- package/build/{cli-1ve18npr.js → cli-72y76bpg.js} +3 -2
- package/build/{cli-fy6vh2a7.js → cli-98wmmphf.js} +1 -1
- package/build/{cli-c05y640n.js → cli-9jscnhtg.js} +1 -1
- package/build/{cli-3sp6nd8d.js → cli-9kk9tm58.js} +2 -2
- package/build/{cli-d37a42dc.js → cli-9pz9wjt2.js} +101 -18
- package/build/{cli-dpsw2fe6.js → cli-a6x4jm5a.js} +476 -193
- package/build/{cli-az3xq70v.js → cli-cfrdr25z.js} +1 -1
- package/build/{cli-ngq9dr8n.js → cli-fdrrbb9p.js} +3 -3
- package/build/{cli-k2nwxta0.js → cli-t09zj814.js} +2 -2
- package/build/{cli-qgz1q9g5.js → cli-t4q4t4dx.js} +223 -76
- package/build/{cli-xtc2t6me.js → cli-vdd1s3x9.js} +103 -39
- package/build/{cli-gx71jcke.js → cli-vn4cwac3.js} +1 -1
- package/build/{cli-65g6rcat.js → cli-w9nw2a4z.js} +1 -1
- package/build/{cli-n2en7j5b.js → cli-z7ysyrr4.js} +1 -1
- package/build/{cli-709rvekb.js → cli-zbbtr4sb.js} +4 -2
- package/build/cli.js +70 -40
- package/build/{config-zpqkd5cz.js → config-nkzm9arw.js} +1 -1
- package/build/{fastStrike-mcjdvwez.js → fastStrike-16jw1s61.js} +67 -15
- package/build/{fixes-kytx5dmj.js → fixes-6wxk22v5.js} +13 -13
- package/build/{index-4vqdgb42.js → index-36p56pcf.js} +1473 -1217
- package/build/{index-je6hcsqr.js → index-6nejymsc.js} +1 -1
- package/build/{index-fv64eb32.js → index-asm4y7e4.js} +2 -2
- package/build/{index-n65z6v7b.js → index-bfmn52za.js} +6 -6
- package/build/{index-qv4cc65p.js → index-bt4r13q7.js} +13 -13
- package/build/{index-dr3tg1w3.js → index-gfq1rp1q.js} +1 -1
- package/build/{index-wqetp6gq.js → index-j9pxgrzd.js} +12 -7
- package/build/{index-r9yjkfrv.js → index-n9kapn1x.js} +4 -4
- package/build/{index-ns4m4s01.js → index-tr6evhyg.js} +4 -4
- package/build/{issues-eb3q9d3a.js → issues-7rmf4ker.js} +13 -13
- package/build/{knowledge-fqsvtx0f.js → knowledge-s2sxh8nb.js} +13 -13
- package/build/lib/{chunk-1azdancq.js → chunk-0dnx79b1.js} +1 -1
- package/build/lib/{chunk-4hwzqthr.js → chunk-161ak2am.js} +3 -2
- package/build/lib/{chunk-z137x08b.js → chunk-1rqbhx4b.js} +7 -5
- package/build/lib/{chunk-1yct6cra.js → chunk-3hjvdf67.js} +1 -1
- package/build/lib/{chunk-r2dkp4tb.js → chunk-5j8pp0xf.js} +1 -1
- package/build/lib/{chunk-3c00n0cy.js → chunk-77se1d35.js} +8 -3
- package/build/lib/{chunk-yrnrbjes.js → chunk-7tft4b8b.js} +4 -2
- package/build/lib/{chunk-w66ce82a.js → chunk-8njjwwcw.js} +4 -2
- package/build/lib/{chunk-v3dk9j7k.js → chunk-aq9eyxas.js} +80 -21
- package/build/lib/{chunk-9tt2021m.js → chunk-d05cvnv8.js} +9 -9
- package/build/lib/{chunk-e8yy2k73.js → chunk-f3sq4896.js} +28 -2
- package/build/lib/{chunk-1fy8azee.js → chunk-fasqtjq1.js} +1 -1
- package/build/lib/{chunk-1jvwqnem.js → chunk-gm3b9j4y.js} +104 -40
- package/build/lib/{chunk-r4j8ybn9.js → chunk-hys7nemr.js} +87 -36
- package/build/lib/{chunk-7pwa92rn.js → chunk-j9668h16.js} +1 -1
- package/build/lib/{chunk-ba41jh41.js → chunk-kcw4cpr3.js} +418 -133
- package/build/lib/{chunk-z96pbjhd.js → chunk-m4swxy5r.js} +13 -6
- package/build/lib/{chunk-xhdpgpkm.js → chunk-mbsde9d0.js} +2 -2
- package/build/lib/{chunk-9yksqgzr.js → chunk-mpvjfvz0.js} +20 -13
- package/build/lib/{chunk-2qsq76xq.js → chunk-qkz5sm0d.js} +128 -34
- package/build/lib/{chunk-nhfax4gb.js → chunk-rfyjqybp.js} +1 -1
- package/build/lib/{chunk-mg03jdmt.js → chunk-vsnwzne5.js} +1 -1
- package/build/lib/{chunk-acgbyf5h.js → chunk-ydxhkgjw.js} +3 -2
- package/build/lib/{chunk-bb0ekhkw.js → chunk-z8kej0sp.js} +69 -18
- package/build/lib/core/agents/agentRuntime.d.ts +2 -1
- package/build/lib/core/agents/defineAgent.d.ts +3 -2
- package/build/lib/core/agents/offSecAgent/index.d.ts +3 -1
- package/build/lib/core/agents/offSecAgent/index.js +10 -8
- package/build/lib/core/agents/offSecAgent/prompt.d.ts +3 -1
- package/build/lib/core/agents/offSecAgent/subagentSpawner.d.ts +2 -1
- package/build/lib/core/agents/offSecAgent/subagentSpawner.js +5 -5
- package/build/lib/core/agents/offSecAgent/tools/index.js +4 -4
- package/build/lib/core/agents/offSecAgent/tools/listMemories.d.ts +11 -1
- package/build/lib/core/agents/offSecAgent/tools/reportError.d.ts +2 -1
- package/build/lib/core/agents/offSecAgent/tools/runPentestWorkflow.d.ts +20 -1
- package/build/lib/core/agents/offSecAgent/tools/spawnPentestAgent.d.ts +4 -7
- package/build/lib/core/agents/offSecAgent/tools/spawnPentestSwarm.d.ts +7 -1
- package/build/lib/core/agents/offSecAgent/tools/types.d.ts +2 -1
- package/build/lib/core/agents/offSecAgent/types.d.ts +7 -1
- package/build/lib/core/agents/specialized/attackSurface/blackboxAgent.js +9 -9
- package/build/lib/core/agents/specialized/attackSurface/schemas.js +9 -9
- package/build/lib/core/agents/specialized/authenticationAgent/index.js +10 -10
- package/build/lib/core/agents/specialized/codeAgent/agent.js +9 -9
- package/build/lib/core/agents/specialized/codeAgent/prompts.d.ts +1 -0
- package/build/lib/core/agents/specialized/findingJudge/agent.js +8 -8
- package/build/lib/core/agents/specialized/findingJudge/index.js +3 -3
- package/build/lib/core/agents/specialized/patching/index.js +10 -10
- package/build/lib/core/agents/specialized/pentest/agent.d.ts +18 -4
- package/build/lib/core/agents/specialized/pentest/agent.js +11 -9
- package/build/lib/core/agents/specialized/whiteboxAttackSurface/index.js +9 -9
- package/build/lib/core/ai/ai.d.ts +23 -6
- package/build/lib/core/ai/ai.js +2 -2
- package/build/lib/core/ai/index.js +2 -2
- package/build/lib/core/ai/models/claude-capabilities.d.ts +3 -2
- package/build/lib/core/ai/models/concentrate.d.ts +1 -0
- package/build/lib/core/ai/models/index.d.ts +1 -1
- package/build/lib/core/ai/providers/concentrate.d.ts +1 -0
- package/build/lib/core/ai/utils.d.ts +2 -0
- package/build/lib/core/ai/utils.js +4 -2
- package/build/lib/core/api/index.d.ts +3 -0
- package/build/lib/core/api/index.js +22 -19
- package/build/lib/core/api/targetedPentest.d.ts +1 -0
- package/build/lib/core/api/targetedPentest.js +10 -10
- package/build/lib/core/config/config.d.ts +3 -0
- package/build/lib/core/config/index.js +1 -1
- package/build/lib/core/findings/registry.js +3 -3
- package/build/lib/core/session/index.d.ts +12 -0
- package/build/lib/core/session/index.js +2 -2
- package/build/lib/core/session/persistence.d.ts +7 -0
- package/build/lib/core/session/persistence.js +7 -3
- package/build/lib/core/workflows/fastStrike.d.ts +3 -1
- package/build/lib/core/workflows/pentest.d.ts +8 -1
- package/build/lib/core/workflows/pentest.js +15 -15
- package/build/lib/core/workflows/seams.js +4 -4
- package/build/lib/core/workflows/whiteboxAttackSurface.js +11 -11
- package/build/lib/index.js +22 -22
- package/build/{logs-x62b7hk1.js → logs-70fyr848.js} +13 -13
- package/build/{native-rollout-evidence-c9yhfqcs.js → native-rollout-evidence-ntensvzb.js} +3 -3
- package/build/{offesecAgent-5whnpeta.js → offesecAgent-kk62tf60.js} +4 -4
- package/build/pentest-4jgznn7h.js +22 -0
- package/build/{pentests-e0f32aqx.js → pentests-3e41hj08.js} +13 -13
- package/build/recordedRunClient-w34kcch1.js +11 -0
- package/build/{targetedPentest-rcbs4nvp.js → targetedPentest-t9snxcj2.js} +18 -11
- package/build/{targets-xj9g3q0z.js → targets-1pyf21c7.js} +13 -13
- package/build/threatModel-48y5qjze.js +21 -0
- package/build/{uninstall-7s784q4a.js → uninstall-fbydd9t6.js} +1 -1
- package/build/{upload-4gvhwmvr.js → upload-sbhwe2fq.js} +4 -4
- package/build/{utils-cjrz64pc.js → utils-23903gcj.js} +3 -3
- package/package.json +1 -1
- package/src/cli.ts +48 -14
- package/src/core/agents/agentRuntime.test.ts +38 -0
- package/src/core/agents/agentRuntime.ts +5 -2
- package/src/core/agents/defineAgent.ts +3 -1
- package/src/core/agents/offSecAgent/index.ts +3 -0
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.test.ts +92 -5
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.ts +70 -31
- package/src/core/agents/offSecAgent/prompt.test.ts +46 -0
- package/src/core/agents/offSecAgent/prompt.ts +52 -8
- package/src/core/agents/offSecAgent/selectiveConstruction.publicPath.test.ts +38 -0
- package/src/core/agents/offSecAgent/selectiveConstruction.test.ts +64 -0
- package/src/core/agents/offSecAgent/subagentSpawner.ts +12 -1
- package/src/core/agents/offSecAgent/tools/delegateAuth.ts +1 -0
- package/src/core/agents/offSecAgent/tools/listMemories.test.ts +230 -0
- package/src/core/agents/offSecAgent/tools/listMemories.ts +73 -6
- package/src/core/agents/offSecAgent/tools/reportError.test.ts +6 -0
- package/src/core/agents/offSecAgent/tools/reportError.ts +10 -2
- package/src/core/agents/offSecAgent/tools/runAttackSurface.ts +2 -0
- package/src/core/agents/offSecAgent/tools/runPentestWorkflow.test.ts +57 -0
- package/src/core/agents/offSecAgent/tools/runPentestWorkflow.ts +19 -1
- package/src/core/agents/offSecAgent/tools/runWhiteboxScan.ts +5 -2
- package/src/core/agents/offSecAgent/tools/spawnCodingAgent.ts +1 -0
- package/src/core/agents/offSecAgent/tools/spawnPentestAgent.test.ts +72 -2
- package/src/core/agents/offSecAgent/tools/spawnPentestAgent.ts +32 -11
- package/src/core/agents/offSecAgent/tools/spawnPentestSwarm.ts +25 -5
- package/src/core/agents/offSecAgent/tools/threatModelGenerator.ts +1 -0
- package/src/core/agents/offSecAgent/tools/types.ts +6 -1
- package/src/core/agents/offSecAgent/tools/updateTask.ts +5 -1
- package/src/core/agents/offSecAgent/tools/whiteboxCandidates.ts +11 -4
- package/src/core/agents/offSecAgent/types.ts +9 -0
- package/src/core/agents/specialized/codeAgent/agent.test.ts +7 -0
- package/src/core/agents/specialized/codeAgent/agent.ts +9 -2
- package/src/core/agents/specialized/codeAgent/prompts.ts +6 -0
- package/src/core/agents/specialized/pentest/agent.test.ts +116 -0
- package/src/core/agents/specialized/pentest/agent.ts +178 -49
- package/src/core/agents/specialized/pentest/results.test.ts +59 -4
- package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.ts +1 -0
- package/src/core/ai/ai.operator-context.bench.test.ts +1408 -0
- package/src/core/ai/ai.recorded-context.test.ts +74 -0
- package/src/core/ai/ai.test.ts +54 -0
- package/src/core/ai/ai.ts +312 -82
- package/src/core/ai/compactionTelemetry.test.ts +2 -2
- package/src/core/ai/models/anthropic.ts +6 -0
- package/src/core/ai/models/bedrock.ts +18 -0
- package/src/core/ai/models/claude-capabilities.ts +29 -8
- package/src/core/ai/models/concentrate.ts +52 -0
- package/src/core/ai/models/index.ts +25 -4
- package/src/core/ai/models/models.test.ts +154 -0
- package/src/core/ai/models/openrouter.ts +43 -1
- package/src/core/ai/providers/anthropic-models.test.ts +60 -1
- package/src/core/ai/providers/bedrock-models.test.ts +81 -0
- package/src/core/ai/providers/concentrate.test.ts +31 -0
- package/src/core/ai/providers/concentrate.ts +11 -0
- package/src/core/ai/providers/gateway-models.test.ts +16 -6
- package/src/core/ai/utils.native-rollout-evidence.test.ts +1 -0
- package/src/core/ai/utils.ts +189 -143
- package/src/core/api/blackboxPentest.ts +9 -1
- package/src/core/api/index.ts +9 -0
- package/src/core/api/targetedPentest.ts +19 -5
- package/src/core/config/config.test.ts +35 -0
- package/src/core/config/config.ts +5 -0
- package/src/core/observability/telemetry.test.ts +2 -3
- package/src/core/session/index.ts +5 -0
- package/src/core/session/persistence.test.ts +62 -0
- package/src/core/session/persistence.ts +56 -0
- package/src/core/workflows/fastStrike.seams.test.ts +149 -0
- package/src/core/workflows/fastStrike.test.ts +18 -1
- package/src/core/workflows/fastStrike.ts +103 -11
- package/src/core/workflows/pentest.test.ts +104 -0
- package/src/core/workflows/pentest.ts +110 -7
- package/src/core/workflows/seams.test.ts +13 -0
- package/src/core/workflows/seams.ts +5 -1
- package/src/core/workflows/whiteboxAttackSurface.ts +1 -0
- package/src/tui/components/chat/loading-indicator.tsx +20 -4
- package/src/tui/components/chat/message-list.tsx +1 -0
- package/src/tui/components/commands/__tests__/advanced-settings-lifecycle.tsx +176 -0
- package/src/tui/components/commands/advanced-settings.test.ts +28 -0
- package/src/tui/components/commands/advanced-settings.tsx +237 -19
- package/src/tui/components/operator-dashboard/index.tsx +46 -9
- package/src/tui/components/operator-dashboard/logic.test.ts +106 -0
- package/src/tui/components/operator-dashboard/logic.ts +42 -2
- package/src/tui/components/operator-dashboard/run-events.test.ts +3 -1
- package/src/tui/components/shared/__tests__/tool-renderer-lifecycle.tsx +18 -0
- package/src/tui/components/shared/action-label.test.ts +9 -0
- package/src/tui/components/shared/compacting-icon.tsx +18 -0
- package/src/tui/components/shared/index.ts +1 -0
- package/src/tui/components/shared/tool-registry.ts +1 -0
- package/src/tui/components/shared/tool-renderer.tsx +21 -7
- package/src/tui/context/route.tsx +1 -0
- package/src/tui/keybindings/registry.ts +2 -0
- package/build/agent-6w7egcf1.js +0 -13
- package/build/agent-9zx75feh.js +0 -13
- package/build/pentest-e61hc38s.js +0 -22
- package/build/recordedRunClient-dp032c32.js +0 -11
- package/build/threatModel-jkxfa40s.js +0 -21
|
@@ -1,22 +1,43 @@
|
|
|
1
|
-
type
|
|
1
|
+
export type ClaudeThinkingEffort = "low" | "medium" | "high" | "xhigh" | "max";
|
|
2
|
+
|
|
3
|
+
export type ClaudeCapabilities = {
|
|
2
4
|
alwaysOnThinking: boolean;
|
|
3
5
|
bindsThinking?: boolean;
|
|
6
|
+
defaultEffort: ClaudeThinkingEffort;
|
|
4
7
|
};
|
|
5
8
|
|
|
6
9
|
const CLAUDE_CAPABILITIES: Record<string, ClaudeCapabilities> = {
|
|
7
|
-
"claude-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"claude-
|
|
10
|
+
"claude-haiku-5-5": {
|
|
11
|
+
alwaysOnThinking: false,
|
|
12
|
+
bindsThinking: true,
|
|
13
|
+
defaultEffort: "medium",
|
|
14
|
+
},
|
|
15
|
+
"claude-sonnet-5-5": {
|
|
16
|
+
alwaysOnThinking: true,
|
|
17
|
+
bindsThinking: true,
|
|
18
|
+
defaultEffort: "high",
|
|
19
|
+
},
|
|
20
|
+
"claude-opus-5-5": {
|
|
21
|
+
alwaysOnThinking: true,
|
|
22
|
+
bindsThinking: true,
|
|
23
|
+
defaultEffort: "medium",
|
|
24
|
+
},
|
|
25
|
+
"claude-fable-5-1": {
|
|
26
|
+
alwaysOnThinking: true,
|
|
27
|
+
bindsThinking: true,
|
|
28
|
+
defaultEffort: "high",
|
|
29
|
+
},
|
|
30
|
+
"claude-opus-5": { alwaysOnThinking: false, defaultEffort: "high" },
|
|
31
|
+
"claude-sonnet-5": { alwaysOnThinking: false, defaultEffort: "high" },
|
|
32
|
+
"claude-fable-5": { alwaysOnThinking: true, defaultEffort: "high" },
|
|
13
33
|
};
|
|
14
34
|
|
|
15
35
|
export function getClaudeCapabilities(
|
|
16
36
|
modelId: string,
|
|
17
37
|
): ClaudeCapabilities | undefined {
|
|
18
38
|
const nativeId = modelId
|
|
19
|
-
.replace(/^(concentrate:|
|
|
39
|
+
.replace(/^(concentrate:|pensar:)/, "")
|
|
40
|
+
.replace(/^(?:(?:us|global|eu|au|jp)\.)?anthropic[./]/, "")
|
|
20
41
|
.replace(/(\d)\.(\d)/g, "$1-$2");
|
|
21
42
|
return CLAUDE_CAPABILITIES[nativeId];
|
|
22
43
|
}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { ModelInfo } from "../ai";
|
|
2
2
|
|
|
3
|
+
// Concentrate does not route on max_output_tokens, so these use the lowest
|
|
4
|
+
// ceiling among each slug's upstream providers.
|
|
5
|
+
export const CONCENTRATE_MAX_OUTPUT_TOKENS: Readonly<Record<string, number>> = {
|
|
6
|
+
"concentrate:kimi-k3": 32_768,
|
|
7
|
+
"concentrate:qwen3.8-max": 32_768,
|
|
8
|
+
"concentrate:qwen3.8-27b": 32_768,
|
|
9
|
+
"concentrate:deepseek-v4-1-flash": 32_768,
|
|
10
|
+
"concentrate:deepseek-v4-1-flash-1017": 131_072,
|
|
11
|
+
};
|
|
12
|
+
|
|
3
13
|
// Curated from Concentrate's public model catalog. The local prefix keeps
|
|
4
14
|
// gateway selections distinct from direct-provider models and is not sent.
|
|
5
15
|
export const CONCENTRATE_MODELS: ModelInfo[] = [
|
|
@@ -153,6 +163,36 @@ export const CONCENTRATE_MODELS: ModelInfo[] = [
|
|
|
153
163
|
provider: "concentrate",
|
|
154
164
|
contextLength: 1000000,
|
|
155
165
|
},
|
|
166
|
+
{
|
|
167
|
+
id: "concentrate:qwen3.8-max",
|
|
168
|
+
name: "Qwen3.8 Max",
|
|
169
|
+
provider: "concentrate",
|
|
170
|
+
contextLength: 256000,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "concentrate:qwen3.8-27b",
|
|
174
|
+
name: "Qwen3.8 27B",
|
|
175
|
+
provider: "concentrate",
|
|
176
|
+
contextLength: 262144,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: "concentrate:deepseek-v4-1-flash-1017",
|
|
180
|
+
name: "DeepSeek V4.1 Flash 1017",
|
|
181
|
+
provider: "concentrate",
|
|
182
|
+
contextLength: 1048576,
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "concentrate:deepseek-v4-1-flash",
|
|
186
|
+
name: "DeepSeek V4.1 Flash",
|
|
187
|
+
provider: "concentrate",
|
|
188
|
+
contextLength: 1000000,
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "concentrate:deepseek-v4-pro-0813",
|
|
192
|
+
name: "DeepSeek V4 Pro 0813",
|
|
193
|
+
provider: "concentrate",
|
|
194
|
+
contextLength: 1048576,
|
|
195
|
+
},
|
|
156
196
|
{
|
|
157
197
|
id: "concentrate:deepseek-v3-2",
|
|
158
198
|
name: "DeepSeek V3.2",
|
|
@@ -165,6 +205,12 @@ export const CONCENTRATE_MODELS: ModelInfo[] = [
|
|
|
165
205
|
provider: "concentrate",
|
|
166
206
|
contextLength: 256000,
|
|
167
207
|
},
|
|
208
|
+
{
|
|
209
|
+
id: "concentrate:kimi-k3",
|
|
210
|
+
name: "Kimi K3",
|
|
211
|
+
provider: "concentrate",
|
|
212
|
+
contextLength: 1048576,
|
|
213
|
+
},
|
|
168
214
|
{
|
|
169
215
|
id: "concentrate:kimi-k2-thinking",
|
|
170
216
|
name: "Kimi K2 Thinking",
|
|
@@ -177,6 +223,12 @@ export const CONCENTRATE_MODELS: ModelInfo[] = [
|
|
|
177
223
|
provider: "concentrate",
|
|
178
224
|
contextLength: 204800,
|
|
179
225
|
},
|
|
226
|
+
{
|
|
227
|
+
id: "concentrate:mimo-v2.6-pro",
|
|
228
|
+
name: "MiMo V2.6 Pro",
|
|
229
|
+
provider: "concentrate",
|
|
230
|
+
contextLength: 1048576,
|
|
231
|
+
},
|
|
180
232
|
{
|
|
181
233
|
id: "concentrate:glm-5.3",
|
|
182
234
|
name: "GLM-5.3",
|
|
@@ -12,9 +12,15 @@ import { ANTHROPIC_MODELS } from "./anthropic";
|
|
|
12
12
|
import { BEDROCK_MODELS } from "./bedrock";
|
|
13
13
|
import { getClaudeCapabilities } from "./claude-capabilities";
|
|
14
14
|
|
|
15
|
-
export {
|
|
15
|
+
export {
|
|
16
|
+
type ClaudeThinkingEffort,
|
|
17
|
+
getClaudeCapabilities,
|
|
18
|
+
} from "./claude-capabilities";
|
|
16
19
|
|
|
17
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
CONCENTRATE_MAX_OUTPUT_TOKENS,
|
|
22
|
+
CONCENTRATE_MODELS,
|
|
23
|
+
} from "./concentrate";
|
|
18
24
|
import { GOOGLE_MODELS } from "./google";
|
|
19
25
|
import { INCEPTION_MODELS } from "./inception";
|
|
20
26
|
// Bedrock Mantle (OpenAI Responses API) — curated manually.
|
|
@@ -100,6 +106,8 @@ export function getMaxOutputTokens(
|
|
|
100
106
|
function lookupOutputBudgetByPattern(modelId: string): number {
|
|
101
107
|
if (modelId === "chat-latest") return 128_000;
|
|
102
108
|
if (getClaudeCapabilities(modelId)) return 128_000;
|
|
109
|
+
const concentrateBudget = CONCENTRATE_MAX_OUTPUT_TOKENS[modelId];
|
|
110
|
+
if (concentrateBudget) return concentrateBudget;
|
|
103
111
|
// OpenRouter uses dots in Claude version numbers (anthropic/claude-opus-4.6)
|
|
104
112
|
// while native Anthropic uses dashes (claude-opus-4-6-20250929). Normalize
|
|
105
113
|
// digit.digit sequences to dashes so all Claude patterns match both forms.
|
|
@@ -219,14 +227,22 @@ function lookupOutputBudgetByPattern(modelId: string): number {
|
|
|
219
227
|
return 131_072;
|
|
220
228
|
}
|
|
221
229
|
|
|
230
|
+
if (modelId.includes("mimo-v2.6-pro")) {
|
|
231
|
+
return 131_072;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (modelId.includes("kimi-k3")) {
|
|
235
|
+
return 131_072;
|
|
236
|
+
}
|
|
237
|
+
|
|
222
238
|
// GLM 5 models ship a ~131K (128Ki) max-output window. Matching the family
|
|
223
239
|
// keeps Bedrock and OpenRouter model IDs on the same budget.
|
|
224
240
|
if (modelId.includes("glm-5")) {
|
|
225
241
|
return 131_072;
|
|
226
242
|
}
|
|
227
243
|
|
|
228
|
-
// V4
|
|
229
|
-
if (
|
|
244
|
+
// DeepSeek V4's larger output window must precede the legacy DeepSeek fallback.
|
|
245
|
+
if (/deepseek-v4[.-]/.test(modelId)) {
|
|
230
246
|
return 384_000;
|
|
231
247
|
}
|
|
232
248
|
|
|
@@ -235,6 +251,11 @@ function lookupOutputBudgetByPattern(modelId: string): number {
|
|
|
235
251
|
return 8_192;
|
|
236
252
|
}
|
|
237
253
|
|
|
254
|
+
// Qwen3.8's first-party 131K output window must precede the Qwen fallback.
|
|
255
|
+
if (modelId.includes("qwen3.8")) {
|
|
256
|
+
return 131_072;
|
|
257
|
+
}
|
|
258
|
+
|
|
238
259
|
// Qwen3 Coder ships a 16K max-output window over its 128K+ context. Match the
|
|
239
260
|
// whole `qwen` family so future Bedrock/OpenRouter qwen ids don't silently
|
|
240
261
|
// inherit the 4,096 default.
|
|
@@ -103,6 +103,11 @@ describe("getMaxOutputTokens", () => {
|
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
it("recognizes Claude tier-specific budgets", () => {
|
|
106
|
+
expect(getMaxOutputTokens("claude-haiku-5-5")).toBe(128_000);
|
|
107
|
+
expect(getMaxOutputTokens("global.anthropic.claude-haiku-5-5")).toBe(
|
|
108
|
+
128_000,
|
|
109
|
+
);
|
|
110
|
+
expect(getMaxOutputTokens("anthropic/claude-haiku-5.5")).toBe(128_000);
|
|
106
111
|
expect(getMaxOutputTokens("claude-sonnet-4-5-20250929")).toBe(64_000);
|
|
107
112
|
expect(getMaxOutputTokens("claude-opus-4-5-20250101")).toBe(64_000);
|
|
108
113
|
expect(getMaxOutputTokens("claude-haiku-4-5-20251001")).toBe(64_000);
|
|
@@ -111,6 +116,24 @@ describe("getMaxOutputTokens", () => {
|
|
|
111
116
|
expect(getMaxOutputTokens("claude-3-5-haiku-20241022")).toBe(8_192);
|
|
112
117
|
});
|
|
113
118
|
|
|
119
|
+
it("registers Claude Haiku 5.5 across Anthropic, Bedrock, and OpenRouter", () => {
|
|
120
|
+
expect(getModelInfo("claude-haiku-5-5")).toMatchObject({
|
|
121
|
+
name: "Claude Haiku 5.5",
|
|
122
|
+
provider: "anthropic",
|
|
123
|
+
contextLength: 1_000_000,
|
|
124
|
+
});
|
|
125
|
+
expect(getModelInfo("global.anthropic.claude-haiku-5-5")).toMatchObject({
|
|
126
|
+
name: "Claude Haiku 5.5 (Global)",
|
|
127
|
+
provider: "bedrock",
|
|
128
|
+
contextLength: 1_000_000,
|
|
129
|
+
});
|
|
130
|
+
expect(getModelInfo("anthropic/claude-haiku-5.5")).toMatchObject({
|
|
131
|
+
name: "Claude Haiku 5.5",
|
|
132
|
+
provider: "openrouter",
|
|
133
|
+
contextLength: 1_000_000,
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
114
137
|
it("pins latest-tier Claude (4.6 + 4.7 + 4.8) to 128K output", () => {
|
|
115
138
|
// These ship the 128K window; they MUST not fall through to the
|
|
116
139
|
// generic `claude-opus-4-` / `claude-sonnet-4-` catch-alls (32K/64K)
|
|
@@ -288,3 +311,134 @@ describe("OpenAI reasoning effort support", () => {
|
|
|
288
311
|
);
|
|
289
312
|
});
|
|
290
313
|
});
|
|
314
|
+
|
|
315
|
+
describe("open-weight gateway models", () => {
|
|
316
|
+
it.each([
|
|
317
|
+
{
|
|
318
|
+
id: "xiaomi/mimo-v2.6-pro",
|
|
319
|
+
name: "MiMo-V2.6-Pro",
|
|
320
|
+
provider: "openrouter",
|
|
321
|
+
contextLength: 1_050_000,
|
|
322
|
+
maxOutputTokens: 131_072,
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
id: "concentrate:mimo-v2.6-pro",
|
|
326
|
+
name: "MiMo V2.6 Pro",
|
|
327
|
+
provider: "concentrate",
|
|
328
|
+
contextLength: 1_048_576,
|
|
329
|
+
maxOutputTokens: 131_072,
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
id: "moonshotai/kimi-k3",
|
|
333
|
+
name: "Kimi K3",
|
|
334
|
+
provider: "openrouter",
|
|
335
|
+
contextLength: 1_048_576,
|
|
336
|
+
maxOutputTokens: 131_072,
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
id: "concentrate:kimi-k3",
|
|
340
|
+
name: "Kimi K3",
|
|
341
|
+
provider: "concentrate",
|
|
342
|
+
contextLength: 1_048_576,
|
|
343
|
+
maxOutputTokens: 32_768,
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
id: "qwen/qwen3.8-max-0902",
|
|
347
|
+
name: "Qwen3.8 Max (0902)",
|
|
348
|
+
provider: "openrouter",
|
|
349
|
+
contextLength: 1_000_000,
|
|
350
|
+
maxOutputTokens: 131_072,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
id: "qwen/qwen3.8-27b",
|
|
354
|
+
name: "Qwen3.8 27B",
|
|
355
|
+
provider: "openrouter",
|
|
356
|
+
contextLength: 1_000_000,
|
|
357
|
+
maxOutputTokens: 131_072,
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
id: "qwen/qwen3.8-flash",
|
|
361
|
+
name: "Qwen3.8 Flash",
|
|
362
|
+
provider: "openrouter",
|
|
363
|
+
contextLength: 1_000_000,
|
|
364
|
+
maxOutputTokens: 131_072,
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: "concentrate:qwen3.8-max",
|
|
368
|
+
name: "Qwen3.8 Max",
|
|
369
|
+
provider: "concentrate",
|
|
370
|
+
contextLength: 256_000,
|
|
371
|
+
maxOutputTokens: 32_768,
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
id: "concentrate:qwen3.8-27b",
|
|
375
|
+
name: "Qwen3.8 27B",
|
|
376
|
+
provider: "concentrate",
|
|
377
|
+
contextLength: 262_144,
|
|
378
|
+
maxOutputTokens: 32_768,
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
id: "deepseek/deepseek-v4.1-flash-1017",
|
|
382
|
+
name: "DeepSeek V4.1 Flash 1017",
|
|
383
|
+
provider: "openrouter",
|
|
384
|
+
contextLength: 1_048_576,
|
|
385
|
+
maxOutputTokens: 384_000,
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
id: "deepseek/deepseek-v4-pro-0813",
|
|
389
|
+
name: "DeepSeek V4 Pro 0813",
|
|
390
|
+
provider: "openrouter",
|
|
391
|
+
contextLength: 1_048_576,
|
|
392
|
+
maxOutputTokens: 384_000,
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
id: "concentrate:deepseek-v4-1-flash",
|
|
396
|
+
name: "DeepSeek V4.1 Flash",
|
|
397
|
+
provider: "concentrate",
|
|
398
|
+
contextLength: 1_000_000,
|
|
399
|
+
maxOutputTokens: 32_768,
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
id: "concentrate:deepseek-v4-1-flash-1017",
|
|
403
|
+
name: "DeepSeek V4.1 Flash 1017",
|
|
404
|
+
provider: "concentrate",
|
|
405
|
+
contextLength: 1_048_576,
|
|
406
|
+
maxOutputTokens: 131_072,
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: "concentrate:deepseek-v4-pro-0813",
|
|
410
|
+
name: "DeepSeek V4 Pro 0813",
|
|
411
|
+
provider: "concentrate",
|
|
412
|
+
contextLength: 1_048_576,
|
|
413
|
+
maxOutputTokens: 384_000,
|
|
414
|
+
},
|
|
415
|
+
])("registers $id with its gateway limits", ({
|
|
416
|
+
id,
|
|
417
|
+
maxOutputTokens,
|
|
418
|
+
...info
|
|
419
|
+
}) => {
|
|
420
|
+
expect(getModelInfo(id)).toMatchObject(info);
|
|
421
|
+
expect(getMaxOutputTokens(id)).toBe(maxOutputTokens);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it.each([
|
|
425
|
+
"concentrate:mimo-v2.6-pro",
|
|
426
|
+
"concentrate:kimi-k3",
|
|
427
|
+
"concentrate:qwen3.8-max",
|
|
428
|
+
"concentrate:qwen3.8-27b",
|
|
429
|
+
"concentrate:deepseek-v4-1-flash",
|
|
430
|
+
"concentrate:deepseek-v4-1-flash-1017",
|
|
431
|
+
"concentrate:deepseek-v4-pro-0813",
|
|
432
|
+
])("offers every effort Concentrate can route for %s", (id) => {
|
|
433
|
+
expect(modelSupportsOpenAIReasoning(id)).toBe(true);
|
|
434
|
+
expect(getOpenAIReasoningEfforts(id)).toEqual([
|
|
435
|
+
"low",
|
|
436
|
+
"medium",
|
|
437
|
+
"high",
|
|
438
|
+
"xhigh",
|
|
439
|
+
"max",
|
|
440
|
+
]);
|
|
441
|
+
expect(normalizeOpenAIReasoningEffort(id)).toBe("medium");
|
|
442
|
+
expect(normalizeOpenAIReasoningEffort(id, "max")).toBe("max");
|
|
443
|
+
});
|
|
444
|
+
});
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
import type { ModelInfo } from "../ai";
|
|
5
5
|
export const OPENROUTER_MODELS: ModelInfo[] = [
|
|
6
|
+
{
|
|
7
|
+
id: "anthropic/claude-haiku-5.5",
|
|
8
|
+
name: "Claude Haiku 5.5",
|
|
9
|
+
provider: "openrouter",
|
|
10
|
+
contextLength: 1000000,
|
|
11
|
+
},
|
|
6
12
|
{
|
|
7
13
|
id: "anthropic/claude-sonnet-5.5",
|
|
8
14
|
name: "Claude Sonnet 5.5",
|
|
@@ -177,12 +183,24 @@ export const OPENROUTER_MODELS: ModelInfo[] = [
|
|
|
177
183
|
provider: "openrouter",
|
|
178
184
|
contextLength: 128000,
|
|
179
185
|
},
|
|
186
|
+
{
|
|
187
|
+
id: "deepseek/deepseek-v4.1-flash-1017",
|
|
188
|
+
name: "DeepSeek V4.1 Flash 1017",
|
|
189
|
+
provider: "openrouter",
|
|
190
|
+
contextLength: 1048576,
|
|
191
|
+
},
|
|
180
192
|
{
|
|
181
193
|
id: "deepseek/deepseek-v4.1-flash",
|
|
182
194
|
name: "DeepSeek V4.1 Flash",
|
|
183
195
|
provider: "openrouter",
|
|
184
196
|
contextLength: 1048576,
|
|
185
197
|
},
|
|
198
|
+
{
|
|
199
|
+
id: "deepseek/deepseek-v4-pro-0813",
|
|
200
|
+
name: "DeepSeek V4 Pro 0813",
|
|
201
|
+
provider: "openrouter",
|
|
202
|
+
contextLength: 1048576,
|
|
203
|
+
},
|
|
186
204
|
{
|
|
187
205
|
id: "deepseek/deepseek-chat",
|
|
188
206
|
name: "DeepSeek Chat",
|
|
@@ -217,7 +235,7 @@ export const OPENROUTER_MODELS: ModelInfo[] = [
|
|
|
217
235
|
id: "moonshotai/kimi-k3",
|
|
218
236
|
name: "Kimi K3",
|
|
219
237
|
provider: "openrouter",
|
|
220
|
-
contextLength:
|
|
238
|
+
contextLength: 1048576,
|
|
221
239
|
},
|
|
222
240
|
{
|
|
223
241
|
id: "moonshot/kimi-k2-turbo",
|
|
@@ -249,6 +267,24 @@ export const OPENROUTER_MODELS: ModelInfo[] = [
|
|
|
249
267
|
provider: "openrouter",
|
|
250
268
|
contextLength: 1048576,
|
|
251
269
|
},
|
|
270
|
+
{
|
|
271
|
+
id: "qwen/qwen3.8-max-0902",
|
|
272
|
+
name: "Qwen3.8 Max (0902)",
|
|
273
|
+
provider: "openrouter",
|
|
274
|
+
contextLength: 1000000,
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
id: "qwen/qwen3.8-27b",
|
|
278
|
+
name: "Qwen3.8 27B",
|
|
279
|
+
provider: "openrouter",
|
|
280
|
+
contextLength: 1000000,
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: "qwen/qwen3.8-flash",
|
|
284
|
+
name: "Qwen3.8 Flash",
|
|
285
|
+
provider: "openrouter",
|
|
286
|
+
contextLength: 1000000,
|
|
287
|
+
},
|
|
252
288
|
{
|
|
253
289
|
id: "qwen/qwen3-8b",
|
|
254
290
|
name: "Qwen 3 8B Thinking",
|
|
@@ -315,6 +351,12 @@ export const OPENROUTER_MODELS: ModelInfo[] = [
|
|
|
315
351
|
provider: "openrouter",
|
|
316
352
|
contextLength: 256000,
|
|
317
353
|
},
|
|
354
|
+
{
|
|
355
|
+
id: "xiaomi/mimo-v2.6-pro",
|
|
356
|
+
name: "MiMo-V2.6-Pro",
|
|
357
|
+
provider: "openrouter",
|
|
358
|
+
contextLength: 1050000,
|
|
359
|
+
},
|
|
318
360
|
{
|
|
319
361
|
id: "z-ai/glm-4.7-flash",
|
|
320
362
|
name: "GLM 4.7 Flash",
|
|
@@ -12,12 +12,14 @@ import { getMaxOutputTokens } from "../models";
|
|
|
12
12
|
import { getProviderModel } from "../utils";
|
|
13
13
|
|
|
14
14
|
const boundModels = new Set([
|
|
15
|
+
"claude-haiku-5-5",
|
|
15
16
|
"claude-sonnet-5-5",
|
|
16
17
|
"claude-opus-5-5",
|
|
17
18
|
"claude-fable-5-1",
|
|
18
19
|
]);
|
|
19
20
|
|
|
20
21
|
const models = [
|
|
22
|
+
{ id: "claude-haiku-5-5", required: false },
|
|
21
23
|
{ id: "claude-sonnet-5-5", required: true },
|
|
22
24
|
{ id: "claude-opus-5-5", required: true },
|
|
23
25
|
{ id: "claude-fable-5-1", required: true },
|
|
@@ -105,7 +107,10 @@ describe.each(models)("Anthropic $id", ({ id, required }) => {
|
|
|
105
107
|
expect(body).toMatchObject({
|
|
106
108
|
model: id,
|
|
107
109
|
max_tokens: 128_000,
|
|
108
|
-
output_config: {
|
|
110
|
+
output_config: {
|
|
111
|
+
...(enableThinking || required ? { effort: "medium" } : {}),
|
|
112
|
+
format: { type: "json_schema" },
|
|
113
|
+
},
|
|
109
114
|
thinking: { type: enableThinking || required ? "adaptive" : "disabled" },
|
|
110
115
|
});
|
|
111
116
|
expect(body.temperature).toBeUndefined();
|
|
@@ -287,3 +292,57 @@ describe.each(models)("Anthropic $id", ({ id, required }) => {
|
|
|
287
292
|
);
|
|
288
293
|
});
|
|
289
294
|
});
|
|
295
|
+
|
|
296
|
+
describe("Anthropic Claude Haiku 5.5 effort", () => {
|
|
297
|
+
it.each([
|
|
298
|
+
"xhigh",
|
|
299
|
+
"max",
|
|
300
|
+
] as const)("sends the %s effort with adaptive thinking", async (effort) => {
|
|
301
|
+
const fetchMock = vi.fn(
|
|
302
|
+
async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
|
303
|
+
completion("claude-haiku-5-5"),
|
|
304
|
+
);
|
|
305
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
306
|
+
|
|
307
|
+
await getProviderModel("claude-haiku-5-5", {
|
|
308
|
+
anthropicAPIKey: "test-key",
|
|
309
|
+
}).doGenerate({
|
|
310
|
+
prompt: [{ role: "user", content: [{ type: "text", text: "Check" }] }],
|
|
311
|
+
providerOptions: buildReasoningProviderOptions("claude-haiku-5-5", {
|
|
312
|
+
enableThinking: true,
|
|
313
|
+
thinkingEffort: effort,
|
|
314
|
+
}),
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const call = fetchMock.mock.calls[0];
|
|
318
|
+
if (!call) throw new Error("Expected a Claude request");
|
|
319
|
+
expect(JSON.parse(String(call[1]?.body))).toMatchObject({
|
|
320
|
+
thinking: { type: "adaptive" },
|
|
321
|
+
output_config: { effort },
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("uses the documented medium effort by default", async () => {
|
|
326
|
+
const fetchMock = vi.fn(
|
|
327
|
+
async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
|
328
|
+
completion("claude-haiku-5-5"),
|
|
329
|
+
);
|
|
330
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
331
|
+
|
|
332
|
+
await getProviderModel("claude-haiku-5-5", {
|
|
333
|
+
anthropicAPIKey: "test-key",
|
|
334
|
+
}).doGenerate({
|
|
335
|
+
prompt: [{ role: "user", content: [{ type: "text", text: "Check" }] }],
|
|
336
|
+
providerOptions: buildReasoningProviderOptions("claude-haiku-5-5", {
|
|
337
|
+
enableThinking: true,
|
|
338
|
+
}),
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const call = fetchMock.mock.calls[0];
|
|
342
|
+
if (!call) throw new Error("Expected a Claude request");
|
|
343
|
+
expect(JSON.parse(String(call[1]?.body))).toMatchObject({
|
|
344
|
+
thinking: { type: "adaptive" },
|
|
345
|
+
output_config: { effort: "medium" },
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { buildReasoningProviderOptions } from "../ai";
|
|
3
|
+
import { getProviderModel } from "../utils";
|
|
4
|
+
|
|
5
|
+
function completion() {
|
|
6
|
+
return Response.json({
|
|
7
|
+
output: {
|
|
8
|
+
message: {
|
|
9
|
+
role: "assistant",
|
|
10
|
+
content: [{ text: "ok" }],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
stopReason: "end_turn",
|
|
14
|
+
usage: {
|
|
15
|
+
inputTokens: 12,
|
|
16
|
+
outputTokens: 2,
|
|
17
|
+
totalTokens: 14,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
afterEach(() => vi.unstubAllGlobals());
|
|
23
|
+
|
|
24
|
+
describe("Bedrock Claude Haiku 5.5", () => {
|
|
25
|
+
it("sends adaptive max effort to the global inference profile", async () => {
|
|
26
|
+
const fetchMock = vi.fn(
|
|
27
|
+
async (_input: RequestInfo | URL, _init?: RequestInit) => completion(),
|
|
28
|
+
);
|
|
29
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
30
|
+
|
|
31
|
+
await getProviderModel("global.anthropic.claude-haiku-5-5", {
|
|
32
|
+
bedrock: { apiKey: "test-key", region: "us-east-1" },
|
|
33
|
+
}).doGenerate({
|
|
34
|
+
prompt: [{ role: "user", content: [{ type: "text", text: "Check" }] }],
|
|
35
|
+
providerOptions: buildReasoningProviderOptions(
|
|
36
|
+
"global.anthropic.claude-haiku-5-5",
|
|
37
|
+
{ enableThinking: true, thinkingEffort: "max" },
|
|
38
|
+
),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const call = fetchMock.mock.calls[0];
|
|
42
|
+
if (!call) throw new Error("Expected a Bedrock request");
|
|
43
|
+
expect(String(call[0])).toContain(
|
|
44
|
+
"/model/global.anthropic.claude-haiku-5-5/converse",
|
|
45
|
+
);
|
|
46
|
+
expect(new Headers(call[1]?.headers).get("authorization")).toBe(
|
|
47
|
+
"Bearer test-key",
|
|
48
|
+
);
|
|
49
|
+
expect(JSON.parse(String(call[1]?.body))).toMatchObject({
|
|
50
|
+
additionalModelRequestFields: {
|
|
51
|
+
thinking: { type: "adaptive", display: "summarized" },
|
|
52
|
+
output_config: { effort: "max" },
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("forwards thinking disabled explicitly", async () => {
|
|
58
|
+
const fetchMock = vi.fn(
|
|
59
|
+
async (_input: RequestInfo | URL, _init?: RequestInit) => completion(),
|
|
60
|
+
);
|
|
61
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
62
|
+
|
|
63
|
+
await getProviderModel("global.anthropic.claude-haiku-5-5", {
|
|
64
|
+
bedrock: { apiKey: "test-key", region: "us-east-1" },
|
|
65
|
+
}).doGenerate({
|
|
66
|
+
prompt: [{ role: "user", content: [{ type: "text", text: "Check" }] }],
|
|
67
|
+
providerOptions: buildReasoningProviderOptions(
|
|
68
|
+
"global.anthropic.claude-haiku-5-5",
|
|
69
|
+
{ enableThinking: false },
|
|
70
|
+
),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const call = fetchMock.mock.calls[0];
|
|
74
|
+
if (!call) throw new Error("Expected a Bedrock request");
|
|
75
|
+
expect(JSON.parse(String(call[1]?.body))).toMatchObject({
|
|
76
|
+
additionalModelRequestFields: {
|
|
77
|
+
thinking: { type: "disabled" },
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -79,6 +79,37 @@ describe("createConcentrateModel", () => {
|
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
it.each([
|
|
83
|
+
"mimo-v2.6-pro",
|
|
84
|
+
"kimi-k3",
|
|
85
|
+
"qwen3.8-max",
|
|
86
|
+
"qwen3.8-27b",
|
|
87
|
+
"deepseek-v4-1-flash",
|
|
88
|
+
"deepseek-v4-1-flash-1017",
|
|
89
|
+
"deepseek-v4-pro-0813",
|
|
90
|
+
])("forces reasoning on the %s Responses request", async (slug) => {
|
|
91
|
+
const fetchMock = vi.fn(
|
|
92
|
+
async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
|
93
|
+
completedResponse(),
|
|
94
|
+
);
|
|
95
|
+
const model = createConcentrateModel(`concentrate:${slug}`, {
|
|
96
|
+
apiKey: "sk-cn-test",
|
|
97
|
+
fetch: fetchMock,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await model.doGenerate({
|
|
101
|
+
prompt: [{ role: "user", content: [{ type: "text", text: "Say ok" }] }],
|
|
102
|
+
providerOptions: { openai: { reasoningEffort: "max" } },
|
|
103
|
+
} satisfies LanguageModelV3CallOptions);
|
|
104
|
+
|
|
105
|
+
const body = JSON.parse(String(fetchMock.mock.calls[0]?.[1]?.body));
|
|
106
|
+
expect(body).toMatchObject({
|
|
107
|
+
model: slug,
|
|
108
|
+
store: false,
|
|
109
|
+
reasoning: { effort: "max", summary: "auto" },
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
82
113
|
it("fails before constructing a request when the key is missing", () => {
|
|
83
114
|
expect(() =>
|
|
84
115
|
createConcentrateModel("concentrate:glm-5.3", { apiKey: " " }),
|
|
@@ -9,6 +9,16 @@ import { getClaudeCapabilities } from "../models";
|
|
|
9
9
|
|
|
10
10
|
export const CONCENTRATE_BASE_URL = "https://api.concentrate.ai/v1";
|
|
11
11
|
export const CONCENTRATE_GLM_5_3_MODEL_ID = "concentrate:glm-5.3";
|
|
12
|
+
// Concentrate routes each reasoning effort only to upstreams that accept it.
|
|
13
|
+
export const CONCENTRATE_REASONING_MODEL_IDS: ReadonlySet<string> = new Set([
|
|
14
|
+
"concentrate:mimo-v2.6-pro",
|
|
15
|
+
"concentrate:kimi-k3",
|
|
16
|
+
"concentrate:qwen3.8-max",
|
|
17
|
+
"concentrate:qwen3.8-27b",
|
|
18
|
+
"concentrate:deepseek-v4-1-flash",
|
|
19
|
+
"concentrate:deepseek-v4-1-flash-1017",
|
|
20
|
+
"concentrate:deepseek-v4-pro-0813",
|
|
21
|
+
]);
|
|
12
22
|
|
|
13
23
|
const RETRYABLE_STATUSES = new Set([424, 429, 500, 503, 504]);
|
|
14
24
|
|
|
@@ -139,6 +149,7 @@ export function createConcentrateModel(
|
|
|
139
149
|
return withConcentrateDefaults(
|
|
140
150
|
concentrate.responses(upstreamModelId),
|
|
141
151
|
modelId === CONCENTRATE_GLM_5_3_MODEL_ID ||
|
|
152
|
+
CONCENTRATE_REASONING_MODEL_IDS.has(modelId) ||
|
|
142
153
|
/^gpt-6[.-]/.test(upstreamModelId) ||
|
|
143
154
|
!!getClaudeCapabilities(modelId),
|
|
144
155
|
);
|