mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 22:35:51 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6536757428 | ||
|
|
a0dc4540ca | ||
|
|
7e4df5c3e9 | ||
|
|
4d939e5722 |
1
build.ts
1
build.ts
@@ -11,6 +11,7 @@ rmSync(outdir, { recursive: true, force: true })
|
|||||||
// Default features that match the official CLI build.
|
// Default features that match the official CLI build.
|
||||||
// Additional features can be enabled via FEATURE_<NAME>=1 env vars.
|
// Additional features can be enabled via FEATURE_<NAME>=1 env vars.
|
||||||
const DEFAULT_BUILD_FEATURES = [
|
const DEFAULT_BUILD_FEATURES = [
|
||||||
|
'BUDDY', 'TRANSCRIPT_CLASSIFIER', 'BRIDGE_MODE',
|
||||||
'AGENT_TRIGGERS_REMOTE',
|
'AGENT_TRIGGERS_REMOTE',
|
||||||
'CHICAGO_MCP',
|
'CHICAGO_MCP',
|
||||||
'VOICE_MODE',
|
'VOICE_MODE',
|
||||||
|
|||||||
57
package.json
57
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-code-best",
|
"name": "claude-code-best",
|
||||||
"version": "1.4.2",
|
"version": "1.4.4",
|
||||||
"description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal",
|
"description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "claude-code-best <claude-code-best@proton.me>",
|
"author": "claude-code-best <claude-code-best@proton.me>",
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
"scripts/postinstall.cjs",
|
"scripts/postinstall.cjs",
|
||||||
|
"scripts/run-parallel.mjs",
|
||||||
"scripts/setup-chrome-mcp.mjs"
|
"scripts/setup-chrome-mcp.mjs"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -72,20 +73,20 @@
|
|||||||
"@ant/computer-use-mcp": "workspace:*",
|
"@ant/computer-use-mcp": "workspace:*",
|
||||||
"@ant/computer-use-swift": "workspace:*",
|
"@ant/computer-use-swift": "workspace:*",
|
||||||
"@anthropic-ai/bedrock-sdk": "^0.26.4",
|
"@anthropic-ai/bedrock-sdk": "^0.26.4",
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.87",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.114",
|
||||||
"@anthropic-ai/foundry-sdk": "^0.2.3",
|
"@anthropic-ai/foundry-sdk": "^0.2.3",
|
||||||
"@anthropic-ai/mcpb": "^2.1.2",
|
"@anthropic-ai/mcpb": "^2.1.2",
|
||||||
"@anthropic-ai/sandbox-runtime": "^0.0.44",
|
"@anthropic-ai/sandbox-runtime": "^0.0.44",
|
||||||
"@anthropic-ai/sdk": "^0.80.0",
|
"@anthropic-ai/sdk": "^0.80.0",
|
||||||
"@anthropic-ai/vertex-sdk": "^0.14.4",
|
"@anthropic-ai/vertex-sdk": "^0.14.4",
|
||||||
"@anthropic/ink": "workspace:*",
|
"@anthropic/ink": "workspace:*",
|
||||||
"@aws-sdk/client-bedrock": "^3.1020.0",
|
"@aws-sdk/client-bedrock": "^3.1032.0",
|
||||||
"@aws-sdk/client-bedrock-runtime": "^3.1020.0",
|
"@aws-sdk/client-bedrock-runtime": "^3.1032.0",
|
||||||
"@aws-sdk/client-sts": "^3.1020.0",
|
"@aws-sdk/client-sts": "^3.1032.0",
|
||||||
"@aws-sdk/credential-provider-node": "^3.972.28",
|
"@aws-sdk/credential-provider-node": "^3.972.32",
|
||||||
"@aws-sdk/credential-providers": "^3.1020.0",
|
"@aws-sdk/credential-providers": "^3.1032.0",
|
||||||
"@azure/identity": "^4.13.1",
|
"@azure/identity": "^4.13.1",
|
||||||
"@biomejs/biome": "^2.4.10",
|
"@biomejs/biome": "^2.4.12",
|
||||||
"@claude-code-best/agent-tools": "workspace:*",
|
"@claude-code-best/agent-tools": "workspace:*",
|
||||||
"@claude-code-best/builtin-tools": "workspace:*",
|
"@claude-code-best/builtin-tools": "workspace:*",
|
||||||
"@claude-code-best/mcp-client": "workspace:*",
|
"@claude-code-best/mcp-client": "workspace:*",
|
||||||
@@ -96,7 +97,7 @@
|
|||||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||||
"@opentelemetry/api": "^1.9.1",
|
"@opentelemetry/api": "^1.9.1",
|
||||||
"@opentelemetry/api-logs": "^0.214.0",
|
"@opentelemetry/api-logs": "^0.214.0",
|
||||||
"@opentelemetry/core": "^2.6.1",
|
"@opentelemetry/core": "^2.7.0",
|
||||||
"@opentelemetry/exporter-logs-otlp-grpc": "^0.214.0",
|
"@opentelemetry/exporter-logs-otlp-grpc": "^0.214.0",
|
||||||
"@opentelemetry/exporter-logs-otlp-http": "^0.214.0",
|
"@opentelemetry/exporter-logs-otlp-http": "^0.214.0",
|
||||||
"@opentelemetry/exporter-logs-otlp-proto": "^0.214.0",
|
"@opentelemetry/exporter-logs-otlp-proto": "^0.214.0",
|
||||||
@@ -107,14 +108,14 @@
|
|||||||
"@opentelemetry/exporter-trace-otlp-grpc": "^0.214.0",
|
"@opentelemetry/exporter-trace-otlp-grpc": "^0.214.0",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.214.0",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.214.0",
|
||||||
"@opentelemetry/exporter-trace-otlp-proto": "^0.214.0",
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.214.0",
|
||||||
"@opentelemetry/resources": "^2.6.1",
|
"@opentelemetry/resources": "^2.7.0",
|
||||||
"@opentelemetry/sdk-logs": "^0.214.0",
|
"@opentelemetry/sdk-logs": "^0.214.0",
|
||||||
"@opentelemetry/sdk-metrics": "^2.6.1",
|
"@opentelemetry/sdk-metrics": "^2.7.0",
|
||||||
"@opentelemetry/sdk-trace-base": "^2.6.1",
|
"@opentelemetry/sdk-trace-base": "^2.7.0",
|
||||||
"@opentelemetry/semantic-conventions": "^1.40.0",
|
"@opentelemetry/semantic-conventions": "^1.40.0",
|
||||||
"@sentry/node": "^10.47.0",
|
"@sentry/node": "^10.49.0",
|
||||||
"@smithy/core": "^3.23.13",
|
"@smithy/core": "^3.23.15",
|
||||||
"@smithy/node-http-handler": "^4.5.1",
|
"@smithy/node-http-handler": "^4.5.3",
|
||||||
"@types/bun": "^1.3.12",
|
"@types/bun": "^1.3.12",
|
||||||
"@types/cacache": "^20.0.1",
|
"@types/cacache": "^20.0.1",
|
||||||
"@types/he": "^1.2.3",
|
"@types/he": "^1.2.3",
|
||||||
@@ -136,7 +137,7 @@
|
|||||||
"asciichart": "^1.5.25",
|
"asciichart": "^1.5.25",
|
||||||
"audio-capture-napi": "workspace:*",
|
"audio-capture-napi": "workspace:*",
|
||||||
"auto-bind": "^5.0.1",
|
"auto-bind": "^5.0.1",
|
||||||
"axios": "^1.14.0",
|
"axios": "^1.15.0",
|
||||||
"bidi-js": "^1.0.3",
|
"bidi-js": "^1.0.3",
|
||||||
"cacache": "^20.0.4",
|
"cacache": "^20.0.4",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
@@ -151,7 +152,7 @@
|
|||||||
"execa": "^9.6.1",
|
"execa": "^9.6.1",
|
||||||
"fflate": "^0.8.2",
|
"fflate": "^0.8.2",
|
||||||
"figures": "^6.1.0",
|
"figures": "^6.1.0",
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.3.0",
|
||||||
"get-east-asian-width": "^1.5.0",
|
"get-east-asian-width": "^1.5.0",
|
||||||
"google-auth-library": "^10.6.2",
|
"google-auth-library": "^10.6.2",
|
||||||
"he": "^1.2.0",
|
"he": "^1.2.0",
|
||||||
@@ -161,21 +162,21 @@
|
|||||||
"image-processor-napi": "workspace:*",
|
"image-processor-napi": "workspace:*",
|
||||||
"indent-string": "^5.0.0",
|
"indent-string": "^5.0.0",
|
||||||
"jsonc-parser": "^3.3.1",
|
"jsonc-parser": "^3.3.1",
|
||||||
"knip": "^6.1.1",
|
"knip": "^6.4.1",
|
||||||
"lodash-es": "^4.17.23",
|
"lodash-es": "^4.18.1",
|
||||||
"lru-cache": "^11.2.7",
|
"lru-cache": "^11.3.5",
|
||||||
"marked": "^17.0.5",
|
"marked": "^17.0.6",
|
||||||
"modifiers-napi": "workspace:*",
|
"modifiers-napi": "workspace:*",
|
||||||
"openai": "^6.33.0",
|
"openai": "^6.34.0",
|
||||||
"p-map": "^7.0.4",
|
"p-map": "^7.0.4",
|
||||||
"picomatch": "^4.0.4",
|
"picomatch": "^4.0.4",
|
||||||
"plist": "^3.1.0",
|
"plist": "^3.1.0",
|
||||||
"proper-lockfile": "^4.1.2",
|
"proper-lockfile": "^4.1.2",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.5",
|
||||||
"react-compiler-runtime": "^1.0.0",
|
"react-compiler-runtime": "^1.0.0",
|
||||||
"react-reconciler": "^0.33.0",
|
"react-reconciler": "^0.33.0",
|
||||||
"rollup": "^4.60.1",
|
"rollup": "^4.60.2",
|
||||||
"semver": "^7.7.4",
|
"semver": "^7.7.4",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"shell-quote": "^1.8.3",
|
"shell-quote": "^1.8.3",
|
||||||
@@ -184,10 +185,10 @@
|
|||||||
"strip-ansi": "^7.2.0",
|
"strip-ansi": "^7.2.0",
|
||||||
"supports-hyperlinks": "^4.4.0",
|
"supports-hyperlinks": "^4.4.0",
|
||||||
"tree-kill": "^1.2.2",
|
"tree-kill": "^1.2.2",
|
||||||
"turndown": "^7.2.2",
|
"turndown": "^7.2.4",
|
||||||
"type-fest": "^5.5.0",
|
"type-fest": "^5.6.0",
|
||||||
"typescript": "^6.0.2",
|
"typescript": "^6.0.3",
|
||||||
"undici": "^7.24.6",
|
"undici": "^7.25.0",
|
||||||
"url-handler-napi": "workspace:*",
|
"url-handler-napi": "workspace:*",
|
||||||
"usehooks-ts": "^3.1.1",
|
"usehooks-ts": "^3.1.1",
|
||||||
"vite": "^8.0.8",
|
"vite": "^8.0.8",
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ export const config = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export function getBaseUrl(): string {
|
export function getBaseUrl(): string {
|
||||||
if (config.baseUrl) return config.baseUrl;
|
const url = config.baseUrl || `http://localhost:${config.port}`;
|
||||||
return `http://localhost:${config.port}`;
|
return url.replace(/\/+$/, "");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,17 @@ const app = new Hono();
|
|||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
app.use("*", logger());
|
app.use("*", logger());
|
||||||
|
app.use("*", async (c, next) => {
|
||||||
|
// Normalize double slashes in path (e.g. //v1/environments/bridge → /v1/environments/bridge)
|
||||||
|
const path = new URL(c.req.url).pathname;
|
||||||
|
if (path.includes("//")) {
|
||||||
|
const normalized = path.replace(/\/+/g, "/");
|
||||||
|
const url = new URL(c.req.url);
|
||||||
|
url.pathname = normalized;
|
||||||
|
return app.fetch(new Request(url.toString(), c.req.raw));
|
||||||
|
}
|
||||||
|
await next();
|
||||||
|
});
|
||||||
app.use("/web/*", cors());
|
app.use("/web/*", cors());
|
||||||
|
|
||||||
// Health check
|
// Health check
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
ACP_RCS_URL=http://localhost:3000 ACP_RCS_TOKEN=test-my-key acp-link ccb-bun -- --acp
|
# ACP_RCS_URL=http://localhost:3000 ACP_RCS_TOKEN=test-my-key acp-link ccb-bun -- --acp
|
||||||
|
ACP_RCS_URL=https://remote-control.claude-code-best.win/ ACP_RCS_TOKEN=test-my-key acp-link ccb-bun -- --acp
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import type { SDKAssistantMessageError } from '../../../entrypoints/agentSdkType
|
|||||||
import type { SystemPrompt } from '../../../utils/systemPromptType.js'
|
import type { SystemPrompt } from '../../../utils/systemPromptType.js'
|
||||||
import type { ThinkingConfig } from '../../../utils/thinking.js'
|
import type { ThinkingConfig } from '../../../utils/thinking.js'
|
||||||
import type { Options } from '../claude.js'
|
import type { Options } from '../claude.js'
|
||||||
|
import { recordLLMObservation } from '../../../services/langfuse/tracing.js'
|
||||||
|
import { convertMessagesToLangfuse, convertOutputToLangfuse, convertToolsToLangfuse } from '../../../services/langfuse/convert.js'
|
||||||
import { streamGeminiGenerateContent } from './client.js'
|
import { streamGeminiGenerateContent } from './client.js'
|
||||||
import { anthropicMessagesToGemini, resolveGeminiModel, adaptGeminiStreamToAnthropic, anthropicToolsToGemini, anthropicToolChoiceToGemini, GEMINI_THOUGHT_SIGNATURE_FIELD } from '@ant/model-provider'
|
import { anthropicMessagesToGemini, resolveGeminiModel, adaptGeminiStreamToAnthropic, anthropicToolsToGemini, anthropicToolChoiceToGemini, GEMINI_THOUGHT_SIGNATURE_FIELD } from '@ant/model-provider'
|
||||||
|
|
||||||
@@ -100,6 +102,7 @@ export async function* queryModelGemini(
|
|||||||
|
|
||||||
const adaptedStream = adaptGeminiStreamToAnthropic(stream, geminiModel)
|
const adaptedStream = adaptGeminiStreamToAnthropic(stream, geminiModel)
|
||||||
const contentBlocks: Record<number, any> = {}
|
const contentBlocks: Record<number, any> = {}
|
||||||
|
const collectedMessages: AssistantMessage[] = []
|
||||||
let partialMessage: any = undefined
|
let partialMessage: any = undefined
|
||||||
let ttftMs = 0
|
let ttftMs = 0
|
||||||
const start = Date.now()
|
const start = Date.now()
|
||||||
@@ -160,6 +163,7 @@ export async function* queryModelGemini(
|
|||||||
uuid: randomUUID(),
|
uuid: randomUUID(),
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
}
|
}
|
||||||
|
collectedMessages.push(message)
|
||||||
yield message
|
yield message
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -174,6 +178,22 @@ export async function* queryModelGemini(
|
|||||||
...(event.type === 'message_start' ? { ttftMs } : undefined),
|
...(event.type === 'message_start' ? { ttftMs } : undefined),
|
||||||
} as StreamEvent
|
} as StreamEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record LLM observation in Langfuse (no-op if not configured)
|
||||||
|
recordLLMObservation(options.langfuseTrace ?? null, {
|
||||||
|
model: geminiModel,
|
||||||
|
provider: 'gemini',
|
||||||
|
input: convertMessagesToLangfuse(messagesForAPI, systemPrompt),
|
||||||
|
output: convertOutputToLangfuse(collectedMessages),
|
||||||
|
usage: {
|
||||||
|
input_tokens: 0,
|
||||||
|
output_tokens: 0,
|
||||||
|
},
|
||||||
|
startTime: new Date(start),
|
||||||
|
endTime: new Date(),
|
||||||
|
completionStartTime: ttftMs > 0 ? new Date(start + ttftMs) : undefined,
|
||||||
|
tools: convertToolsToLangfuse(toolSchemas as unknown[]),
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||||
logForDebugging(`[Gemini] Error: ${errorMessage}`, { level: 'error' })
|
logForDebugging(`[Gemini] Error: ${errorMessage}`, { level: 'error' })
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import { toolToAPISchema } from '../../../utils/api.js'
|
|||||||
import { logForDebugging } from '../../../utils/debug.js'
|
import { logForDebugging } from '../../../utils/debug.js'
|
||||||
import { addToTotalSessionCost } from '../../../cost-tracker.js'
|
import { addToTotalSessionCost } from '../../../cost-tracker.js'
|
||||||
import { calculateUSDCost } from '../../../utils/modelCost.js'
|
import { calculateUSDCost } from '../../../utils/modelCost.js'
|
||||||
|
import { recordLLMObservation } from '../../../services/langfuse/tracing.js'
|
||||||
|
import { convertMessagesToLangfuse, convertOutputToLangfuse, convertToolsToLangfuse } from '../../../services/langfuse/convert.js'
|
||||||
import type { Options } from '../claude.js'
|
import type { Options } from '../claude.js'
|
||||||
import { randomUUID } from 'crypto'
|
import { randomUUID } from 'crypto'
|
||||||
import {
|
import {
|
||||||
@@ -92,6 +94,7 @@ export async function* queryModelGrok(
|
|||||||
const adaptedStream = adaptOpenAIStreamToAnthropic(stream as AsyncIterable<ChatCompletionChunk>, grokModel)
|
const adaptedStream = adaptOpenAIStreamToAnthropic(stream as AsyncIterable<ChatCompletionChunk>, grokModel)
|
||||||
|
|
||||||
const contentBlocks: Record<number, any> = {}
|
const contentBlocks: Record<number, any> = {}
|
||||||
|
const collectedMessages: AssistantMessage[] = []
|
||||||
let partialMessage: any = undefined
|
let partialMessage: any = undefined
|
||||||
let usage = {
|
let usage = {
|
||||||
input_tokens: 0,
|
input_tokens: 0,
|
||||||
@@ -157,6 +160,7 @@ export async function* queryModelGrok(
|
|||||||
uuid: randomUUID(),
|
uuid: randomUUID(),
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
}
|
}
|
||||||
|
collectedMessages.push(m)
|
||||||
yield m
|
yield m
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -182,6 +186,24 @@ export async function* queryModelGrok(
|
|||||||
...(event.type === 'message_start' ? { ttftMs } : undefined),
|
...(event.type === 'message_start' ? { ttftMs } : undefined),
|
||||||
} as StreamEvent
|
} as StreamEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record LLM observation in Langfuse (no-op if not configured)
|
||||||
|
recordLLMObservation(options.langfuseTrace ?? null, {
|
||||||
|
model: grokModel,
|
||||||
|
provider: 'grok',
|
||||||
|
input: convertMessagesToLangfuse(messagesForAPI, systemPrompt),
|
||||||
|
output: convertOutputToLangfuse(collectedMessages),
|
||||||
|
usage: {
|
||||||
|
input_tokens: usage.input_tokens,
|
||||||
|
output_tokens: usage.output_tokens,
|
||||||
|
cache_creation_input_tokens: usage.cache_creation_input_tokens,
|
||||||
|
cache_read_input_tokens: usage.cache_read_input_tokens,
|
||||||
|
},
|
||||||
|
startTime: new Date(start),
|
||||||
|
endTime: new Date(),
|
||||||
|
completionStartTime: ttftMs > 0 ? new Date(start + ttftMs) : undefined,
|
||||||
|
tools: convertToolsToLangfuse(toolSchemas as unknown[]),
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||||
logForDebugging(`[Grok] Error: ${errorMessage}`, { level: 'error' })
|
logForDebugging(`[Grok] Error: ${errorMessage}`, { level: 'error' })
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import { logForDebugging } from '../../../utils/debug.js'
|
|||||||
import { addToTotalSessionCost } from '../../../cost-tracker.js'
|
import { addToTotalSessionCost } from '../../../cost-tracker.js'
|
||||||
import { calculateUSDCost } from '../../../utils/modelCost.js'
|
import { calculateUSDCost } from '../../../utils/modelCost.js'
|
||||||
import { isOpenAIThinkingEnabled, resolveOpenAIMaxTokens, buildOpenAIRequestBody } from './requestBody.js'
|
import { isOpenAIThinkingEnabled, resolveOpenAIMaxTokens, buildOpenAIRequestBody } from './requestBody.js'
|
||||||
|
import { recordLLMObservation } from '../../../services/langfuse/tracing.js'
|
||||||
|
import { convertMessagesToLangfuse, convertOutputToLangfuse, convertToolsToLangfuse } from '../../../services/langfuse/convert.js'
|
||||||
export { isOpenAIThinkingEnabled, resolveOpenAIMaxTokens, buildOpenAIRequestBody }
|
export { isOpenAIThinkingEnabled, resolveOpenAIMaxTokens, buildOpenAIRequestBody }
|
||||||
import { getModelMaxOutputTokens } from '../../../utils/context.js'
|
import { getModelMaxOutputTokens } from '../../../utils/context.js'
|
||||||
import type { Options } from '../claude.js'
|
import type { Options } from '../claude.js'
|
||||||
@@ -246,6 +248,7 @@ export async function* queryModelOpenAI(
|
|||||||
|
|
||||||
// Accumulate content blocks and usage, same as the Anthropic path in claude.ts
|
// Accumulate content blocks and usage, same as the Anthropic path in claude.ts
|
||||||
const contentBlocks: Record<number, any> = {}
|
const contentBlocks: Record<number, any> = {}
|
||||||
|
const collectedMessages: AssistantMessage[] = []
|
||||||
let partialMessage: any
|
let partialMessage: any
|
||||||
let stopReason: string | null = null
|
let stopReason: string | null = null
|
||||||
let usage = {
|
let usage = {
|
||||||
@@ -323,6 +326,9 @@ export async function* queryModelOpenAI(
|
|||||||
partialMessage, contentBlocks, tools, agentId: options.agentId,
|
partialMessage, contentBlocks, tools, agentId: options.agentId,
|
||||||
usage, stopReason, maxTokens,
|
usage, stopReason, maxTokens,
|
||||||
})) {
|
})) {
|
||||||
|
if (output.type === 'assistant') {
|
||||||
|
collectedMessages.push(output)
|
||||||
|
}
|
||||||
yield output
|
yield output
|
||||||
}
|
}
|
||||||
// Reset partialMessage so the post-loop safety fallback does not
|
// Reset partialMessage so the post-loop safety fallback does not
|
||||||
@@ -346,6 +352,24 @@ export async function* queryModelOpenAI(
|
|||||||
} as StreamEvent
|
} as StreamEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record LLM observation in Langfuse (no-op if not configured)
|
||||||
|
recordLLMObservation(options.langfuseTrace ?? null, {
|
||||||
|
model: openaiModel,
|
||||||
|
provider: 'openai',
|
||||||
|
input: convertMessagesToLangfuse(messagesForAPI, systemPrompt),
|
||||||
|
output: convertOutputToLangfuse(collectedMessages),
|
||||||
|
usage: {
|
||||||
|
input_tokens: usage.input_tokens,
|
||||||
|
output_tokens: usage.output_tokens,
|
||||||
|
cache_creation_input_tokens: usage.cache_creation_input_tokens,
|
||||||
|
cache_read_input_tokens: usage.cache_read_input_tokens,
|
||||||
|
},
|
||||||
|
startTime: new Date(start),
|
||||||
|
endTime: new Date(),
|
||||||
|
completionStartTime: ttftMs > 0 ? new Date(start + ttftMs) : undefined,
|
||||||
|
tools: convertToolsToLangfuse(toolSchemas as unknown[]),
|
||||||
|
})
|
||||||
|
|
||||||
// Safety: if stream ended without message_stop, assemble and yield whatever we have
|
// Safety: if stream ended without message_stop, assemble and yield whatever we have
|
||||||
if (partialMessage) {
|
if (partialMessage) {
|
||||||
for (const output of assembleFinalAssistantOutputs({
|
for (const output of assembleFinalAssistantOutputs({
|
||||||
|
|||||||
Reference in New Issue
Block a user