fix(runtime): deep audit fixes — clarification loop termination + callback alignment
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CRITICAL: - ask_clarification now terminates Agent Loop in both run() and run_streaming() paths, preventing the LLM from continuing after requesting user clarification HIGH: - SaaS relay now forwards plan_mode and subagent_enabled to backend - GatewayClient.chatStream now supports onThinkingDelta, onSubtaskStatus, and token-bearing onComplete — aligned with kernel-types StreamCallbacks - ZclawStreamEvent type extended with thinking_delta, subtask_status variants and input_tokens/output_tokens fields for token tracking via Gateway path
This commit is contained in:
@@ -175,9 +175,11 @@ export class GatewayClient {
|
||||
private deviceKeysPromise: Promise<DeviceKeys>;
|
||||
private streamCallbacks = new Map<string, {
|
||||
onDelta: (delta: string) => void;
|
||||
onThinkingDelta?: (delta: string) => void;
|
||||
onTool?: (tool: string, input: string, output: string) => void;
|
||||
onHand?: (name: string, status: string, result?: unknown) => void;
|
||||
onComplete: () => void;
|
||||
onSubtaskStatus?: (description: string, status: string, detail?: string) => void;
|
||||
onComplete: (inputTokens?: number, outputTokens?: number) => void;
|
||||
onError: (error: string) => void;
|
||||
}>();
|
||||
|
||||
@@ -465,9 +467,11 @@ export class GatewayClient {
|
||||
message: string,
|
||||
callbacks: {
|
||||
onDelta: (delta: string) => void;
|
||||
onThinkingDelta?: (delta: string) => void;
|
||||
onTool?: (tool: string, input: string, output: string) => void;
|
||||
onHand?: (name: string, status: string, result?: unknown) => void;
|
||||
onComplete: () => void;
|
||||
onSubtaskStatus?: (description: string, status: string, detail?: string) => void;
|
||||
onComplete: (inputTokens?: number, outputTokens?: number) => void;
|
||||
onError: (error: string) => void;
|
||||
},
|
||||
opts?: {
|
||||
@@ -638,10 +642,26 @@ export class GatewayClient {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'thinking_delta':
|
||||
// Extended thinking delta
|
||||
if (data.content && callbacks.onThinkingDelta) {
|
||||
callbacks.onThinkingDelta(data.content);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'subtask_status':
|
||||
// Sub-agent task status update
|
||||
if (callbacks.onSubtaskStatus && data.description) {
|
||||
callbacks.onSubtaskStatus(data.description, data.status || '', data.detail);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'phase':
|
||||
// Phase change: streaming | done
|
||||
if (data.phase === 'done') {
|
||||
callbacks.onComplete();
|
||||
const inputTokens = typeof data.input_tokens === 'number' ? data.input_tokens : undefined;
|
||||
const outputTokens = typeof data.output_tokens === 'number' ? data.output_tokens : undefined;
|
||||
callbacks.onComplete(inputTokens, outputTokens);
|
||||
this.streamCallbacks.delete(runId);
|
||||
if (this.zclawWs) {
|
||||
this.zclawWs.close(1000, 'Stream complete');
|
||||
@@ -657,7 +677,11 @@ export class GatewayClient {
|
||||
callbacks.onDelta(data.content);
|
||||
}
|
||||
// Mark complete if phase done wasn't sent
|
||||
callbacks.onComplete();
|
||||
{
|
||||
const inputTokens = typeof data.input_tokens === 'number' ? data.input_tokens : undefined;
|
||||
const outputTokens = typeof data.output_tokens === 'number' ? data.output_tokens : undefined;
|
||||
callbacks.onComplete(inputTokens, outputTokens);
|
||||
}
|
||||
this.streamCallbacks.delete(runId);
|
||||
if (this.zclawWs) {
|
||||
this.zclawWs.close(1000, 'Stream complete');
|
||||
|
||||
@@ -68,7 +68,7 @@ export interface AgentStreamDelta {
|
||||
|
||||
/** ZCLAW WebSocket stream event types */
|
||||
export interface ZclawStreamEvent {
|
||||
type: 'text_delta' | 'phase' | 'response' | 'typing' | 'tool_call' | 'tool_result' | 'hand' | 'workflow' | 'error' | 'connected' | 'agents_updated';
|
||||
type: 'text_delta' | 'thinking_delta' | 'subtask_status' | 'phase' | 'response' | 'typing' | 'tool_call' | 'tool_result' | 'hand' | 'workflow' | 'error' | 'connected' | 'agents_updated';
|
||||
content?: string;
|
||||
phase?: 'streaming' | 'done';
|
||||
state?: 'start' | 'stop';
|
||||
@@ -87,6 +87,13 @@ export interface ZclawStreamEvent {
|
||||
code?: string;
|
||||
agent_id?: string;
|
||||
agents?: Array<{ id: string; name: string; status: string }>;
|
||||
// Subtask status fields
|
||||
description?: string;
|
||||
status?: string;
|
||||
detail?: string;
|
||||
// Token tracking fields (present in phase=done and response events)
|
||||
input_tokens?: number;
|
||||
output_tokens?: number;
|
||||
}
|
||||
|
||||
// === Connection State ===
|
||||
|
||||
@@ -125,6 +125,8 @@ export function createSaaSRelayGatewayClient(
|
||||
if (opts?.agentId) body['agent_id'] = opts.agentId;
|
||||
if (opts?.thinking_enabled) body['thinking_enabled'] = true;
|
||||
if (opts?.reasoning_effort) body['reasoning_effort'] = opts.reasoning_effort;
|
||||
if (opts?.plan_mode) body['plan_mode'] = true;
|
||||
if (opts?.subagent_enabled) body['subagent_enabled'] = true;
|
||||
|
||||
const response = await saasClient.chatCompletion(body);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user