kanna-code 0.13.9 → 0.14.0

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.
@@ -1,6 +1,9 @@
1
1
  import { query } from "@anthropic-ai/claude-agent-sdk"
2
2
  import { CodexAppServerManager } from "./codex-app-server"
3
3
 
4
+ const LOG_PREFIX = "[kanna:title]"
5
+ const CLAUDE_STRUCTURED_TIMEOUT_MS = 5_000
6
+
4
7
  type JsonSchema = {
5
8
  type: "object"
6
9
  properties: Record<string, unknown>
@@ -61,14 +64,32 @@ async function runClaudeStructured(args: Omit<StructuredQuickResponseArgs<unknow
61
64
  })
62
65
 
63
66
  try {
64
- for await (const message of q) {
65
- if ("result" in message) {
66
- return (message as Record<string, unknown>).structured_output ?? null
67
- }
68
- }
67
+ const result = await Promise.race<unknown | null>([
68
+ (async () => {
69
+ for await (const message of q) {
70
+ if ("result" in message) {
71
+ return (message as Record<string, unknown>).structured_output ?? null
72
+ }
73
+ }
74
+ return null
75
+ })(),
76
+ new Promise<null>((_, reject) => {
77
+ setTimeout(() => {
78
+ reject(new Error(`Claude structured response timed out after ${CLAUDE_STRUCTURED_TIMEOUT_MS}ms`))
79
+ }, CLAUDE_STRUCTURED_TIMEOUT_MS)
80
+ }),
81
+ ])
82
+
83
+ return result
84
+ } catch (error) {
85
+ console.warn(`${LOG_PREFIX} claude structured query failed before fallback:`, error)
69
86
  return null
70
87
  } finally {
71
- q.close()
88
+ try {
89
+ q.close()
90
+ } catch {
91
+ // Ignore close failures on timed-out or failed quick responses.
92
+ }
72
93
  }
73
94
  }
74
95
 
@@ -104,20 +125,37 @@ export class QuickResponseAdapter {
104
125
  schema: args.schema,
105
126
  }
106
127
 
107
- const claudeResult = await this.tryProvider(args.parse, () => this.runClaudeStructured(request))
128
+ console.log(`${LOG_PREFIX} starting ${args.task} via claude`, { cwd: args.cwd })
129
+ const claudeResult = await this.tryProvider("claude", args.task, args.parse, () => this.runClaudeStructured(request))
108
130
  if (claudeResult !== null) return claudeResult
109
131
 
110
- return await this.tryProvider(args.parse, () => this.runCodexStructured(request))
132
+ console.warn(`${LOG_PREFIX} claude returned no usable result for ${args.task}, falling back to codex`)
133
+ return await this.tryProvider("codex", args.task, args.parse, () => this.runCodexStructured(request))
111
134
  }
112
135
 
113
136
  private async tryProvider<T>(
137
+ provider: "claude" | "codex",
138
+ task: string,
114
139
  parse: (value: unknown) => T | null,
115
140
  run: () => Promise<unknown | null>
116
141
  ): Promise<T | null> {
117
142
  try {
118
143
  const result = await run()
119
- return result === null ? null : parse(result)
120
- } catch {
144
+ if (result === null) {
145
+ console.warn(`${LOG_PREFIX} ${provider} returned no structured output for ${task}`)
146
+ return null
147
+ }
148
+
149
+ const parsed = parse(result)
150
+ if (parsed === null) {
151
+ console.warn(`${LOG_PREFIX} ${provider} returned unparseable structured output for ${task}`, { result })
152
+ return null
153
+ }
154
+
155
+ console.log(`${LOG_PREFIX} ${provider} produced structured output for ${task}`)
156
+ return parsed
157
+ } catch (error) {
158
+ console.warn(`${LOG_PREFIX} ${provider} failed during ${task}:`, error)
121
159
  return null
122
160
  }
123
161
  }