Stream model events to activity panel

This commit is contained in:
wuyang6
2026-05-11 21:24:32 +08:00
parent e89e35c6fd
commit 413a37b32c
2 changed files with 43 additions and 3 deletions
+27
View File
@@ -32,13 +32,16 @@ type ClawChatResponse = {
type ClawRuntimeEvent = {
type?: string;
run_id?: string;
tool_call_index?: number | null;
tool_name?: string;
tool_call_id?: string;
arguments?: unknown;
arguments_delta?: string;
assistant_content?: string;
metadata?: Record<string, unknown>;
ok?: boolean;
delta?: string;
finish_reason?: string | null;
elapsed_ms?: number;
};
@@ -52,6 +55,7 @@ type StreamState = {
textStreamed: boolean;
phase: "waiting" | "queued" | "running" | "done";
runId?: string;
announcedToolCallKeys: Set<string>;
};
type ChatRequestBody = {
@@ -107,6 +111,7 @@ export async function POST(req: Request) {
textStarted: false,
textStreamed: false,
phase: "waiting",
announcedToolCallKeys: new Set<string>(),
};
writer.write({ type: "start" });
writer.write({ type: "start-step" });
@@ -491,6 +496,28 @@ function writeRuntimeEvent(
delta: `\n${phase}${elapsed}`,
});
}
if (event.type === "content_delta" && event.delta) {
writer.write({
type: "reasoning-delta",
id: "reasoning-1",
delta: event.delta,
});
}
if (event.type === "tool_call_delta") {
const key =
event.tool_call_id ??
(event.tool_call_index === null || event.tool_call_index === undefined
? undefined
: `index:${event.tool_call_index}`);
if (key && !streamState?.announcedToolCallKeys.has(key)) {
streamState?.announcedToolCallKeys.add(key);
writer.write({
type: "reasoning-delta",
id: "reasoning-1",
delta: `\n准备调用 ${event.tool_name ?? "工具"}`,
});
}
}
if (event.type === "final_text_start") {
if (!streamState?.textStarted) {
writer.write({ type: "text-start", id: "text-1" });
+15 -2
View File
@@ -692,7 +692,11 @@ class LocalCodingAgent:
self.last_run_result = result
return result
try:
turn, turn_events = self._query_model(session, tool_specs)
turn, turn_events = self._query_model(
session,
tool_specs,
stream_events=stream_events,
)
except OpenAICompatError as exc:
if self._is_prompt_too_long_error(exc) and self._reactive_compact_session(
session,
@@ -700,7 +704,11 @@ class LocalCodingAgent:
turn_index=turn_index,
):
try:
turn, turn_events = self._query_model(session, tool_specs)
turn, turn_events = self._query_model(
session,
tool_specs,
stream_events=stream_events,
)
except OpenAICompatError as retry_exc:
exc = retry_exc
else:
@@ -1479,6 +1487,8 @@ class LocalCodingAgent:
self,
session: AgentSessionState,
tool_specs: list[dict[str, object]],
*,
stream_events: list[dict[str, object]] | None = None,
) -> tuple[AssistantTurn, tuple[StreamEvent, ...]]:
if not self.runtime_config.stream_model_responses:
turn = self.client.complete(
@@ -1520,7 +1530,10 @@ class LocalCodingAgent:
tool_specs,
output_schema=self.runtime_config.output_schema,
):
if stream_events is None:
events.append(event)
else:
stream_events.append(event.to_dict())
if event.type == 'content_delta':
session.append_assistant_delta(assistant_index, event.delta)
elif event.type == 'tool_call_delta':