





















@@ -1,84 +1,20 @@
1-import { randomUUID } from "node:crypto";
21import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
32import type { PluginRuntime, RuntimeLogger } from "openclaw/plugin-sdk/plugin-runtime";
43import {
4+consultRealtimeVoiceAgent,
55REALTIME_VOICE_AGENT_CONSULT_TOOL,
66REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME,
7+resolveRealtimeVoiceAgentConsultTools,
8+resolveRealtimeVoiceAgentConsultToolsAllow,
79type RealtimeVoiceTool,
810} from "openclaw/plugin-sdk/realtime-voice";
9-import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
1011import type { GoogleMeetConfig, GoogleMeetToolPolicy } from "./config.js";
111212-type AgentPayload = {
13-text?: string;
14-isError?: boolean;
15-isReasoning?: boolean;
16-};
17-1813export const GOOGLE_MEET_AGENT_CONSULT_TOOL_NAME = REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME;
1914export const GOOGLE_MEET_AGENT_CONSULT_TOOL = REALTIME_VOICE_AGENT_CONSULT_TOOL;
20152116export function resolveGoogleMeetRealtimeTools(policy: GoogleMeetToolPolicy): RealtimeVoiceTool[] {
22-return policy === "none" ? [] : [GOOGLE_MEET_AGENT_CONSULT_TOOL];
23-}
24-25-function normalizeToolArgString(args: unknown, key: string): string | undefined {
26-if (!args || typeof args !== "object" || Array.isArray(args)) {
27-return undefined;
28-}
29-return normalizeOptionalString((args as Record<string, unknown>)[key]);
30-}
31-32-function collectVisibleText(payloads: AgentPayload[]): string | null {
33-const chunks: string[] = [];
34-for (const payload of payloads) {
35-if (payload.isError || payload.isReasoning) {
36-continue;
37-}
38-const text = normalizeOptionalString(payload.text);
39-if (text) {
40-chunks.push(text);
41-}
42-}
43-return chunks.length > 0 ? chunks.join("\n\n").trim() : null;
44-}
45-46-function resolveToolsAllow(policy: GoogleMeetToolPolicy): string[] | undefined {
47-if (policy === "owner") {
48-return undefined;
49-}
50-if (policy === "safe-read-only") {
51-return ["read", "web_search", "web_fetch", "x_search", "memory_search", "memory_get"];
52-}
53-return [];
54-}
55-56-function buildPrompt(params: {
57-args: unknown;
58-transcript: Array<{ role: "user" | "assistant"; text: string }>;
59-}): string {
60-const question = normalizeToolArgString(params.args, "question");
61-if (!question) {
62-throw new Error("question required");
63-}
64-const context = normalizeToolArgString(params.args, "context");
65-const responseStyle = normalizeToolArgString(params.args, "responseStyle");
66-const transcript = params.transcript
67-.slice(-12)
68-.map((entry) => `${entry.role === "assistant" ? "Agent" : "Participant"}: ${entry.text}`)
69-.join("\n");
70-return [
71-"You are helping an OpenClaw realtime voice agent during a private Google Meet.",
72-"Answer the participant's question with the strongest useful reasoning and available tools.",
73-"Return only the concise answer the realtime voice agent should speak next.",
74-"Do not include markdown, citations unless needed, tool logs, or private reasoning.",
75-responseStyle ? `Spoken style: ${responseStyle}` : undefined,
76-transcript ? `Recent meeting transcript:\n${transcript}` : undefined,
77-context ? `Additional context:\n${context}` : undefined,
78-`Question:\n${question}`,
79-]
80-.filter(Boolean)
81-.join("\n\n");
17+return resolveRealtimeVoiceAgentConsultTools(policy);
8218}
83198420export async function consultOpenClawAgentForGoogleMeet(params: {
@@ -90,54 +26,22 @@ export async function consultOpenClawAgentForGoogleMeet(params: {
9026args: unknown;
9127transcript: Array<{ role: "user" | "assistant"; text: string }>;
9228}): Promise<{ text: string }> {
93-const agentId = "main";
94-const sessionKey = `google-meet:${params.meetingSessionId}`;
95-const cfg = params.fullConfig;
96-const agentDir = params.runtime.agent.resolveAgentDir(cfg, agentId);
97-const workspaceDir = params.runtime.agent.resolveAgentWorkspaceDir(cfg, agentId);
98-await params.runtime.agent.ensureAgentWorkspace({ dir: workspaceDir });
99-100-const storePath = params.runtime.agent.session.resolveStorePath(cfg.session?.store, { agentId });
101-const sessionStore = params.runtime.agent.session.loadSessionStore(storePath);
102-const now = Date.now();
103-const existing = sessionStore[sessionKey] as
104-| { sessionId?: string; updatedAt?: number }
105-| undefined;
106-const sessionId = normalizeOptionalString(existing?.sessionId) ?? randomUUID();
107-sessionStore[sessionKey] = { ...existing, sessionId, updatedAt: now };
108-await params.runtime.agent.session.saveSessionStore(storePath, sessionStore);
109-110-const sessionFile = params.runtime.agent.session.resolveSessionFilePath(
111-sessionId,
112-sessionStore[sessionKey],
113-{ agentId },
114-);
115-const result = await params.runtime.agent.runEmbeddedPiAgent({
116- sessionId,
117- sessionKey,
29+return await consultRealtimeVoiceAgent({
30+cfg: params.fullConfig,
31+agentRuntime: params.runtime.agent,
32+logger: params.logger,
33+sessionKey: `google-meet:${params.meetingSessionId}`,
11834messageProvider: "google-meet",
119- sessionFile,
120- workspaceDir,
121-config: cfg,
122-prompt: buildPrompt({ args: params.args, transcript: params.transcript }),
123-thinkLevel: "high",
124-verboseLevel: "off",
125-reasoningLevel: "off",
126-toolResultFormat: "plain",
127-toolsAllow: resolveToolsAllow(params.config.realtime.toolPolicy),
128-timeoutMs: params.runtime.agent.resolveAgentTimeoutMs({ cfg }),
129-runId: `google-meet:${params.meetingSessionId}:${Date.now()}`,
13035lane: "google-meet",
36+runIdPrefix: `google-meet:${params.meetingSessionId}`,
37+args: params.args,
38+transcript: params.transcript,
39+surface: "a private Google Meet",
40+userLabel: "Participant",
41+assistantLabel: "Agent",
42+questionSourceLabel: "participant",
43+toolsAllow: resolveRealtimeVoiceAgentConsultToolsAllow(params.config.realtime.toolPolicy),
13144extraSystemPrompt:
13245"You are a behind-the-scenes consultant for a live meeting voice agent. Be accurate, brief, and speakable.",
133- agentDir,
13446});
135-136-const text = collectVisibleText((result.payloads ?? []) as AgentPayload[]);
137-if (!text) {
138-const reason = result.meta?.aborted ? "agent run aborted" : "agent returned no speakable text";
139-params.logger.warn(`[google-meet] agent consult produced no answer: ${reason}`);
140-return { text: "I need a moment to verify that before answering." };
141-}
142-return { text };
14347}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。