fix(openai): bound GPT-Live delegation output

This commit is contained in:
Vincent Koc
2026-07-31 00:50:04 +08:00
parent 1bca61b509
commit ef4cebb263
4 changed files with 23 additions and 7 deletions

View File

@@ -22,6 +22,7 @@ import {
type OpenAIQuicksilverSocketFactory,
} from "./realtime-quicksilver-sideband.js";
import {
boundOpenAIQuicksilverDelegationResult,
buildOpenAIQuicksilverSessionUpdate,
buildOpenAIQuicksilverWebSocketUrl,
chunkOpenAIQuicksilverAppendText,
@@ -342,13 +343,13 @@ export class OpenAIQuicksilverVoiceBridge implements RealtimeVoiceBridge {
options?: RealtimeVoiceToolResultOptions,
): void {
const channel = options?.suppressResponse || options?.willContinue ? "commentary" : "speakable";
const type = this.activeDelegations.has(callId)
? "delegation.context.append"
: "session.context.append";
const isDelegation = this.activeDelegations.has(callId);
const type = isDelegation ? "delegation.context.append" : "session.context.append";
const text = toolResultText(result);
this.sendContext(
type,
type === "delegation.context.append" ? callId : undefined,
toolResultText(result),
isDelegation ? callId : undefined,
isDelegation ? boundOpenAIQuicksilverDelegationResult(text) : text,
channel,
);
if (!options?.willContinue) {

View File

@@ -26,6 +26,7 @@ import {
} from "./realtime-quicksilver-sideband.js";
import {
boundOpenAIQuicksilverContextItems,
boundOpenAIQuicksilverDelegationResult,
buildOpenAIQuicksilverSession,
chunkOpenAIQuicksilverAppendText,
createOpenAIQuicksilverCall,
@@ -479,7 +480,7 @@ export class OpenAIQuicksilverGatewayBridge implements RealtimeVoiceBridge {
if (params.signal.aborted) {
return;
}
text = result.text;
text = boundOpenAIQuicksilverDelegationResult(result.text);
} catch (error) {
// Host steering aborts the runner's registered chat signal, not this bridge-owned signal.
// Abort-shaped rejection is therefore the runner boundary's cancellation marker.

View File

@@ -30,6 +30,7 @@ import {
} from "./realtime-quicksilver-sideband.js";
import {
boundOpenAIQuicksilverContextItems,
boundOpenAIQuicksilverDelegationResult,
buildOpenAIQuicksilverSession,
chunkOpenAIQuicksilverAppendText,
createOpenAIQuicksilverCall,
@@ -295,7 +296,7 @@ export function createOpenAIQuicksilverBrowserSessionBroker(params: {
if (signal.aborted) {
return;
}
finalText = result.text;
finalText = boundOpenAIQuicksilverDelegationResult(result.text);
} catch (error) {
if (signal.aborted) {
return;

View File

@@ -5,10 +5,12 @@ import {
readResponseTextLimited,
resolveProviderRequestHeaders,
} from "openclaw/plugin-sdk/provider-http";
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
import { z } from "zod";
import { isOpenAIGptLiveModel } from "./realtime-quicksilver.js";
const OPENAI_QUICKSILVER_APPEND_MAX_BYTES = 500;
const OPENAI_QUICKSILVER_DELEGATION_RESULT_MAX_CHARS = 1_800;
const OPENAI_QUICKSILVER_CONTEXT_MAX_ENTRIES = 16;
const OPENAI_QUICKSILVER_CONTEXT_MAX_ITEM_CHARS = 800;
const OPENAI_QUICKSILVER_CONTEXT_MAX_UTF8_BYTES = 8_000;
@@ -609,3 +611,14 @@ export function chunkOpenAIQuicksilverAppendText(text: string): string[] {
}
return chunks;
}
/** Bound completed delegation output while preserving under-limit text byte-for-byte. */
export function boundOpenAIQuicksilverDelegationResult(text: string): string {
if (text.length <= OPENAI_QUICKSILVER_DELEGATION_RESULT_MAX_CHARS) {
return text;
}
return `${truncateUtf16Safe(
text,
OPENAI_QUICKSILVER_DELEGATION_RESULT_MAX_CHARS - 16,
).trimEnd()} [truncated]`;
}