diff --git a/layers/identity/server/tasks/send-digests.ts b/layers/identity/server/tasks/send-digests.ts index 8676f99d..f972d9a5 100644 --- a/layers/identity/server/tasks/send-digests.ts +++ b/layers/identity/server/tasks/send-digests.ts @@ -17,7 +17,7 @@ import { renderDigest } from '../utils/digest-template' import { sendEmailWithEnv, signUnsubToken } from '../utils/email' const CRON = '0 9 1 * *' -// Kill switch: the per-repo digest sentence runs `anthropic/claude-haiku-4.5`, +// Kill switch: the per-repo digest sentence runs `anthropic/claude-sonnet-5.5`, // a partner model brokered through the Workers AI binding, so every call bills // against AI Gateway credits. Those credits are exhausted, so each monthly run // returned `provider_failure: 2021: Insufficient AI Gateway credits`, delivered diff --git a/layers/identity/server/utils/digest-summary.ts b/layers/identity/server/utils/digest-summary.ts index 49c0efec..fd138b01 100644 --- a/layers/identity/server/utils/digest-summary.ts +++ b/layers/identity/server/utils/digest-summary.ts @@ -15,15 +15,15 @@ export interface AiBinding { messages: Array<{ role: 'user' | 'assistant', content: string }> max_tokens: number system?: string - temperature?: number + thinking?: { type: 'between_tools' } }) => Promise } -// Anthropic Haiku 4.5 brokered through Workers AI. The binding handles auth; +// Anthropic Sonnet 5.5 brokered through Workers AI. The binding handles auth; // no Anthropic key or gateway token needed. Swap to a llama/qwen if cost or // latency need to drop later — caller doesn't care which model produced // `response`. -const MODEL = 'anthropic/claude-haiku-4.5' +const MODEL = 'anthropic/claude-sonnet-5.5' export interface SubscriptionContext { owner: string @@ -133,6 +133,7 @@ Output JSON only, no prose, with this exact shape: system: systemPrompt, messages: [{ role: 'user', content: userPrompt }], max_tokens: 1024, + thinking: { type: 'between_tools' }, }).then( value => ({ _tag: 'response' as const, value }), error => ({ diff --git a/layers/registry/server/jobs/generate-faqs.ts b/layers/registry/server/jobs/generate-faqs.ts index bf43dc8e..00472a8d 100644 --- a/layers/registry/server/jobs/generate-faqs.ts +++ b/layers/registry/server/jobs/generate-faqs.ts @@ -73,7 +73,7 @@ export async function generateFaqs(ctx: FaqContext, skill: FaqSkill): Promise { - const { systemPrompt, userPrompt, model = 'claude-haiku-4-5-20251001' } = opts + const { systemPrompt, userPrompt, model = 'claude-haiku-5-5' } = opts // CC wraps/injects its own framing around --system-prompt, so Haiku tends // to stay conversational. For batch jobs we fold the system prompt into the diff --git a/workers/skill-harness/src/gateway.ts b/workers/skill-harness/src/gateway.ts index e29860af..9f7ea45d 100644 --- a/workers/skill-harness/src/gateway.ts +++ b/workers/skill-harness/src/gateway.ts @@ -90,9 +90,10 @@ export async function forwardSandboxRequest( if (!await options.consumeModelCall()) return Response.json({ code: 'MODEL_CALL_LIMIT' }, { status: 403 }) const standardInput = { ...input } - delete standardInput.speed + for (const field of ['speed', 'temperature', 'top_p', 'top_k']) + delete standardInput[field] const thinking = input.thinking && typeof input.thinking === 'object' && 'type' in input.thinking && input.thinking.type === 'enabled' - ? { type: 'enabled', budget_tokens: 2048 } + ? { type: 'adaptive' } : input.thinking return fetchClient('https://api.anthropic.com/v1/messages', { method: 'POST', diff --git a/workers/skill-harness/test/gateway.test.ts b/workers/skill-harness/test/gateway.test.ts index f898316d..31fa6258 100644 --- a/workers/skill-harness/test/gateway.test.ts +++ b/workers/skill-harness/test/gateway.test.ts @@ -132,18 +132,19 @@ describe('sandbox credential gateway', () => { }) it('routes Anthropic with Worker credentials and enforced model limits', async () => { - const options = { ...fixture(), provider: 'anthropic' as const, model: 'claude-sonnet-4-6' } + const options = { ...fixture(), provider: 'anthropic' as const, model: 'claude-sonnet-5-5' } const response = await forwardSandboxRequest(new Request('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'x-api-key': 'container-key', 'anthropic-beta': 'untrusted-beta' }, - body: JSON.stringify({ model: 'expensive-model', max_tokens: 32000, service_tier: 'priority', speed: 'fast', messages: [], thinking: { type: 'enabled', budget_tokens: 16000 } }), + body: JSON.stringify({ model: 'expensive-model', max_tokens: 32000, service_tier: 'priority', speed: 'fast', temperature: 0.3, top_p: 0.9, top_k: 20, messages: [], thinking: { type: 'enabled', budget_tokens: 16000 } }), }), options) expect(response.status).toBe(200) const [, forwarded] = options.fetch.mock.calls[0]! expect(new Headers(forwarded?.headers).get('x-api-key')).toBe('worker-only-secret') expect(new Headers(forwarded?.headers).get('anthropic-beta')).toBeNull() - expect(JSON.parse(String(forwarded?.body))).not.toHaveProperty('speed') - expect(JSON.parse(String(forwarded?.body))).toMatchObject({ model: 'claude-sonnet-4-6', max_tokens: 8192, service_tier: 'standard_only', thinking: { type: 'enabled', budget_tokens: 2048 } }) + for (const field of ['speed', 'temperature', 'top_p', 'top_k']) + expect(JSON.parse(String(forwarded?.body))).not.toHaveProperty(field) + expect(JSON.parse(String(forwarded?.body))).toMatchObject({ model: 'claude-sonnet-5-5', max_tokens: 8192, service_tier: 'standard_only', thinking: { type: 'adaptive' } }) }) it.each([{ tools: [{ type: 'web_search_20250305' }] }, { mcp_servers: [{ url: 'https://external.example' }] }])('blocks Anthropic hosted execution %j', async (body) => {