@shareai-lab/kode 1.0.81 → 1.0.83

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.
package/README.md CHANGED
@@ -1,11 +1,30 @@
1
1
  # Kode - AI Assistant for Your Terminal
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/@shareai-lab%2Fkode.svg)](https://www.npmjs.com/package/@shareai-lab/kode)
4
- [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
4
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
5
  [![AGENTS.md](https://img.shields.io/badge/AGENTS.md-Compatible-brightgreen)](https://agents.md)
6
6
 
7
7
  [中文文档](README.zh-CN.md) | [Contributing](CONTRIBUTING.md) | [Documentation](docs/)
8
8
 
9
+ ## 🎉 Big Announcement: We're Now Apache 2.0 Licensed!
10
+
11
+ **Great news for the developer community!** In our commitment to democratizing AI agent technology and fostering a vibrant ecosystem of innovation, we're thrilled to announce that Kode has transitioned from AGPLv3 to the **Apache 2.0 license**.
12
+
13
+ ### What This Means for You:
14
+ - ✅ **Complete Freedom**: Use Kode in any project - personal, commercial, or enterprise
15
+ - ✅ **Build Without Barriers**: Create proprietary solutions without open-sourcing requirements
16
+ - ✅ **Simple Attribution**: Just maintain copyright notices and license info
17
+ - ✅ **Join a Movement**: Be part of accelerating the world's transition to AI-powered development
18
+
19
+ This change reflects our belief that the future of software development is collaborative, open, and augmented by AI. By removing licensing barriers, we're empowering developers worldwide to build the next generation of AI-assisted tools and workflows. Let's build the future together! 🚀
20
+
21
+ ## 📢 Update Log
22
+
23
+ **2025-08-29**: We've added Windows support! All Windows users can now run Kode using Git Bash, Unix subsystems, or WSL (Windows Subsystem for Linux) on their computers.
24
+
25
+
26
+ <img width="606" height="303" alt="image" src="https://github.com/user-attachments/assets/6cf50553-aacd-4241-a579-6e935b6c62b5" />
27
+
9
28
  ## 🤝 AGENTS.md Standard Support
10
29
 
11
30
  **Kode proudly supports the [AGENTS.md standard protocol](https://agents.md) initiated by OpenAI** - a simple, open format for guiding programming agents that's used by 20k+ open source projects.
@@ -27,6 +46,8 @@ Kode is a powerful AI assistant that lives in your terminal. It can understand y
27
46
  >
28
47
  > **📊 Model Performance**: For optimal performance, we recommend using newer, more capable models designed for autonomous task completion. Avoid older Q&A-focused models like GPT-4o or Gemini 2.5 Pro, which are optimized for answering questions rather than sustained independent task execution. Choose models specifically trained for agentic workflows and extended reasoning capabilities.
29
48
 
49
+ <img width="600" height="577" alt="image" src="https://github.com/user-attachments/assets/8b46a39d-1ab6-4669-9391-14ccc6c5234c" />
50
+
30
51
  ## Features
31
52
 
32
53
  ### Core Capabilities
@@ -390,7 +411,7 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
390
411
 
391
412
  ## License
392
413
 
393
- ISC License - see [LICENSE](LICENSE) for details.
414
+ Apache 2.0 License - see [LICENSE](LICENSE) for details.
394
415
 
395
416
  ## Thanks
396
417
 
package/README.zh-CN.md CHANGED
@@ -1,10 +1,26 @@
1
1
  # Kode - 终端 AI 助手
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/@shareai-lab%2Fkode.svg)](https://www.npmjs.com/package/@shareai-lab/kode)
4
- [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
4
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
5
 
6
6
  [English](README.md) | [贡献指南](CONTRIBUTING.md) | [文档](docs/)
7
7
 
8
+ ## 🎉 重磅消息:我们已切换至 Apache 2.0 开源协议!
9
+
10
+ **开发者社区的福音来了!** 为了推动 AI 智能体技术的民主化进程,构建充满活力的创新生态,我们激动地宣布:Kode 已正式从 AGPLv3 协议升级为 **Apache 2.0 开源协议**。
11
+
12
+ ### 这对您意味着什么:
13
+ - ✅ **完全自由**:在任何项目中使用 Kode - 无论是个人项目、商业产品还是企业方案
14
+ - ✅ **无障碍创新**:构建专有解决方案,无需开源您的代码
15
+ - ✅ **极简要求**:仅需保留版权声明和许可信息
16
+ - ✅ **共创未来**:与全球开发者一起,加速世界向 AI 驱动生产的转型
17
+
18
+ 让我们携手共建未来!🚀
19
+
20
+ ## 📢 更新日志
21
+
22
+ **2025-08-29**:我们添加了 Windows 电脑的运行支持!所有的 Windows 用户现在可以使用你电脑上的 Git Bash、Unix 子系统或 WSL(Windows Subsystem for Linux)来运行 Kode。
23
+
8
24
  Kode 是一个强大的 AI 助手,运行在你的终端中。它能理解你的代码库、编辑文件、运行命令,并为你处理整个开发工作流。
9
25
 
10
26
  > **⚠️ 安全提示**:Kode 默认以 YOLO 模式运行(等同于 Claude 的 `--dangerously-skip-permissions` 标志),跳过所有权限检查以获得最大生产力。YOLO 模式仅建议在安全可信的环境中处理非重要项目时使用。如果您正在处理重要文件或使用能力存疑的模型,我们强烈建议使用 `kode --safe` 启用权限检查和手动审批所有操作。
@@ -301,7 +317,7 @@ bun test
301
317
 
302
318
  ## 许可证
303
319
 
304
- ISC 许可证 - 详见 [LICENSE](LICENSE)。
320
+ Apache 2.0 许可证 - 详见 [LICENSE](LICENSE)。
305
321
 
306
322
  ## 支持
307
323
 
package/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  const { spawn } = require('child_process');
4
4
  const path = require('path');
5
5
 
6
- // Prefer bun if available, otherwise use node with loader
6
+ // Prefer bun if available, otherwise use node with tsx (ESM --import, fallback to --loader)
7
7
  const args = process.argv.slice(2);
8
8
  const cliPath = path.join(__dirname, 'src', 'entrypoints', 'cli.tsx');
9
9
 
@@ -32,26 +32,55 @@ try {
32
32
  }
33
33
 
34
34
  function runWithNode() {
35
- // Use local tsx installation
36
- const tsxPath = path.join(__dirname, 'node_modules', '.bin', 'tsx');
37
- const child = spawn(tsxPath, [cliPath, ...args], {
38
- stdio: 'inherit',
39
- env: {
40
- ...process.env,
41
- YOGA_WASM_PATH: path.join(__dirname, 'yoga.wasm')
42
- }
43
- });
44
-
45
- child.on('error', (err) => {
46
- if (err.code === 'ENOENT') {
47
- console.error('\nError: tsx is required but not found.');
48
- console.error('Please run: npm install');
49
- process.exit(1);
50
- } else {
51
- console.error('Failed to start Kode:', err.message);
52
- process.exit(1);
53
- }
54
- });
55
-
56
- child.on('exit', (code) => process.exit(code || 0));
35
+ const nodeVersion = process.versions.node.split('.').map(Number)
36
+ const [major, minor] = nodeVersion
37
+ const supportsImport = major > 20 || (major === 20 && minor >= 6) || major >= 21
38
+
39
+ const baseArgs = ['--no-warnings=ExperimentalWarning', '--enable-source-maps']
40
+
41
+ const tryWithLoader = () => {
42
+ const child = spawn(process.execPath, [...baseArgs, '--loader', 'tsx', cliPath, ...args], {
43
+ stdio: 'inherit',
44
+ env: { ...process.env, YOGA_WASM_PATH: path.join(__dirname, 'yoga.wasm') },
45
+ })
46
+ child.on('error', () => tryWithTsxBinary())
47
+ child.on('exit', code => {
48
+ if (code && code !== 0) return tryWithTsxBinary()
49
+ process.exit(code || 0)
50
+ })
51
+ }
52
+
53
+ const tryWithTsxBinary = () => {
54
+ const tsxPath = path.join(__dirname, 'node_modules', '.bin', 'tsx')
55
+ const child = spawn(tsxPath, [cliPath, ...args], {
56
+ stdio: 'inherit',
57
+ env: { ...process.env, YOGA_WASM_PATH: path.join(__dirname, 'yoga.wasm') },
58
+ })
59
+ child.on('error', err => {
60
+ if (err.code === 'ENOENT') {
61
+ console.error('
62
+ Error: tsx is required but not found.')
63
+ console.error('Please run: npm install')
64
+ process.exit(1)
65
+ } else {
66
+ console.error('Failed to start Kode:', err.message)
67
+ process.exit(1)
68
+ }
69
+ })
70
+ child.on('exit', code => process.exit(code || 0))
71
+ }
72
+
73
+ if (supportsImport) {
74
+ const child = spawn(process.execPath, [...baseArgs, '--import', 'tsx', cliPath, ...args], {
75
+ stdio: 'inherit',
76
+ env: { ...process.env, YOGA_WASM_PATH: path.join(__dirname, 'yoga.wasm') },
77
+ })
78
+ child.on('error', () => tryWithLoader())
79
+ child.on('exit', code => {
80
+ if (code && code !== 0) return tryWithLoader()
81
+ process.exit(code || 0)
82
+ })
83
+ } else {
84
+ tryWithLoader()
85
+ }
57
86
  }
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@shareai-lab/kode",
3
- "version": "1.0.81",
3
+ "version": "1.0.83",
4
4
  "bin": {
5
5
  "kode": "cli.js",
6
6
  "kwa": "cli.js",
7
7
  "kd": "cli.js"
8
8
  },
9
9
  "engines": {
10
- "node": ">=18.0.0"
10
+ "node": ">=20.18.1"
11
11
  },
12
12
  "main": "cli.js",
13
13
  "author": "ShareAI-lab <ai-lab@foxmail.com>",
14
- "license": "ISC",
14
+ "license": "Apache-2.0",
15
15
  "description": "AI-powered terminal assistant that understands your codebase, edits files, runs commands, and automates development workflows.",
16
16
  "homepage": "https://github.com/shareAI-lab/kode",
17
17
  "repository": {
@@ -76,12 +76,15 @@
76
76
  "lru-cache": "^11.1.0",
77
77
  "marked": "^15.0.12",
78
78
  "nanoid": "^5.1.5",
79
+ "node-fetch": "^3.3.2",
80
+ "node-html-parser": "^7.0.1",
79
81
  "openai": "^4.104.0",
80
82
  "react": "18.3.1",
81
83
  "semver": "^7.7.2",
82
84
  "shell-quote": "^1.8.3",
83
85
  "spawn-rx": "^5.1.2",
84
86
  "tsx": "^4.20.3",
87
+ "turndown": "^7.2.1",
85
88
  "undici": "^7.11.0",
86
89
  "wrap-ansi": "^9.0.0",
87
90
  "zod": "^3.25.76",
@@ -113,4 +116,4 @@
113
116
  "terminal",
114
117
  "command-line"
115
118
  ]
116
- }
119
+ }
@@ -480,6 +480,7 @@ export function ModelSelector({
480
480
  'x-api-key': apiKey,
481
481
  'anthropic-version': '2023-06-01',
482
482
  'Content-Type': 'application/json',
483
+ 'Authorization': `Bearer ${apiKey}`
483
484
  },
484
485
  })
485
486
 
@@ -1846,7 +1847,7 @@ export function ModelSelector({
1846
1847
  }
1847
1848
 
1848
1849
  // Use the verifyApiKey function which uses the official Anthropic SDK
1849
- const isValid = await verifyApiKey(apiKey, testBaseURL)
1850
+ const isValid = await verifyApiKey(apiKey, testBaseURL, selectedProvider)
1850
1851
 
1851
1852
  if (isValid) {
1852
1853
  return {
package/src/query.ts CHANGED
@@ -206,10 +206,10 @@ export async function* query(
206
206
  typeof lastUserMessage.message.content === 'string'
207
207
  ? reminders + lastUserMessage.message.content
208
208
  : [
209
- { type: 'text', text: reminders },
210
209
  ...(Array.isArray(lastUserMessage.message.content)
211
210
  ? lastUserMessage.message.content
212
211
  : []),
212
+ { type: 'text', text: reminders },
213
213
  ],
214
214
  },
215
215
  }
@@ -567,8 +567,16 @@ async function* checkPermissionsAndCallTool(
567
567
  // (surprisingly, the model is not great at generating valid input)
568
568
  const isValidInput = tool.inputSchema.safeParse(input)
569
569
  if (!isValidInput.success) {
570
+ // Create a more helpful error message for common cases
571
+ let errorMessage = `InputValidationError: ${isValidInput.error.message}`
572
+
573
+ // Special handling for the "View" tool (FileReadTool) being called with empty parameters
574
+ if (tool.name === 'View' && Object.keys(input).length === 0) {
575
+ errorMessage = `Error: The View tool requires a 'file_path' parameter to specify which file to read. Please provide the absolute path to the file you want to view. For example: {"file_path": "/path/to/file.txt"}`
576
+ }
577
+
570
578
  logEvent('tengu_tool_use_error', {
571
- error: `InputValidationError: ${isValidInput.error.message}`,
579
+ error: errorMessage,
572
580
  messageID: assistantMessage.message.id,
573
581
  toolName: tool.name,
574
582
  toolInput: JSON.stringify(input).slice(0, 200),
@@ -576,7 +584,7 @@ async function* checkPermissionsAndCallTool(
576
584
  yield createUserMessage([
577
585
  {
578
586
  type: 'tool_result',
579
- content: `InputValidationError: ${isValidInput.error.message}`,
587
+ content: errorMessage,
580
588
  is_error: true,
581
589
  tool_use_id: toolUseID,
582
590
  },
@@ -962,6 +962,84 @@ export function resetAnthropicClient(): void {
962
962
  * 4. Fallback region (us-east5)
963
963
  */
964
964
 
965
+ /**
966
+ * Manage cache control to ensure it doesn't exceed Claude's 4 cache block limit
967
+ * Priority:
968
+ * 1. System prompts (high priority)
969
+ * 2. Long documents or reference materials (high priority)
970
+ * 3. Reusable context (medium priority)
971
+ * 4. Short messages or one-time content (no caching)
972
+ */
973
+ function applyCacheControlWithLimits(
974
+ systemBlocks: TextBlockParam[],
975
+ messageParams: MessageParam[]
976
+ ): { systemBlocks: TextBlockParam[]; messageParams: MessageParam[] } {
977
+ if (!PROMPT_CACHING_ENABLED) {
978
+ return { systemBlocks, messageParams }
979
+ }
980
+
981
+ const maxCacheBlocks = 4
982
+ let usedCacheBlocks = 0
983
+
984
+ // 1. Prioritize adding cache to system prompts (highest priority)
985
+ const processedSystemBlocks = systemBlocks.map((block, index) => {
986
+ if (usedCacheBlocks < maxCacheBlocks && block.text.length > 1000) {
987
+ usedCacheBlocks++
988
+ return {
989
+ ...block,
990
+ cache_control: { type: 'ephemeral' as const }
991
+ }
992
+ }
993
+ const { cache_control, ...blockWithoutCache } = block
994
+ return blockWithoutCache
995
+ })
996
+
997
+ // 2. Add cache to message content based on priority
998
+ const processedMessageParams = messageParams.map((message, messageIndex) => {
999
+ if (Array.isArray(message.content)) {
1000
+ const processedContent = message.content.map((contentBlock, blockIndex) => {
1001
+ // Determine whether this content block should be cached
1002
+ const shouldCache =
1003
+ usedCacheBlocks < maxCacheBlocks &&
1004
+ contentBlock.type === 'text' &&
1005
+ typeof contentBlock.text === 'string' &&
1006
+ (
1007
+ // Long documents (over 2000 characters)
1008
+ contentBlock.text.length > 2000 ||
1009
+ // Last content block of the last message (may be important context)
1010
+ (messageIndex === messageParams.length - 1 &&
1011
+ blockIndex === message.content.length - 1 &&
1012
+ contentBlock.text.length > 500)
1013
+ )
1014
+
1015
+ if (shouldCache) {
1016
+ usedCacheBlocks++
1017
+ return {
1018
+ ...contentBlock,
1019
+ cache_control: { type: 'ephemeral' as const }
1020
+ }
1021
+ }
1022
+
1023
+ // Remove existing cache_control
1024
+ const { cache_control, ...blockWithoutCache } = contentBlock as any
1025
+ return blockWithoutCache
1026
+ })
1027
+
1028
+ return {
1029
+ ...message,
1030
+ content: processedContent
1031
+ }
1032
+ }
1033
+
1034
+ return message
1035
+ })
1036
+
1037
+ return {
1038
+ systemBlocks: processedSystemBlocks,
1039
+ messageParams: processedMessageParams
1040
+ }
1041
+ }
1042
+
965
1043
  export function userMessageToMessageParam(
966
1044
  message: UserMessage,
967
1045
  addCache = false,
@@ -974,23 +1052,13 @@ export function userMessageToMessageParam(
974
1052
  {
975
1053
  type: 'text',
976
1054
  text: message.message.content,
977
- ...(PROMPT_CACHING_ENABLED
978
- ? { cache_control: { type: 'ephemeral' } }
979
- : {}),
980
1055
  },
981
1056
  ],
982
1057
  }
983
1058
  } else {
984
1059
  return {
985
1060
  role: 'user',
986
- content: message.message.content.map((_, i) => ({
987
- ..._,
988
- ...(i === message.message.content.length - 1
989
- ? PROMPT_CACHING_ENABLED
990
- ? { cache_control: { type: 'ephemeral' } }
991
- : {}
992
- : {}),
993
- })),
1061
+ content: message.message.content.map((_) => ({ ..._ })),
994
1062
  }
995
1063
  }
996
1064
  }
@@ -1012,25 +1080,13 @@ export function assistantMessageToMessageParam(
1012
1080
  {
1013
1081
  type: 'text',
1014
1082
  text: message.message.content,
1015
- ...(PROMPT_CACHING_ENABLED
1016
- ? { cache_control: { type: 'ephemeral' } }
1017
- : {}),
1018
1083
  },
1019
1084
  ],
1020
1085
  }
1021
1086
  } else {
1022
1087
  return {
1023
1088
  role: 'assistant',
1024
- content: message.message.content.map((_, i) => ({
1025
- ..._,
1026
- ...(i === message.message.content.length - 1 &&
1027
- _.type !== 'thinking' &&
1028
- _.type !== 'redacted_thinking'
1029
- ? PROMPT_CACHING_ENABLED
1030
- ? { cache_control: { type: 'ephemeral' } }
1031
- : {}
1032
- : {}),
1033
- })),
1089
+ content: message.message.content.map((_) => ({ ..._ })),
1034
1090
  }
1035
1091
  }
1036
1092
  }
@@ -1383,9 +1439,6 @@ async function queryAnthropicNative(
1383
1439
 
1384
1440
  const system: TextBlockParam[] = splitSysPromptPrefix(systemPrompt).map(
1385
1441
  _ => ({
1386
- ...(PROMPT_CACHING_ENABLED
1387
- ? { cache_control: { type: 'ephemeral' } }
1388
- : {}),
1389
1442
  text: _,
1390
1443
  type: 'text',
1391
1444
  }),
@@ -1404,6 +1457,10 @@ async function queryAnthropicNative(
1404
1457
  )
1405
1458
 
1406
1459
  const anthropicMessages = addCacheBreakpoints(messages)
1460
+
1461
+ // apply cache control
1462
+ const { systemBlocks: processedSystem, messageParams: processedMessages } =
1463
+ applyCacheControlWithLimits(system, anthropicMessages)
1407
1464
  const startIncludingRetries = Date.now()
1408
1465
 
1409
1466
  // 记录系统提示构建过程
@@ -1426,8 +1483,8 @@ async function queryAnthropicNative(
1426
1483
  const params: Anthropic.Beta.Messages.MessageCreateParams = {
1427
1484
  model,
1428
1485
  max_tokens: getMaxTokensFromProfile(modelProfile),
1429
- messages: anthropicMessages,
1430
- system,
1486
+ messages: processedMessages,
1487
+ system: processedSystem,
1431
1488
  tools: toolSchemas.length > 0 ? toolSchemas : undefined,
1432
1489
  tool_choice: toolSchemas.length > 0 ? { type: 'auto' } : undefined,
1433
1490
  }
@@ -1450,6 +1507,7 @@ async function queryAnthropicNative(
1450
1507
  : null,
1451
1508
  maxTokens: params.max_tokens,
1452
1509
  temperature: MAIN_QUERY_TEMPERATURE,
1510
+ params: params,
1453
1511
  messageCount: params.messages?.length || 0,
1454
1512
  streamMode: true,
1455
1513
  toolsCount: toolSchemas.length,
@@ -1471,6 +1529,7 @@ async function queryAnthropicNative(
1471
1529
  let finalResponse: any | null = null
1472
1530
  let messageStartEvent: any = null
1473
1531
  const contentBlocks: any[] = []
1532
+ const inputJSONBuffers = new Map<number, string>()
1474
1533
  let usage: any = null
1475
1534
  let stopReason: string | null = null
1476
1535
  let stopSequence: string | null = null
@@ -1484,30 +1543,81 @@ async function queryAnthropicNative(
1484
1543
  })
1485
1544
  throw new Error('Request was cancelled')
1486
1545
  }
1487
- if (event.type === 'message_start') {
1488
- messageStartEvent = event
1489
- finalResponse = {
1490
- ...event.message,
1491
- content: [], // Will be populated from content blocks
1492
- }
1493
- } else if (event.type === 'content_block_start') {
1494
- contentBlocks[event.index] = { ...event.content_block }
1495
- } else if (event.type === 'content_block_delta') {
1496
- if (!contentBlocks[event.index]) {
1497
- contentBlocks[event.index] = {
1498
- type: event.delta.type === 'text_delta' ? 'text' : 'unknown',
1499
- text: '',
1546
+
1547
+ switch (event.type) {
1548
+ case 'message_start':
1549
+ messageStartEvent = event
1550
+ finalResponse = {
1551
+ ...event.message,
1552
+ content: [], // Will be populated from content blocks
1500
1553
  }
1501
- }
1502
- if (event.delta.type === 'text_delta') {
1503
- contentBlocks[event.index].text += event.delta.text
1504
- }
1505
- } else if (event.type === 'message_delta') {
1506
- if (event.delta.stop_reason) stopReason = event.delta.stop_reason
1507
- if (event.delta.stop_sequence)
1508
- stopSequence = event.delta.stop_sequence
1509
- if (event.usage) usage = { ...usage, ...event.usage }
1510
- } else if (event.type === 'message_stop') {
1554
+ break
1555
+
1556
+ case 'content_block_start':
1557
+ contentBlocks[event.index] = { ...event.content_block }
1558
+ // Initialize JSON buffer for tool_use blocks
1559
+ if (event.content_block.type === 'tool_use') {
1560
+ inputJSONBuffers.set(event.index, '')
1561
+ }
1562
+ break
1563
+
1564
+ case 'content_block_delta':
1565
+ const blockIndex = event.index
1566
+
1567
+ // Ensure content block exists
1568
+ if (!contentBlocks[blockIndex]) {
1569
+ contentBlocks[blockIndex] = {
1570
+ type: event.delta.type === 'text_delta' ? 'text' : 'tool_use',
1571
+ text: event.delta.type === 'text_delta' ? '' : undefined,
1572
+ }
1573
+ if (event.delta.type === 'input_json_delta') {
1574
+ inputJSONBuffers.set(blockIndex, '')
1575
+ }
1576
+ }
1577
+
1578
+ if (event.delta.type === 'text_delta') {
1579
+ contentBlocks[blockIndex].text += event.delta.text
1580
+ } else if (event.delta.type === 'input_json_delta') {
1581
+ const currentBuffer = inputJSONBuffers.get(blockIndex) || ''
1582
+ inputJSONBuffers.set(blockIndex, currentBuffer + event.delta.partial_json)
1583
+ }
1584
+ break
1585
+
1586
+ case 'message_delta':
1587
+ if (event.delta.stop_reason) stopReason = event.delta.stop_reason
1588
+ if (event.delta.stop_sequence) stopSequence = event.delta.stop_sequence
1589
+ if (event.usage) usage = { ...usage, ...event.usage }
1590
+ break
1591
+
1592
+ case 'content_block_stop':
1593
+ const stopIndex = event.index
1594
+ const block = contentBlocks[stopIndex]
1595
+
1596
+ if (block?.type === 'tool_use' && inputJSONBuffers.has(stopIndex)) {
1597
+ const jsonStr = inputJSONBuffers.get(stopIndex)
1598
+ if (jsonStr) {
1599
+ try {
1600
+ block.input = JSON.parse(jsonStr)
1601
+ } catch (error) {
1602
+ debugLogger.error('JSON_PARSE_ERROR', {
1603
+ blockIndex: stopIndex,
1604
+ jsonStr,
1605
+ error: error instanceof Error ? error.message : String(error)
1606
+ })
1607
+ block.input = {}
1608
+ }
1609
+ inputJSONBuffers.delete(stopIndex)
1610
+ }
1611
+ }
1612
+ break
1613
+
1614
+ case 'message_stop':
1615
+ // Clear any remaining buffers
1616
+ inputJSONBuffers.clear()
1617
+ break
1618
+ }
1619
+
1620
+ if (event.type === 'message_stop') {
1511
1621
  break
1512
1622
  }
1513
1623
  }
@@ -1557,6 +1667,10 @@ async function queryAnthropicNative(
1557
1667
  }
1558
1668
  }, { signal })
1559
1669
 
1670
+ debugLogger.api('ANTHROPIC_API_CALL_SUCCESS', {
1671
+ content: response.content
1672
+ })
1673
+
1560
1674
  const ttftMs = start - Date.now()
1561
1675
  const durationMs = Date.now() - startIncludingRetries
1562
1676