This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

thinking

+36 -2
+2
.env.example
··· 18 18 ANTHROPIC_MODEL= 19 19 ANTHROPIC_MAX_TOKENS=8192 20 20 ANTHROPIC_VERSION=2024-10-22 21 + # Budget tokens for Anthropic extended thinking (≥1024, < max_tokens). Only used when ENABLE_THINKING=true. 22 + ANTHROPIC_THINKING_BUDGET=4096 21 23 22 24 # ── Memory embeddings ──────────────────────────────────────────────────────── 23 25 # Used for semantic memory reranking and low-information chatter suppression.
+34 -2
src/runner/anthropic.ts
··· 2 2 import OpenAI from "openai" 3 3 import { recordMetric } from "../metrics" 4 4 import { emit } from "../stream" 5 + import { ENABLE_THINKING } from "./util" 5 6 import type { CompletionRequest, CompletionTurnResult, ToolCallAssembly } from "./loop-shared" 6 7 7 8 // ── config ────────────────────────────────────────────────────────────── ··· 11 12 export const ANTHROPIC_MODEL = process.env.ANTHROPIC_MODEL ?? "" 12 13 export const ANTHROPIC_MAX_TOKENS = Math.max(1, Number.parseInt(process.env.ANTHROPIC_MAX_TOKENS ?? "8192", 10)) || 8192 13 14 export const ANTHROPIC_VERSION = process.env.ANTHROPIC_VERSION ?? "2024-10-22" 15 + export const ANTHROPIC_THINKING_BUDGET = Math.max( 16 + 1024, 17 + Number.parseInt(process.env.ANTHROPIC_THINKING_BUDGET ?? "4096", 10) || 4096, 18 + ) 14 19 15 20 const client = new Anthropic({ 16 21 apiKey: ANTHROPIC_API_KEY, ··· 204 209 205 210 // ── streaming conversion (Anthropic SSE → OpenAI chunks) ──────────────── 206 211 207 - function makeChunk(partial: Omit<OpenAI.Chat.ChatCompletionChunk.Choice.Delta, "role" | "content" | "tool_calls"> & { 212 + function makeChunk(partial: Omit<OpenAI.Chat.ChatCompletionChunk.Choice.Delta, "role" | "content" | "tool_calls" | "reasoning_content"> & { 208 213 role?: "assistant" 209 214 content?: string | null 215 + reasoning_content?: string 210 216 tool_calls?: OpenAI.Chat.ChatCompletionChunk.Choice.Delta.ToolCall[] 211 217 }): OpenAI.Chat.ChatCompletionChunk { 212 218 return { ··· 259 265 const delta = event.delta 260 266 if (delta.type === "text_delta") { 261 267 yield makeChunk({ content: delta.text }) 268 + } else if (delta.type === "thinking_delta") { 269 + yield makeChunk({ reasoning_content: delta.thinking }) 262 270 } else if (delta.type === "input_json_delta") { 263 271 const tool = toolBuffers.get(index) 264 272 if (tool) { ··· 319 327 let usage: OpenAI.Completions.CompletionUsage | undefined 320 328 let emittedText = false 321 329 let emittedThinking = false 330 + const reasoningParts: string[] = [] 322 331 323 332 for await (const chunk of stream) { 324 333 if (chunk.usage) usage = chunk.usage ··· 330 339 reasoning_content?: string 331 340 } 332 341 342 + if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) { 343 + reasoningParts.push(delta.reasoning_content) 344 + } 345 + 333 346 if (typeof delta.content === "string" && delta.content.length > 0) { 347 + if (ENABLE_THINKING && !emittedThinking && reasoningParts.length > 0) { 348 + emit({ type: "thinking", text: reasoningParts.join("") }) 349 + emittedThinking = true 350 + } 334 351 contentParts.push(delta.content) 335 352 emit({ type: "text", text: delta.content }) 336 353 emittedText = true ··· 368 385 ...(finalToolCalls.length > 0 ? { tool_calls: finalToolCalls } : {}), 369 386 } 370 387 388 + if (reasoningParts.length > 0) { 389 + ;(message as OpenAI.Chat.ChatCompletionMessage & { reasoning_content?: string }).reasoning_content = 390 + reasoningParts.join("") 391 + } 392 + 371 393 const elapsedMs = Math.max(0, Date.now() - startedAt) 372 394 const tokensPerSecond = 373 395 usage && elapsedMs > 0 ? usage.completion_tokens / (elapsedMs / 1000) : undefined ··· 377 399 usage, 378 400 emittedText, 379 401 emittedThinking, 380 - bufferedThinking: "", 402 + bufferedThinking: reasoningParts.join(""), 381 403 elapsedMs, 382 404 tokensPerSecond, 383 405 } ··· 395 417 max_tokens: ANTHROPIC_MAX_TOKENS, 396 418 messages, 397 419 ...(system ? { system } : {}), 420 + } 421 + 422 + if (ENABLE_THINKING) { 423 + const thinkingBudget = Math.min(ANTHROPIC_MAX_TOKENS - 1, ANTHROPIC_THINKING_BUDGET) 424 + if (thinkingBudget >= 1024) { 425 + ;(body as unknown as Record<string, unknown>).thinking = { 426 + type: "enabled", 427 + budget_tokens: thinkingBudget, 428 + } 429 + } 398 430 } 399 431 400 432 if (request.tools.length > 0 && request.tool_choice !== "none") {