codeblog-app 1.6.3 → 1.6.4
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 +1 -1
- package/src/ai/chat.ts +50 -78
package/package.json
CHANGED
package/src/ai/chat.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { streamText, type CoreMessage } from "ai"
|
|
1
|
+
import { streamText, type CoreMessage, type CoreToolMessage, type CoreAssistantMessage } from "ai"
|
|
2
2
|
import { AIProvider } from "./provider"
|
|
3
3
|
import { chatTools } from "./tools"
|
|
4
4
|
import { Log } from "../util/log"
|
|
@@ -35,92 +35,64 @@ export namespace AIChat {
|
|
|
35
35
|
onToolResult?: (name: string, result: unknown) => void
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// Convert our simple messages to CoreMessage[] for AI SDK
|
|
39
|
+
// Only user/assistant text messages — tool history is handled by maxSteps internally
|
|
40
|
+
function toCoreMessages(messages: Message[]): CoreMessage[] {
|
|
41
|
+
return messages
|
|
42
|
+
.filter((m) => m.role === "user" || m.role === "assistant")
|
|
43
|
+
.map((m) => ({ role: m.role as "user" | "assistant", content: m.content }))
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
export async function stream(messages: Message[], callbacks: StreamCallbacks, modelID?: string, signal?: AbortSignal) {
|
|
39
47
|
const model = await AIProvider.getModel(modelID)
|
|
40
48
|
log.info("streaming", { model: modelID || AIProvider.DEFAULT_MODEL, messages: messages.length })
|
|
41
49
|
|
|
42
|
-
const
|
|
50
|
+
const coreMessages = toCoreMessages(messages)
|
|
43
51
|
let full = ""
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
callbacks.onToolResult?.(name, output)
|
|
80
|
-
const match = calls.find((c) => c.name === name && c.output === undefined)
|
|
81
|
-
if (match) match.output = output
|
|
82
|
-
break
|
|
83
|
-
}
|
|
84
|
-
case "error": {
|
|
85
|
-
const msg = part.error instanceof Error ? part.error.message : String(part.error)
|
|
86
|
-
log.error("stream part error", { error: msg })
|
|
87
|
-
callbacks.onError?.(part.error instanceof Error ? part.error : new Error(msg))
|
|
88
|
-
break
|
|
89
|
-
}
|
|
53
|
+
const result = streamText({
|
|
54
|
+
model,
|
|
55
|
+
system: SYSTEM_PROMPT,
|
|
56
|
+
messages: coreMessages,
|
|
57
|
+
tools: chatTools,
|
|
58
|
+
maxSteps: 5,
|
|
59
|
+
abortSignal: signal,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
for await (const part of result.fullStream) {
|
|
64
|
+
if (signal?.aborted) break
|
|
65
|
+
switch (part.type) {
|
|
66
|
+
case "text-delta": {
|
|
67
|
+
const delta = (part as any).text ?? (part as any).textDelta ?? ""
|
|
68
|
+
if (delta) { full += delta; callbacks.onToken?.(delta) }
|
|
69
|
+
break
|
|
70
|
+
}
|
|
71
|
+
case "tool-call": {
|
|
72
|
+
const input = (part as any).input ?? (part as any).args
|
|
73
|
+
callbacks.onToolCall?.(part.toolName, input)
|
|
74
|
+
break
|
|
75
|
+
}
|
|
76
|
+
case "tool-result": {
|
|
77
|
+
const output = (part as any).output ?? (part as any).result ?? {}
|
|
78
|
+
const name = (part as any).toolName
|
|
79
|
+
callbacks.onToolResult?.(name, output)
|
|
80
|
+
break
|
|
81
|
+
}
|
|
82
|
+
case "error": {
|
|
83
|
+
const msg = part.error instanceof Error ? part.error.message : String(part.error)
|
|
84
|
+
log.error("stream part error", { error: msg })
|
|
85
|
+
callbacks.onError?.(part.error instanceof Error ? part.error : new Error(msg))
|
|
86
|
+
break
|
|
90
87
|
}
|
|
91
88
|
}
|
|
92
|
-
} catch (err) {
|
|
93
|
-
const error = err instanceof Error ? err : new Error(String(err))
|
|
94
|
-
log.error("stream error", { error: error.message })
|
|
95
|
-
if (callbacks.onError) callbacks.onError(error)
|
|
96
|
-
else throw error
|
|
97
|
-
return full
|
|
98
89
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
role: "assistant",
|
|
106
|
-
content: calls.map((c) => ({
|
|
107
|
-
type: "tool-call" as const,
|
|
108
|
-
toolCallId: c.id,
|
|
109
|
-
toolName: c.name,
|
|
110
|
-
input: c.input ?? {},
|
|
111
|
-
})),
|
|
112
|
-
} as any)
|
|
113
|
-
history.push({
|
|
114
|
-
role: "tool",
|
|
115
|
-
content: calls.map((c) => ({
|
|
116
|
-
type: "tool-result" as const,
|
|
117
|
-
toolCallId: c.id,
|
|
118
|
-
toolName: c.name,
|
|
119
|
-
output: { type: "json", value: c.output ?? {} },
|
|
120
|
-
})),
|
|
121
|
-
} as any)
|
|
122
|
-
|
|
123
|
-
log.info("tool round done, sending follow-up", { step, tools: calls.map((c) => c.name) })
|
|
90
|
+
} catch (err) {
|
|
91
|
+
const error = err instanceof Error ? err : new Error(String(err))
|
|
92
|
+
log.error("stream error", { error: error.message })
|
|
93
|
+
if (callbacks.onError) callbacks.onError(error)
|
|
94
|
+
else throw error
|
|
95
|
+
return full
|
|
124
96
|
}
|
|
125
97
|
|
|
126
98
|
callbacks.onFinish?.(full || "(No response)")
|