@pensar/apex 2.6.1 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/build/agent-4f87bydg.js +13 -0
  2. package/build/{agent-ayreaj6z.js → agent-6h49fhz1.js} +5 -5
  3. package/build/{agent-yby11zaq.js → agent-a5vq5fsm.js} +6 -6
  4. package/build/{agent-runs-g37vkrjr.js → agent-runs-9nncftzk.js} +16 -16
  5. package/build/agent-sa0ty54v.js +13 -0
  6. package/build/{apps-xn6km9yn.js → apps-rh90z2nb.js} +13 -13
  7. package/build/{auth-d105wc64.js → auth-hshx11mc.js} +13 -13
  8. package/build/{blackboxAgent-s56sgx9b.js → blackboxAgent-t6zq0ekj.js} +6 -6
  9. package/build/{blackboxPentest-ps78v3w7.js → blackboxPentest-eskvsmez.js} +11 -11
  10. package/build/{cli-d37a42dc.js → cli-29179gt8.js} +8 -8
  11. package/build/{cli-gx71jcke.js → cli-2etfgtj3.js} +1 -1
  12. package/build/{cli-ngq9dr8n.js → cli-6r1ntbmf.js} +3 -3
  13. package/build/{cli-709rvekb.js → cli-9eyk8rhx.js} +1 -1
  14. package/build/{cli-ae8jqxqr.js → cli-c4x5b3q4.js} +2 -2
  15. package/build/{cli-az3xq70v.js → cli-c9nnxr52.js} +1 -1
  16. package/build/{cli-1ve18npr.js → cli-dawkcveq.js} +1 -1
  17. package/build/{cli-3sp6nd8d.js → cli-dqrqgfrp.js} +2 -2
  18. package/build/{cli-7eea4e2y.js → cli-e0v6hd3d.js} +6 -6
  19. package/build/{cli-k2nwxta0.js → cli-ewav0q78.js} +2 -2
  20. package/build/{cli-kb21qhvm.js → cli-fk5e62a6.js} +2 -2
  21. package/build/{cli-65g6rcat.js → cli-gzgyjs36.js} +1 -1
  22. package/build/{cli-c05y640n.js → cli-mrk3hg6f.js} +1 -1
  23. package/build/{cli-dpsw2fe6.js → cli-prw2dfje.js} +353 -185
  24. package/build/{cli-qgz1q9g5.js → cli-pwhx13h3.js} +105 -36
  25. package/build/{cli-n2en7j5b.js → cli-q0wmet0t.js} +1 -1
  26. package/build/{cli-xtc2t6me.js → cli-tf2kp8s4.js} +3 -3
  27. package/build/{cli-fy6vh2a7.js → cli-vdbnh2ha.js} +1 -1
  28. package/build/cli.js +37 -37
  29. package/build/{config-zpqkd5cz.js → config-srw06gyv.js} +1 -1
  30. package/build/{fastStrike-mcjdvwez.js → fastStrike-gaphkhrs.js} +5 -5
  31. package/build/{fixes-kytx5dmj.js → fixes-j99tce5t.js} +13 -13
  32. package/build/{index-wqetp6gq.js → index-3rsrzfje.js} +5 -5
  33. package/build/{index-fv64eb32.js → index-652yqmn2.js} +2 -2
  34. package/build/{index-n65z6v7b.js → index-6fxag2h2.js} +6 -6
  35. package/build/{index-r9yjkfrv.js → index-a9yy0fe3.js} +4 -4
  36. package/build/{index-dr3tg1w3.js → index-c1tgca1w.js} +1 -1
  37. package/build/{index-qv4cc65p.js → index-fsv57ssp.js} +13 -13
  38. package/build/{index-ns4m4s01.js → index-y9h10rfq.js} +4 -4
  39. package/build/{index-4vqdgb42.js → index-yj0ye642.js} +1236 -1195
  40. package/build/{index-je6hcsqr.js → index-ynsam8mg.js} +1 -1
  41. package/build/{issues-eb3q9d3a.js → issues-267ytycy.js} +13 -13
  42. package/build/{knowledge-fqsvtx0f.js → knowledge-44acmwfw.js} +13 -13
  43. package/build/lib/{chunk-yrnrbjes.js → chunk-2015fqpw.js} +1 -1
  44. package/build/lib/{chunk-acgbyf5h.js → chunk-3jr0sp3v.js} +1 -1
  45. package/build/lib/{chunk-7pwa92rn.js → chunk-45ne0t6e.js} +1 -1
  46. package/build/lib/{chunk-nhfax4gb.js → chunk-5ma2ns65.js} +1 -1
  47. package/build/lib/{chunk-z96pbjhd.js → chunk-8zfn4feq.js} +1 -1
  48. package/build/lib/{chunk-1jvwqnem.js → chunk-93b8vp9x.js} +3 -3
  49. package/build/lib/{chunk-r4j8ybn9.js → chunk-9kmc9yp6.js} +37 -20
  50. package/build/lib/{chunk-9yksqgzr.js → chunk-bb2sekn4.js} +11 -11
  51. package/build/lib/{chunk-e8yy2k73.js → chunk-c3e9aen5.js} +1 -1
  52. package/build/lib/{chunk-v3dk9j7k.js → chunk-db0bmkrv.js} +11 -11
  53. package/build/lib/{chunk-1yct6cra.js → chunk-dm8yvkdy.js} +1 -1
  54. package/build/lib/{chunk-xhdpgpkm.js → chunk-dvn6bg2m.js} +2 -2
  55. package/build/lib/{chunk-9tt2021m.js → chunk-fwe0fdb5.js} +9 -9
  56. package/build/lib/{chunk-3c00n0cy.js → chunk-gfzspfyd.js} +3 -3
  57. package/build/lib/{chunk-ba41jh41.js → chunk-hw0vcs3m.js} +297 -127
  58. package/build/lib/{chunk-r2dkp4tb.js → chunk-m8w0npxg.js} +1 -1
  59. package/build/lib/{chunk-z137x08b.js → chunk-mbm9w4ac.js} +5 -5
  60. package/build/lib/{chunk-4hwzqthr.js → chunk-mjey3y7s.js} +1 -1
  61. package/build/lib/{chunk-mg03jdmt.js → chunk-mw108bmx.js} +1 -1
  62. package/build/lib/{chunk-1azdancq.js → chunk-njn4tjsr.js} +1 -1
  63. package/build/lib/{chunk-bb0ekhkw.js → chunk-p8jd9s8k.js} +8 -8
  64. package/build/lib/{chunk-2qsq76xq.js → chunk-t6yh604c.js} +62 -10
  65. package/build/lib/{chunk-1fy8azee.js → chunk-yqengqce.js} +1 -1
  66. package/build/lib/{chunk-w66ce82a.js → chunk-ysmhn1p6.js} +1 -1
  67. package/build/lib/core/agents/offSecAgent/index.js +7 -7
  68. package/build/lib/core/agents/offSecAgent/subagentSpawner.js +5 -5
  69. package/build/lib/core/agents/offSecAgent/tools/index.js +4 -4
  70. package/build/lib/core/agents/offSecAgent/tools/listMemories.d.ts +11 -1
  71. package/build/lib/core/agents/specialized/attackSurface/blackboxAgent.js +9 -9
  72. package/build/lib/core/agents/specialized/attackSurface/schemas.js +9 -9
  73. package/build/lib/core/agents/specialized/authenticationAgent/index.js +10 -10
  74. package/build/lib/core/agents/specialized/codeAgent/agent.js +9 -9
  75. package/build/lib/core/agents/specialized/findingJudge/agent.js +8 -8
  76. package/build/lib/core/agents/specialized/findingJudge/index.js +3 -3
  77. package/build/lib/core/agents/specialized/patching/index.js +10 -10
  78. package/build/lib/core/agents/specialized/pentest/agent.js +9 -9
  79. package/build/lib/core/agents/specialized/whiteboxAttackSurface/index.js +9 -9
  80. package/build/lib/core/ai/ai.d.ts +23 -6
  81. package/build/lib/core/ai/ai.js +2 -2
  82. package/build/lib/core/ai/index.js +2 -2
  83. package/build/lib/core/ai/models/claude-capabilities.d.ts +3 -2
  84. package/build/lib/core/ai/models/index.d.ts +1 -1
  85. package/build/lib/core/ai/utils.d.ts +2 -0
  86. package/build/lib/core/ai/utils.js +4 -2
  87. package/build/lib/core/api/index.js +19 -19
  88. package/build/lib/core/api/targetedPentest.js +10 -10
  89. package/build/lib/core/config/index.js +1 -1
  90. package/build/lib/core/findings/registry.js +3 -3
  91. package/build/lib/core/session/index.js +2 -2
  92. package/build/lib/core/session/persistence.js +3 -3
  93. package/build/lib/core/workflows/pentest.js +15 -15
  94. package/build/lib/core/workflows/seams.js +4 -4
  95. package/build/lib/core/workflows/whiteboxAttackSurface.js +11 -11
  96. package/build/lib/index.js +22 -22
  97. package/build/{logs-x62b7hk1.js → logs-wx69vy65.js} +13 -13
  98. package/build/{native-rollout-evidence-c9yhfqcs.js → native-rollout-evidence-2akrepvz.js} +3 -3
  99. package/build/{offesecAgent-5whnpeta.js → offesecAgent-zewvmk98.js} +4 -4
  100. package/build/pentest-n2mjksg2.js +22 -0
  101. package/build/{pentests-e0f32aqx.js → pentests-xvj8g8h4.js} +13 -13
  102. package/build/recordedRunClient-a0ye97sw.js +11 -0
  103. package/build/{targetedPentest-rcbs4nvp.js → targetedPentest-p3cdq712.js} +6 -6
  104. package/build/{targets-xj9g3q0z.js → targets-1wajqhm7.js} +13 -13
  105. package/build/threatModel-g9pbtnt1.js +21 -0
  106. package/build/{uninstall-7s784q4a.js → uninstall-jpm5ppfb.js} +1 -1
  107. package/build/{upload-4gvhwmvr.js → upload-csny5mns.js} +4 -4
  108. package/build/{utils-cjrz64pc.js → utils-tzbr4bxg.js} +3 -3
  109. package/package.json +1 -1
  110. package/src/core/agents/offSecAgent/offensiveSecurityAgent.test.ts +92 -5
  111. package/src/core/agents/offSecAgent/offensiveSecurityAgent.ts +49 -28
  112. package/src/core/agents/offSecAgent/tools/listMemories.test.ts +230 -0
  113. package/src/core/agents/offSecAgent/tools/listMemories.ts +73 -6
  114. package/src/core/ai/ai.operator-context.bench.test.ts +1408 -0
  115. package/src/core/ai/ai.recorded-context.test.ts +74 -0
  116. package/src/core/ai/ai.test.ts +54 -0
  117. package/src/core/ai/ai.ts +299 -80
  118. package/src/core/ai/compactionTelemetry.test.ts +2 -2
  119. package/src/core/ai/models/anthropic.ts +6 -0
  120. package/src/core/ai/models/bedrock.ts +18 -0
  121. package/src/core/ai/models/claude-capabilities.ts +29 -8
  122. package/src/core/ai/models/index.ts +4 -1
  123. package/src/core/ai/models/models.test.ts +23 -0
  124. package/src/core/ai/models/openrouter.ts +6 -0
  125. package/src/core/ai/providers/anthropic-models.test.ts +60 -1
  126. package/src/core/ai/providers/bedrock-models.test.ts +81 -0
  127. package/src/core/ai/providers/gateway-models.test.ts +16 -6
  128. package/src/core/ai/utils.native-rollout-evidence.test.ts +1 -0
  129. package/src/core/ai/utils.ts +189 -143
  130. package/src/core/observability/telemetry.test.ts +2 -3
  131. package/src/tui/components/chat/loading-indicator.tsx +20 -4
  132. package/src/tui/components/chat/message-list.tsx +1 -0
  133. package/src/tui/components/operator-dashboard/run-events.test.ts +3 -1
  134. package/src/tui/components/shared/__tests__/tool-renderer-lifecycle.tsx +18 -0
  135. package/src/tui/components/shared/action-label.test.ts +9 -0
  136. package/src/tui/components/shared/compacting-icon.tsx +18 -0
  137. package/src/tui/components/shared/index.ts +1 -0
  138. package/src/tui/components/shared/tool-registry.ts +1 -0
  139. package/src/tui/components/shared/tool-renderer.tsx +21 -7
  140. package/build/agent-6w7egcf1.js +0 -13
  141. package/build/agent-9zx75feh.js +0 -13
  142. package/build/pentest-e61hc38s.js +0 -22
  143. package/build/recordedRunClient-dp032c32.js +0 -11
  144. package/build/threatModel-jkxfa40s.js +0 -21
@@ -1,22 +1,43 @@
1
- type ClaudeCapabilities = {
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-sonnet-5-5": { alwaysOnThinking: true, bindsThinking: true },
8
- "claude-opus-5-5": { alwaysOnThinking: true, bindsThinking: true },
9
- "claude-fable-5-1": { alwaysOnThinking: true, bindsThinking: true },
10
- "claude-opus-5": { alwaysOnThinking: false },
11
- "claude-sonnet-5": { alwaysOnThinking: false },
12
- "claude-fable-5": { alwaysOnThinking: true },
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:|anthropic\/)/, "")
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
  }
@@ -12,7 +12,10 @@ import { ANTHROPIC_MODELS } from "./anthropic";
12
12
  import { BEDROCK_MODELS } from "./bedrock";
13
13
  import { getClaudeCapabilities } from "./claude-capabilities";
14
14
 
15
- export { getClaudeCapabilities } from "./claude-capabilities";
15
+ export {
16
+ type ClaudeThinkingEffort,
17
+ getClaudeCapabilities,
18
+ } from "./claude-capabilities";
16
19
 
17
20
  import { CONCENTRATE_MODELS } from "./concentrate";
18
21
  import { GOOGLE_MODELS } from "./google";
@@ -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)
@@ -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",
@@ -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: { effort: "medium", format: { type: "json_schema" } },
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
+ });
@@ -25,6 +25,12 @@ vi.mock("undici", async (importOriginal) => {
25
25
  });
26
26
 
27
27
  const models = [
28
+ {
29
+ slug: "claude-haiku-5-5",
30
+ context: 1000000,
31
+ openrouter: "anthropic/claude-haiku-5.5",
32
+ concentrate: false,
33
+ },
28
34
  {
29
35
  slug: "claude-sonnet-5-5",
30
36
  context: 1000000,
@@ -376,9 +382,9 @@ describe.each(routes)("Gateway $id", ({ id, upstream, provider, context }) => {
376
382
  });
377
383
 
378
384
  it("preserves the highest supported reasoning effort through the SDK", async () => {
379
- const effort = upstream.includes("claude")
380
- ? "high"
381
- : getOpenAIReasoningEfforts(id).at(-1);
385
+ const claudeEffort = upstream.includes("claude-haiku-5.5") ? "max" : "high";
386
+ const openAIEffort = getOpenAIReasoningEfforts(id).at(-1);
387
+ const effort = upstream.includes("claude") ? claudeEffort : openAIEffort;
382
388
  const fetchMock = vi.fn(
383
389
  async (_input: RequestInfo | URL, _init?: RequestInit) =>
384
390
  completedResponse(upstream, openrouter),
@@ -387,9 +393,9 @@ describe.each(routes)("Gateway $id", ({ id, upstream, provider, context }) => {
387
393
  await getProviderModel(id, credentials).doGenerate({
388
394
  ...options(),
389
395
  providerOptions: buildReasoningProviderOptions(id, {
390
- openAIReasoningEffort: effort,
396
+ openAIReasoningEffort: openAIEffort,
391
397
  enableThinking: true,
392
- thinkingEffort: "high",
398
+ thinkingEffort: claudeEffort,
393
399
  }),
394
400
  });
395
401
  const call = fetchMock.mock.calls[0];
@@ -440,7 +446,11 @@ describe.each(routes)("Gateway $id", ({ id, upstream, provider, context }) => {
440
446
  if (!call) throw new Error("Expected structured Claude request");
441
447
  const body = JSON.parse(String(call[1]?.body));
442
448
  expect(body.reasoning.effort).toBe(
443
- modelRequiresThinking(id) ? "high" : "none",
449
+ modelRequiresThinking(id)
450
+ ? /claude-opus-5[.-]5/.test(upstream)
451
+ ? "medium"
452
+ : "high"
453
+ : "none",
444
454
  );
445
455
  expect(
446
456
  openrouter ? body.response_format.type : body.text.format.type,
@@ -46,6 +46,7 @@ vi.mock("ai", async () => {
46
46
 
47
47
  vi.mock("./ai", () => ({
48
48
  buildOpenRouterProviderOptions: vi.fn(() => undefined),
49
+ buildReasoningProviderOptions: vi.fn(() => undefined),
49
50
  recordContextRestart: vi.fn(async () => {}),
50
51
  streamResponse: mocks.streamResponse,
51
52
  }));