mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
fix: honor configured default agent in consults (#111749)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
// Google Meet composes platform strategies with the shared meeting session runtime.
|
||||
import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
@@ -94,10 +95,6 @@ function resolveMode(input: GoogleMeetModeInput | undefined, config: GoogleMeetC
|
||||
return input === "realtime" ? "agent" : (input ?? config.defaultMode);
|
||||
}
|
||||
|
||||
function resolveSessionAgentId(request: GoogleMeetJoinRequest, config: GoogleMeetConfig): string {
|
||||
return normalizeAgentId(request.agentId ?? config.realtime.agentId);
|
||||
}
|
||||
|
||||
function withSessionAgentConfig(config: GoogleMeetConfig, agentId: string): GoogleMeetConfig {
|
||||
return config.realtime.agentId === agentId
|
||||
? config
|
||||
@@ -118,6 +115,7 @@ function noteSession(session: GoogleMeetSession, note: string): void {
|
||||
|
||||
export class GoogleMeetRuntime {
|
||||
readonly #createdBrowserTabs = new Map<string, string>();
|
||||
readonly #agentId: string;
|
||||
readonly #voiceCallGateway: VoiceCallGateway;
|
||||
readonly #sessions: GoogleMeetSessionRuntime;
|
||||
|
||||
@@ -129,6 +127,7 @@ export class GoogleMeetRuntime {
|
||||
logger: RuntimeLogger;
|
||||
},
|
||||
) {
|
||||
this.#agentId = resolveDefaultAgentId(params.fullConfig);
|
||||
this.#voiceCallGateway = createVoiceCallGateway(params);
|
||||
this.#sessions = new MeetingSessionRuntime({
|
||||
logger: params.logger,
|
||||
@@ -169,7 +168,9 @@ export class GoogleMeetRuntime {
|
||||
url: GOOGLE_MEET_PLATFORM_ADAPTER.urls.validateAndNormalize(request.url),
|
||||
transport: resolveTransport(request.transport, params.config),
|
||||
mode: resolveMode(request.mode, params.config),
|
||||
agentId: resolveSessionAgentId(request, params.config),
|
||||
agentId: normalizeAgentId(
|
||||
request.agentId ?? params.config.realtime.agentId ?? this.#agentId,
|
||||
),
|
||||
}),
|
||||
createSession: ({ request: _request, resolved, createdAt }) =>
|
||||
createGoogleMeetSession({ config: params.config, resolved, createdAt }),
|
||||
@@ -305,7 +306,8 @@ export class GoogleMeetRuntime {
|
||||
#probeContext(): GoogleMeetRuntimeProbeContext {
|
||||
return {
|
||||
config: this.params.config,
|
||||
resolveAgentId: (request) => resolveSessionAgentId(request, this.params.config),
|
||||
resolveAgentId: (request) =>
|
||||
normalizeAgentId(request.agentId ?? this.params.config.realtime.agentId ?? this.#agentId),
|
||||
list: () => this.list(),
|
||||
join: async (request) => await this.join(request),
|
||||
isReusable: (session, resolved) => this.#sessions.isReusableSession(session, resolved),
|
||||
|
||||
@@ -105,12 +105,13 @@ describe("Microsoft Teams meeting session flow", () => {
|
||||
defaultMode: "transcribe",
|
||||
chrome: { waitForInCallMs: 1 },
|
||||
}),
|
||||
fullConfig: {},
|
||||
fullConfig: { agents: { list: [{ id: "operator", default: true }] } },
|
||||
runtime: harness.runtime,
|
||||
logger,
|
||||
});
|
||||
|
||||
const first = await runtime.join({ url: URL, mode: "transcribe" });
|
||||
expect(first.session.agentId).toBe("operator");
|
||||
expect(first.session.chrome?.health).toMatchObject({ inCall: true, cameraOff: true });
|
||||
|
||||
const reused = await runtime.join({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
@@ -81,6 +82,7 @@ function noteSession(session: TeamsMeetingsSession, note: string): void {
|
||||
}
|
||||
|
||||
export class TeamsMeetingsRuntime {
|
||||
readonly #defaultAgentId: string;
|
||||
readonly #sessions: SessionRuntime;
|
||||
readonly #requesterSessionKeys = new Map<string, string>();
|
||||
|
||||
@@ -92,6 +94,9 @@ export class TeamsMeetingsRuntime {
|
||||
logger: RuntimeLogger;
|
||||
},
|
||||
) {
|
||||
this.#defaultAgentId = normalizeAgentId(
|
||||
params.config.realtime.agentId ?? resolveDefaultAgentId(params.fullConfig),
|
||||
);
|
||||
this.#sessions = new MeetingSessionRuntime({
|
||||
logger: params.logger,
|
||||
logScope: TEAMS_MEETINGS_PLATFORM_ADAPTER.logScope,
|
||||
@@ -131,7 +136,7 @@ export class TeamsMeetingsRuntime {
|
||||
url: TEAMS_MEETINGS_PLATFORM_ADAPTER.urls.validateAndNormalize(request.url),
|
||||
transport: resolveTransport(request, params.config),
|
||||
mode: request.mode ?? params.config.defaultMode,
|
||||
agentId: normalizeAgentId(request.agentId ?? params.config.realtime.agentId),
|
||||
agentId: normalizeAgentId(request.agentId ?? this.#defaultAgentId),
|
||||
}),
|
||||
createSession: ({ request, resolved, createdAt }) => {
|
||||
const session = createTeamsMeetingsSession({ config: params.config, resolved, createdAt });
|
||||
@@ -257,8 +262,7 @@ export class TeamsMeetingsRuntime {
|
||||
#probeContext(): TeamsMeetingsProbeContext {
|
||||
return {
|
||||
config: this.params.config,
|
||||
resolveAgentId: (request) =>
|
||||
normalizeAgentId(request.agentId ?? this.params.config.realtime.agentId),
|
||||
resolveAgentId: (request) => normalizeAgentId(request.agentId ?? this.#defaultAgentId),
|
||||
list: () => this.list(),
|
||||
join: async (request) => await this.join(request),
|
||||
isReusable: (session, resolved) => this.#sessions.isReusableSession(session, resolved),
|
||||
|
||||
@@ -183,13 +183,14 @@ describe("voice-call outbound helpers", () => {
|
||||
expect(persistCallRecordMock).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("assigns per-call session keys to outbound calls when configured", async () => {
|
||||
it("persists the configured agent on outbound call records", async () => {
|
||||
const initiateProviderCall = vi.fn(async () => ({ providerCallId: "provider-1" }));
|
||||
const ctx = {
|
||||
activeCalls: new Map(),
|
||||
providerCallIdMap: new Map(),
|
||||
provider: { name: "twilio", initiateCall: initiateProviderCall },
|
||||
config: {
|
||||
agentId: "operator",
|
||||
maxConcurrentCalls: 3,
|
||||
outbound: { defaultMode: "conversation" },
|
||||
fromNumber: "+14155550100",
|
||||
@@ -205,9 +206,9 @@ describe("voice-call outbound helpers", () => {
|
||||
expect(result.callId).toBeTypeOf("string");
|
||||
expect(result.callId).not.toBe("");
|
||||
expect(ctx.activeCalls.get(result.callId)?.sessionKey).toBe(
|
||||
`agent:main:voice:call:${result.callId}`,
|
||||
`agent:operator:voice:call:${result.callId}`,
|
||||
);
|
||||
expect(ctx.activeCalls.get(result.callId)?.agentId).toBe("main");
|
||||
expect(ctx.activeCalls.get(result.callId)?.agentId).toBe("operator");
|
||||
});
|
||||
|
||||
it("uses the per-call agent for explicit session normalization", async () => {
|
||||
|
||||
@@ -81,6 +81,7 @@ describe("buildRealtimeVoiceInstructions", () => {
|
||||
}),
|
||||
coreConfig,
|
||||
agentRuntime: createAgentRuntime(workspaceDir),
|
||||
agentId: "voice",
|
||||
});
|
||||
|
||||
expect(instructions).toContain("OpenClaw agent voice context:");
|
||||
@@ -114,6 +115,7 @@ describe("buildRealtimeVoiceInstructions", () => {
|
||||
config,
|
||||
coreConfig: { agents: { list: [{ id: agentId }] } } as OpenClawConfig,
|
||||
agentRuntime: createAgentRuntime("/unused"),
|
||||
agentId,
|
||||
});
|
||||
|
||||
expect(instructions).toBe(`Base voice instructions.\n\n${expectedContext}\n[truncated]`);
|
||||
|
||||
@@ -61,6 +61,7 @@ export async function buildRealtimeVoiceInstructions(params: {
|
||||
config: VoiceCallConfig;
|
||||
coreConfig: OpenClawConfig;
|
||||
agentRuntime: CoreAgentDeps;
|
||||
agentId: string;
|
||||
}): Promise<string> {
|
||||
const { config } = params;
|
||||
const sections: string[] = [params.baseInstructions];
|
||||
@@ -74,7 +75,7 @@ export async function buildRealtimeVoiceInstructions(params: {
|
||||
return sections.filter(Boolean).join("\n\n");
|
||||
}
|
||||
|
||||
const agentId = config.agentId ?? "main";
|
||||
const { agentId } = params;
|
||||
const capsule: string[] = [
|
||||
"OpenClaw agent voice context:",
|
||||
`- Agent id: ${agentId}`,
|
||||
|
||||
@@ -334,13 +334,13 @@ describe("createVoiceCallRuntime lifecycle", () => {
|
||||
files: ["SOUL.md"],
|
||||
};
|
||||
const fullConfig = {
|
||||
agents: { list: [{ id: "main" }, { id: "support" }] },
|
||||
agents: { list: [{ id: "operator", default: true }, { id: "support" }] },
|
||||
} as OpenClawConfig;
|
||||
const resolveAgentIdentity = vi.fn((_cfg: OpenClawConfig, agentId: string) => ({
|
||||
name: agentId === "support" ? "Support Voice" : "Main Voice",
|
||||
}));
|
||||
|
||||
await createVoiceCallRuntime({
|
||||
const runtime = await createVoiceCallRuntime({
|
||||
config,
|
||||
coreConfig: {} as CoreConfig,
|
||||
fullConfig,
|
||||
@@ -353,6 +353,16 @@ describe("createVoiceCallRuntime lifecycle", () => {
|
||||
if (typeof resolveInstructions !== "function") {
|
||||
throw new Error("expected per-call realtime instruction resolver");
|
||||
}
|
||||
expect(runtime.config.agentId).toBe("operator");
|
||||
const defaultInstructions = resolveInstructions({
|
||||
callId: "call-default",
|
||||
direction: "outbound",
|
||||
from: "+15550001111",
|
||||
to: "+15550002222",
|
||||
});
|
||||
expect(defaultInstructions).toContain("- Agent id: operator");
|
||||
expect(resolveAgentIdentity).toHaveBeenCalledWith(fullConfig, "operator");
|
||||
|
||||
const supportInstructions = resolveInstructions({
|
||||
callId: "call-support",
|
||||
agentId: "support",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Voice Call plugin module implements runtime behavior.
|
||||
import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
|
||||
@@ -252,7 +253,7 @@ function listRealtimeAgentIds(config: VoiceCallConfig, coreConfig: OpenClawConfi
|
||||
}
|
||||
|
||||
async function createRealtimeInstructionsResolver(params: {
|
||||
config: VoiceCallConfig;
|
||||
config: VoiceCallConfig & { agentId: string };
|
||||
coreConfig: OpenClawConfig;
|
||||
agentRuntime: CoreAgentDeps;
|
||||
}): Promise<(call: CallRecord) => string> {
|
||||
@@ -268,6 +269,7 @@ async function createRealtimeInstructionsResolver(params: {
|
||||
config: genericConfig,
|
||||
coreConfig: params.coreConfig,
|
||||
agentRuntime: params.agentRuntime,
|
||||
agentId: params.config.agentId,
|
||||
});
|
||||
const entries = await Promise.all(
|
||||
listRealtimeAgentIds(params.config, params.coreConfig).map(async (agentId) => {
|
||||
@@ -276,6 +278,7 @@ async function createRealtimeInstructionsResolver(params: {
|
||||
config: { ...params.config, agentId },
|
||||
coreConfig: params.coreConfig,
|
||||
agentRuntime: params.agentRuntime,
|
||||
agentId,
|
||||
});
|
||||
return [agentId, instructions] as const;
|
||||
}),
|
||||
@@ -315,8 +318,12 @@ export async function createVoiceCallRuntime(params: {
|
||||
debug: console.debug,
|
||||
};
|
||||
|
||||
const config = resolveVoiceCallConfig(rawConfig);
|
||||
const cfg = fullConfig ?? (coreConfig as OpenClawConfig);
|
||||
const unresolvedConfig = resolveVoiceCallConfig(rawConfig);
|
||||
const configuredAgentId = unresolvedConfig.agentId
|
||||
? normalizeAgentId(unresolvedConfig.agentId)
|
||||
: resolveDefaultAgentId(cfg);
|
||||
const config = { ...unresolvedConfig, agentId: configuredAgentId };
|
||||
|
||||
if (!config.enabled) {
|
||||
throw new Error("Voice call disabled. Enable the plugin entry in config.");
|
||||
|
||||
@@ -152,12 +152,13 @@ describe("Zoom meeting session flow", () => {
|
||||
defaultMode: "transcribe",
|
||||
chrome: { waitForInCallMs: 1 },
|
||||
}),
|
||||
fullConfig: {},
|
||||
fullConfig: { agents: { list: [{ id: "operator", default: true }] } },
|
||||
runtime: harness.runtime,
|
||||
logger,
|
||||
});
|
||||
|
||||
const first = await runtime.join({ url: URL, mode: "transcribe" });
|
||||
expect(first.session.agentId).toBe("operator");
|
||||
expect(first.session.chrome?.health).toMatchObject({ inCall: true, cameraOff: true });
|
||||
|
||||
const reused = await runtime.join({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
@@ -72,10 +73,9 @@ function resolveTransport(
|
||||
}
|
||||
|
||||
function withSessionAgentConfig(config: ZoomMeetingsConfig, agentId: string): ZoomMeetingsConfig {
|
||||
const consultAgentId = config.realtime.agentId ?? agentId;
|
||||
return config.realtime.agentId === consultAgentId
|
||||
return config.realtime.agentId === agentId
|
||||
? config
|
||||
: { ...config, realtime: { ...config.realtime, agentId: consultAgentId } };
|
||||
: { ...config, realtime: { ...config.realtime, agentId } };
|
||||
}
|
||||
|
||||
function noteSession(session: ZoomMeetingsSession, note: string): void {
|
||||
@@ -90,6 +90,7 @@ function isAwaitingAdmission(session: ZoomMeetingsSession): boolean {
|
||||
}
|
||||
|
||||
export class ZoomMeetingsRuntime {
|
||||
readonly #defaultAgentId: string;
|
||||
readonly #sessions: SessionRuntime;
|
||||
readonly #requesterSessionKeys = new Map<string, string>();
|
||||
|
||||
@@ -101,6 +102,9 @@ export class ZoomMeetingsRuntime {
|
||||
logger: RuntimeLogger;
|
||||
},
|
||||
) {
|
||||
this.#defaultAgentId = normalizeAgentId(
|
||||
params.config.realtime.agentId ?? resolveDefaultAgentId(params.fullConfig),
|
||||
);
|
||||
this.#sessions = new MeetingSessionRuntime({
|
||||
logger: params.logger,
|
||||
logScope: ZOOM_MEETINGS_PLATFORM_ADAPTER.logScope,
|
||||
@@ -139,7 +143,7 @@ export class ZoomMeetingsRuntime {
|
||||
url: ZOOM_MEETINGS_PLATFORM_ADAPTER.urls.validateAndNormalize(request.url),
|
||||
transport: resolveTransport(request, params.config),
|
||||
mode: request.mode ?? params.config.defaultMode,
|
||||
agentId: normalizeAgentId(request.agentId),
|
||||
agentId: normalizeAgentId(request.agentId ?? this.#defaultAgentId),
|
||||
}),
|
||||
createSession: ({ request, resolved, createdAt }) => {
|
||||
const session = createZoomMeetingsSession({ config: params.config, resolved, createdAt });
|
||||
@@ -250,7 +254,7 @@ export class ZoomMeetingsRuntime {
|
||||
async join(request: ZoomMeetingsJoinRequest): Promise<ZoomMeetingsJoinResult> {
|
||||
try {
|
||||
const url = ZOOM_MEETINGS_PLATFORM_ADAPTER.urls.validateAndNormalize(request.url);
|
||||
const agentId = normalizeAgentId(request.agentId);
|
||||
const agentId = normalizeAgentId(request.agentId ?? this.#defaultAgentId);
|
||||
return await this.#sessions.join({ ...request, agentId, url });
|
||||
} catch (error) {
|
||||
const activeIds = new Set(this.list().map((session) => session.id));
|
||||
@@ -314,7 +318,7 @@ export class ZoomMeetingsRuntime {
|
||||
#probeContext(): ZoomMeetingsProbeContext {
|
||||
return {
|
||||
config: this.params.config,
|
||||
resolveAgentId: (request) => normalizeAgentId(request.agentId),
|
||||
resolveAgentId: (request) => normalizeAgentId(request.agentId ?? this.#defaultAgentId),
|
||||
list: () => this.list(),
|
||||
join: async (request) => await this.join(request),
|
||||
isReusable: (session, resolved) => this.#sessions.isReusableSession(session, resolved),
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const consultRealtimeVoiceAgent = vi.hoisted(() => vi.fn(async () => ({ text: "done" })));
|
||||
|
||||
vi.mock("../talk/agent-consult-runtime.js", () => ({ consultRealtimeVoiceAgent }));
|
||||
|
||||
import { consultMeetingAgent, type MeetingAgentConsultSurface } from "./agent-consult.js";
|
||||
|
||||
const surface: MeetingAgentConsultSurface = {
|
||||
id: "test-meeting",
|
||||
provider: "test-meeting",
|
||||
lane: "test-meeting",
|
||||
surface: "a test meeting",
|
||||
userLabel: "Participant",
|
||||
assistantLabel: "Agent",
|
||||
questionSourceLabel: "participant",
|
||||
workingResponseLabel: "participant",
|
||||
extraSystemPrompt: "Answer briefly.",
|
||||
};
|
||||
|
||||
describe("consultMeetingAgent", () => {
|
||||
beforeEach(() => {
|
||||
consultRealtimeVoiceAgent.mockClear();
|
||||
});
|
||||
|
||||
it("targets the configured default agent when agentId is omitted", async () => {
|
||||
await consultMeetingAgent({
|
||||
surface,
|
||||
config: { agents: { list: [{ id: "operator", default: true }] } },
|
||||
runtime: { agent: {} } as never,
|
||||
logger: {} as never,
|
||||
toolPolicy: "safe-read-only",
|
||||
meetingSessionId: "meeting-1",
|
||||
args: { question: "What should I say?" },
|
||||
transcript: [],
|
||||
});
|
||||
|
||||
expect(consultRealtimeVoiceAgent).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
agentId: "operator",
|
||||
sessionKey: "agent:operator:subagent:test-meeting:meeting-1",
|
||||
spawnedBy: "agent:operator:main",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps an explicit agentId ahead of the configured default", async () => {
|
||||
await consultMeetingAgent({
|
||||
surface,
|
||||
config: { agents: { list: [{ id: "operator", default: true }] } },
|
||||
runtime: { agent: {} } as never,
|
||||
logger: {} as never,
|
||||
agentId: "Support",
|
||||
toolPolicy: "safe-read-only",
|
||||
meetingSessionId: "meeting-2",
|
||||
args: { question: "What should I say?" },
|
||||
transcript: [],
|
||||
});
|
||||
|
||||
expect(consultRealtimeVoiceAgent).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
agentId: "support",
|
||||
sessionKey: "agent:support:subagent:test-meeting:meeting-2",
|
||||
spawnedBy: "agent:support:main",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { resolveDefaultAgentId } from "../agents/agent-scope-config.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import type { PluginRuntime, RuntimeLogger } from "../plugins/runtime/types.js";
|
||||
@@ -60,7 +61,9 @@ export async function consultMeetingAgent(params: {
|
||||
args: unknown;
|
||||
transcript: Array<{ role: "user" | "assistant"; text: string }>;
|
||||
}): Promise<{ text: string }> {
|
||||
const agentId = normalizeAgentId(params.agentId);
|
||||
const agentId = params.agentId
|
||||
? normalizeAgentId(params.agentId)
|
||||
: resolveDefaultAgentId(params.config);
|
||||
const requesterSessionKey =
|
||||
normalizeOptionalString(params.requesterSessionKey) ?? `agent:${agentId}:main`;
|
||||
const sessionKey = `agent:${agentId}:subagent:${params.surface.id}:${params.meetingSessionId}`;
|
||||
|
||||
@@ -214,7 +214,7 @@ describe("realtime voice agent consult runtime", () => {
|
||||
const { runtime, runEmbeddedAgent, sessionStore } = createAgentRuntime();
|
||||
|
||||
const result = await consultRealtimeVoiceAgent({
|
||||
cfg: {} as never,
|
||||
cfg: { agents: { list: [{ id: "operator", default: true }] } } as never,
|
||||
agentRuntime: runtime as never,
|
||||
logger: { warn: vi.fn() },
|
||||
sessionKey: "voice:15550001234",
|
||||
@@ -245,8 +245,8 @@ describe("realtime voice agent consult runtime", () => {
|
||||
const call = requireEmbeddedAgentCall(runEmbeddedAgent);
|
||||
expect(call.sessionId).toBe(voiceSession.sessionId);
|
||||
expect(call.sessionKey).toBe("voice:15550001234");
|
||||
expect(call.sandboxSessionKey).toBe("agent:main:voice:15550001234");
|
||||
expect(call.agentId).toBe("main");
|
||||
expect(call.sandboxSessionKey).toBe("agent:operator:voice:15550001234");
|
||||
expect(call.agentId).toBe("operator");
|
||||
expect(call.messageProvider).toBe("voice");
|
||||
expect(call.lane).toBe("voice");
|
||||
expect(call.toolsAllow).toStrictEqual(["read"]);
|
||||
@@ -416,7 +416,7 @@ describe("realtime voice agent consult runtime", () => {
|
||||
const { runtime, runEmbeddedAgent } = createAgentRuntime();
|
||||
|
||||
await consultRealtimeVoiceAgent({
|
||||
cfg: {} as never,
|
||||
cfg: { agents: { list: [{ id: "operator", default: true }] } } as never,
|
||||
agentRuntime: runtime as never,
|
||||
logger: { warn: vi.fn() },
|
||||
agentId: "voice",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Agent consult runtime starts agent consultation flows from talk sessions.
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { resolveDefaultAgentId } from "../agents/agent-scope-config.js";
|
||||
import type { RunEmbeddedAgentParams } from "../agents/embedded-agent-runner/run/params.js";
|
||||
import { forkSessionEntryFromParent } from "../auto-reply/reply/session-fork.js";
|
||||
import { resolveSessionWorkStartError } from "../config/sessions/lifecycle.js";
|
||||
@@ -258,7 +259,7 @@ export async function consultRealtimeVoiceAgent(params: {
|
||||
extraSystemPrompt?: string;
|
||||
fallbackText?: string;
|
||||
}): Promise<RealtimeVoiceAgentConsultResult> {
|
||||
const agentId = params.agentId ?? "main";
|
||||
const agentId = params.agentId ?? resolveDefaultAgentId(params.cfg);
|
||||
const agentDir = params.agentRuntime.resolveAgentDir(params.cfg, agentId);
|
||||
const workspaceDir = params.agentRuntime.resolveAgentWorkspaceDir(params.cfg, agentId);
|
||||
const storePath = params.agentRuntime.session.resolveStorePath(params.cfg.session?.store, {
|
||||
|
||||
Reference in New Issue
Block a user