mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 09:01:14 +00:00
feat(ai): add adaptive thinking support for Claude Opus 4.6
- Add adaptive thinking mode (type: 'adaptive') for Opus 4.6+
- Add effort parameter ('low', 'medium', 'high', 'max') for adaptive thinking
- thinkingEnabled now auto-detects: adaptive for 4.6+, budget-based for older
- streamSimple/completeSimple map ThinkingLevel to effort levels for Opus 4.6
- Add tests for Opus 4.6 adaptive thinking and GPT-5.3 Codex
- Update @anthropic-ai/sdk to 0.73.0
- Update @aws-sdk/client-bedrock-runtime to 3.983.0
- Update @google/genai to 1.40.0
- Remove fast-xml-parser override (no longer needed)
This commit is contained in:
parent
b07b72ba2b
commit
4c4d787b1a
6 changed files with 260 additions and 18 deletions
|
|
@ -2,6 +2,20 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added adaptive thinking support for Claude Opus 4.6 with effort levels (`low`, `medium`, `high`, `max`)
|
||||
- Added `effort` option to `AnthropicOptions` for controlling adaptive thinking depth
|
||||
- `thinkingEnabled` now automatically uses adaptive thinking for Opus 4.6+ models and budget-based thinking for older models
|
||||
- `streamSimple`/`completeSimple` automatically map `ThinkingLevel` to effort levels for Opus 4.6
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `@anthropic-ai/sdk` to 0.73.0
|
||||
- Updated `@aws-sdk/client-bedrock-runtime` to 3.983.0
|
||||
- Updated `@google/genai` to 1.40.0
|
||||
- Removed `fast-xml-parser` override (no longer needed)
|
||||
|
||||
## [0.52.0] - 2026-02-05
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@
|
|||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.71.2",
|
||||
"@aws-sdk/client-bedrock-runtime": "^3.966.0",
|
||||
"@google/genai": "1.34.0",
|
||||
"@anthropic-ai/sdk": "^0.73.0",
|
||||
"@aws-sdk/client-bedrock-runtime": "^3.983.0",
|
||||
"@google/genai": "^1.40.0",
|
||||
"@mistralai/mistralai": "1.10.0",
|
||||
"@sinclair/typebox": "^0.34.41",
|
||||
"ajv": "^8.17.1",
|
||||
|
|
|
|||
|
|
@ -151,9 +151,30 @@ function convertContentBlocks(content: (TextContent | ImageContent)[]):
|
|||
return blocks;
|
||||
}
|
||||
|
||||
export type AnthropicEffort = "low" | "medium" | "high" | "max";
|
||||
|
||||
export interface AnthropicOptions extends StreamOptions {
|
||||
/**
|
||||
* Enable extended thinking.
|
||||
* For Opus 4.6+: uses adaptive thinking (Claude decides when/how much to think).
|
||||
* For older models: uses budget-based thinking with thinkingBudgetTokens.
|
||||
*/
|
||||
thinkingEnabled?: boolean;
|
||||
/**
|
||||
* Token budget for extended thinking (older models only).
|
||||
* Ignored for Opus 4.6+ which uses adaptive thinking.
|
||||
*/
|
||||
thinkingBudgetTokens?: number;
|
||||
/**
|
||||
* Effort level for adaptive thinking (Opus 4.6+ only).
|
||||
* Controls how much thinking Claude allocates:
|
||||
* - "max": Always thinks with no constraints
|
||||
* - "high": Always thinks, deep reasoning (default)
|
||||
* - "medium": Moderate thinking, may skip for simple queries
|
||||
* - "low": Minimal thinking, skips for simple tasks
|
||||
* Ignored for older models.
|
||||
*/
|
||||
effort?: AnthropicEffort;
|
||||
interleavedThinking?: boolean;
|
||||
toolChoice?: "auto" | "any" | "none" | { type: "tool"; name: string };
|
||||
}
|
||||
|
|
@ -377,6 +398,34 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
|
|||
return stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a model supports adaptive thinking (Opus 4.6+)
|
||||
*/
|
||||
function supportsAdaptiveThinking(modelId: string): boolean {
|
||||
// Opus 4.6 model IDs (with or without date suffix)
|
||||
return modelId.includes("opus-4-6") || modelId.includes("opus-4.6");
|
||||
}
|
||||
|
||||
/**
|
||||
* Map ThinkingLevel to Anthropic effort levels for adaptive thinking
|
||||
*/
|
||||
function mapThinkingLevelToEffort(level: SimpleStreamOptions["reasoning"]): AnthropicEffort {
|
||||
switch (level) {
|
||||
case "minimal":
|
||||
return "low";
|
||||
case "low":
|
||||
return "low";
|
||||
case "medium":
|
||||
return "medium";
|
||||
case "high":
|
||||
return "high";
|
||||
case "xhigh":
|
||||
return "max";
|
||||
default:
|
||||
return "high";
|
||||
}
|
||||
}
|
||||
|
||||
export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleStreamOptions> = (
|
||||
model: Model<"anthropic-messages">,
|
||||
context: Context,
|
||||
|
|
@ -392,6 +441,17 @@ export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleS
|
|||
return streamAnthropic(model, context, { ...base, thinkingEnabled: false } satisfies AnthropicOptions);
|
||||
}
|
||||
|
||||
// For Opus 4.6+: use adaptive thinking with effort level
|
||||
// For older models: use budget-based thinking
|
||||
if (supportsAdaptiveThinking(model.id)) {
|
||||
const effort = mapThinkingLevelToEffort(options.reasoning);
|
||||
return streamAnthropic(model, context, {
|
||||
...base,
|
||||
thinkingEnabled: true,
|
||||
effort,
|
||||
} satisfies AnthropicOptions);
|
||||
}
|
||||
|
||||
const adjusted = adjustMaxTokensForThinking(
|
||||
base.maxTokens || 0,
|
||||
model.maxTokens,
|
||||
|
|
@ -517,11 +577,21 @@ function buildParams(
|
|||
params.tools = convertTools(context.tools, isOAuthToken);
|
||||
}
|
||||
|
||||
// Configure thinking mode: adaptive (Opus 4.6+) or budget-based (older models)
|
||||
if (options?.thinkingEnabled && model.reasoning) {
|
||||
params.thinking = {
|
||||
type: "enabled",
|
||||
budget_tokens: options.thinkingBudgetTokens || 1024,
|
||||
};
|
||||
if (supportsAdaptiveThinking(model.id)) {
|
||||
// Adaptive thinking: Claude decides when and how much to think
|
||||
params.thinking = { type: "adaptive" };
|
||||
if (options.effort) {
|
||||
params.output_config = { effort: options.effort };
|
||||
}
|
||||
} else {
|
||||
// Budget-based thinking for older models
|
||||
params.thinking = {
|
||||
type: "enabled",
|
||||
budget_tokens: options.thinkingBudgetTokens || 1024,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (options?.toolChoice) {
|
||||
|
|
|
|||
|
|
@ -922,6 +922,42 @@ describe("Generate E2E Tests", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("Anthropic OAuth Provider (claude-opus-4-6 with adaptive thinking)", () => {
|
||||
const model = getModel("anthropic", "claude-opus-4-6");
|
||||
|
||||
it.skipIf(!anthropicOAuthToken)("should complete basic text generation", { retry: 3 }, async () => {
|
||||
await basicTextGeneration(model, { apiKey: anthropicOAuthToken });
|
||||
});
|
||||
|
||||
it.skipIf(!anthropicOAuthToken)("should handle tool calling", { retry: 3 }, async () => {
|
||||
await handleToolCall(model, { apiKey: anthropicOAuthToken });
|
||||
});
|
||||
|
||||
it.skipIf(!anthropicOAuthToken)("should handle streaming", { retry: 3 }, async () => {
|
||||
await handleStreaming(model, { apiKey: anthropicOAuthToken });
|
||||
});
|
||||
|
||||
it.skipIf(!anthropicOAuthToken)("should handle adaptive thinking with effort high", { retry: 3 }, async () => {
|
||||
await handleThinking(model, { apiKey: anthropicOAuthToken, thinkingEnabled: true, effort: "high" });
|
||||
});
|
||||
|
||||
it.skipIf(!anthropicOAuthToken)("should handle adaptive thinking with effort medium", { retry: 3 }, async () => {
|
||||
await handleThinking(model, { apiKey: anthropicOAuthToken, thinkingEnabled: true, effort: "medium" });
|
||||
});
|
||||
|
||||
it.skipIf(!anthropicOAuthToken)(
|
||||
"should handle multi-turn with adaptive thinking and tools",
|
||||
{ retry: 3 },
|
||||
async () => {
|
||||
await multiTurn(model, { apiKey: anthropicOAuthToken, thinkingEnabled: true, effort: "high" });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(!anthropicOAuthToken)("should handle image input", { retry: 3 }, async () => {
|
||||
await handleImage(model, { apiKey: anthropicOAuthToken });
|
||||
});
|
||||
});
|
||||
|
||||
describe("GitHub Copilot Provider (gpt-4o via OpenAI Completions)", () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
|
||||
|
|
@ -1098,6 +1134,34 @@ describe("Generate E2E Tests", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("OpenAI Codex Provider (gpt-5.3-codex)", () => {
|
||||
const llm = getModel("openai-codex", "gpt-5.3-codex");
|
||||
|
||||
it.skipIf(!openaiCodexToken)("should complete basic text generation", { retry: 3 }, async () => {
|
||||
await basicTextGeneration(llm, { apiKey: openaiCodexToken });
|
||||
});
|
||||
|
||||
it.skipIf(!openaiCodexToken)("should handle tool calling", { retry: 3 }, async () => {
|
||||
await handleToolCall(llm, { apiKey: openaiCodexToken });
|
||||
});
|
||||
|
||||
it.skipIf(!openaiCodexToken)("should handle streaming", { retry: 3 }, async () => {
|
||||
await handleStreaming(llm, { apiKey: openaiCodexToken });
|
||||
});
|
||||
|
||||
it.skipIf(!openaiCodexToken)("should handle thinking with reasoningEffort high", { retry: 3 }, async () => {
|
||||
await handleThinking(llm, { apiKey: openaiCodexToken, reasoningEffort: "high" });
|
||||
});
|
||||
|
||||
it.skipIf(!openaiCodexToken)("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||
await multiTurn(llm, { apiKey: openaiCodexToken, reasoningEffort: "high" });
|
||||
});
|
||||
|
||||
it.skipIf(!openaiCodexToken)("should handle image input", { retry: 3 }, async () => {
|
||||
await handleImage(llm, { apiKey: openaiCodexToken });
|
||||
});
|
||||
});
|
||||
|
||||
describe.skipIf(!hasBedrockCredentials())("Amazon Bedrock Provider (claude-sonnet-4-5)", () => {
|
||||
const llm = getModel("amazon-bedrock", "global.anthropic.claude-sonnet-4-5-20250929-v1:0");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue