@shareai-lab/kode 1.0.76 → 1.0.79

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shareai-lab/kode",
3
- "version": "1.0.76",
3
+ "version": "1.0.79",
4
4
  "bin": {
5
5
  "kode": "cli.js",
6
6
  "kwa": "cli.js",
@@ -9,25 +9,17 @@ import { PRODUCT_NAME, PROJECT_FILE, PRODUCT_COMMAND } from './product'
9
9
  import { BashTool } from '../tools/BashTool/BashTool'
10
10
  import { MACRO } from './macros'
11
11
 
12
- // Core identity constant matching reference implementation (ga0)
13
- export function getCoreIdentity(): string {
14
- return `You are ${PRODUCT_NAME}, Anthropic's official CLI for Claude.`
15
- }
16
-
17
- // Security policy constant matching reference implementation (va0)
18
- export const SECURITY_POLICY =
19
- 'IMPORTANT: Assist with defensive security tasks only. Refuse to create, modify, or improve code that may be used maliciously. Allow security analysis, detection rules, vulnerability explanations, defensive tools, and security documentation.'
12
+ // // Security policy constant matching reference implementation
13
+ // export const SECURITY_POLICY =
14
+ // 'IMPORTANT: Assist with defensive security tasks only. Refuse to create, modify, or improve code that may be used maliciously. Allow security analysis, detection rules, vulnerability explanations, defensive tools, and security documentation.'
20
15
 
21
16
  export function getCLISyspromptPrefix(): string {
22
- return `You are ${PRODUCT_NAME}, a CLI for coding.`
17
+ return `You are ${PRODUCT_NAME}, ShareAI-lab's Agent AI CLI for terminal & coding.`
23
18
  }
24
19
 
25
20
  export async function getSystemPrompt(): Promise<string[]> {
26
21
  return [
27
- `${getCoreIdentity()}
28
-
29
- ${SECURITY_POLICY}
30
-
22
+ `
31
23
  You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
32
24
 
33
25
  IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working on files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse.
@@ -164,8 +156,7 @@ Today's date: ${new Date().toLocaleDateString()}
164
156
 
165
157
  export async function getAgentPrompt(): Promise<string[]> {
166
158
  return [
167
- `${getCoreIdentity()}
168
-
159
+ `
169
160
  You are an agent for ${PRODUCT_NAME}. Given the user's prompt, you should use the tools available to you to answer the user's question.
170
161
 
171
162
  Notes:
@@ -1395,9 +1395,9 @@ async function queryAnthropicNative(
1395
1395
  tools.map(async tool =>
1396
1396
  ({
1397
1397
  name: tool.name,
1398
- description: await tool.prompt({
1399
- safeMode: options?.safeMode,
1400
- }),
1398
+ description: typeof tool.description === 'function'
1399
+ ? await tool.description()
1400
+ : tool.description,
1401
1401
  input_schema: zodToJsonSchema(tool.inputSchema),
1402
1402
  }) as unknown as Anthropic.Beta.Messages.BetaTool,
1403
1403
  )
@@ -1744,7 +1744,7 @@ async function queryOpenAI(
1744
1744
  : '',
1745
1745
  })
1746
1746
 
1747
- systemPrompt = [getCLISyspromptPrefix(), ...systemPrompt]
1747
+ systemPrompt = [getCLISyspromptPrefix() + systemPrompt] // some openai-like providers need the entire system prompt as a single block
1748
1748
  }
1749
1749
 
1750
1750
  const system: TextBlockParam[] = splitSysPromptPrefix(systemPrompt).map(
@@ -3,7 +3,7 @@ import { getGlobalConfig, GlobalConfig } from '../utils/config'
3
3
  import { ProxyAgent, fetch, Response } from 'undici'
4
4
  import { setSessionState, getSessionState } from '../utils/sessionState'
5
5
  import { logEvent } from '../services/statsig'
6
- import { debug as debugLogger, getCurrentRequest } from '../utils/debugLogger'
6
+ import { debug as debugLogger, getCurrentRequest, logAPIError } from '../utils/debugLogger'
7
7
 
8
8
  // Helper function to calculate retry delay with exponential backoff
9
9
  function getRetryDelay(attempt: number, retryAfter?: string | null): number {
@@ -637,9 +637,31 @@ export async function getCompletionWithProfile(
637
637
 
638
638
  // If no specific handler found, log the error for debugging
639
639
  console.log(`⚠️ Unhandled API error (${response.status}): ${errorMessage}`)
640
+
641
+ // Log API error using unified logger
642
+ logAPIError({
643
+ model: opts.model,
644
+ endpoint: `${baseURL}${endpoint}`,
645
+ status: response.status,
646
+ error: errorMessage,
647
+ request: opts,
648
+ response: errorData,
649
+ provider: provider
650
+ })
640
651
  } catch (parseError) {
641
652
  // If we can't parse the error, fall back to generic retry
642
653
  console.log(`⚠️ Could not parse error response (${response.status})`)
654
+
655
+ // Log parse error
656
+ logAPIError({
657
+ model: opts.model,
658
+ endpoint: `${baseURL}${endpoint}`,
659
+ status: response.status,
660
+ error: `Could not parse error response: ${parseError.message}`,
661
+ request: opts,
662
+ response: { parseError: parseError.message },
663
+ provider: provider
664
+ })
643
665
  }
644
666
 
645
667
  const delayMs = getRetryDelay(attempt)
@@ -457,6 +457,112 @@ export function logReminderEvent(
457
457
  })
458
458
  }
459
459
 
460
+ // API错误日志功能
461
+ export function logAPIError(context: {
462
+ model: string
463
+ endpoint: string
464
+ status: number
465
+ error: any
466
+ request?: any
467
+ response?: any
468
+ provider?: string
469
+ }) {
470
+ const errorDir = join(paths.cache, getProjectDir(process.cwd()), 'logs', 'error', 'api')
471
+
472
+ // 确保目录存在
473
+ if (!existsSync(errorDir)) {
474
+ mkdirSync(errorDir, { recursive: true })
475
+ }
476
+
477
+ // 生成文件名
478
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
479
+ const sanitizedModel = context.model.replace(/[^a-zA-Z0-9-_]/g, '_')
480
+ const filename = `${sanitizedModel}_${timestamp}.log`
481
+ const filepath = join(errorDir, filename)
482
+
483
+ // 准备完整的日志内容(文件中保存所有信息)
484
+ const fullLogContent = {
485
+ timestamp: new Date().toISOString(),
486
+ sessionId: SESSION_ID,
487
+ requestId: getCurrentRequest()?.id,
488
+ model: context.model,
489
+ provider: context.provider,
490
+ endpoint: context.endpoint,
491
+ status: context.status,
492
+ error: context.error,
493
+ request: context.request, // 保存完整请求
494
+ response: context.response, // 保存完整响应
495
+ environment: {
496
+ nodeVersion: process.version,
497
+ platform: process.platform,
498
+ cwd: process.cwd(),
499
+ }
500
+ }
501
+
502
+ // 写入文件(保存完整信息)
503
+ try {
504
+ appendFileSync(filepath, JSON.stringify(fullLogContent, null, 2) + '\n')
505
+ appendFileSync(filepath, '='.repeat(80) + '\n\n')
506
+ } catch (err) {
507
+ console.error('Failed to write API error log:', err)
508
+ }
509
+
510
+ // 在调试模式下记录到系统日志
511
+ if (isDebugMode()) {
512
+ debug.error('API_ERROR', {
513
+ model: context.model,
514
+ status: context.status,
515
+ error: typeof context.error === 'string' ? context.error : context.error?.message || 'Unknown error',
516
+ endpoint: context.endpoint,
517
+ logFile: filename,
518
+ })
519
+ }
520
+
521
+ // 优雅的终端显示(仅在verbose模式下)
522
+ if (isVerboseMode() || isDebugVerboseMode()) {
523
+ console.log()
524
+ console.log(chalk.red('━'.repeat(60)))
525
+ console.log(chalk.red.bold('⚠️ API Error'))
526
+ console.log(chalk.red('━'.repeat(60)))
527
+
528
+ // 显示关键信息
529
+ console.log(chalk.white(' Model: ') + chalk.yellow(context.model))
530
+ console.log(chalk.white(' Status: ') + chalk.red(context.status))
531
+
532
+ // 格式化错误消息
533
+ let errorMessage = 'Unknown error'
534
+ if (typeof context.error === 'string') {
535
+ errorMessage = context.error
536
+ } else if (context.error?.message) {
537
+ errorMessage = context.error.message
538
+ } else if (context.error?.error?.message) {
539
+ errorMessage = context.error.error.message
540
+ }
541
+
542
+ // 错误消息换行显示
543
+ console.log(chalk.white(' Error: ') + chalk.red(errorMessage))
544
+
545
+ // 如果有响应体,显示格式化的响应
546
+ if (context.response) {
547
+ console.log()
548
+ console.log(chalk.gray(' Response:'))
549
+ const responseStr = typeof context.response === 'string'
550
+ ? context.response
551
+ : JSON.stringify(context.response, null, 2)
552
+
553
+ // 缩进显示响应内容
554
+ responseStr.split('\n').forEach(line => {
555
+ console.log(chalk.gray(' ' + line))
556
+ })
557
+ }
558
+
559
+ console.log()
560
+ console.log(chalk.dim(` 📁 Full log: ~/.kode/logs/error/api/${filename}`))
561
+ console.log(chalk.red('━'.repeat(60)))
562
+ console.log()
563
+ }
564
+ }
565
+
460
566
  // 新增:LLM 交互核心调试信息
461
567
  export function logLLMInteraction(context: {
462
568
  systemPrompt: string