Download src/plugins/runtime/runtime-agent.ingress.integration.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 9.5 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/plugins/runtime/runtime-agent.ingress.integration.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/plugins/runtime/runtime-agent.ingress.integration.test.ts
-
curl -L -o runtime-agent.ingress.integration.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/plugins/runtime/runtime-agent.ingress.integration.test.ts
9.5 kB
| import fs from "node:fs/promises"; | |
| import { createServer, type ServerResponse } from "node:http"; | |
| import path from "node:path"; | |
| import { describe, expect, it } from "vitest"; | |
| import { | |
| writeOpenAiResponsesSse, | |
| writeOpenAiResponsesText, | |
| } from "../../../test/helpers/openai-responses-sse.js"; | |
| import { createDeferred, withTestTimeout } from "../../../test/helpers/promise.js"; | |
| import { createDefaultDeps } from "../../cli/deps.js"; | |
| import { loadSessionEntry } from "../../config/sessions/session-accessor.js"; | |
| import type { OpenClawConfig } from "../../config/types.openclaw.js"; | |
| import { withLocalGatewayRequestScope } from "../../gateway/local-request-context.js"; | |
| import { buildMockOpenAiResponsesProvider } from "../../gateway/test-openai-responses-model.js"; | |
| import { hasErrnoCode } from "../../infra/errno.js"; | |
| import { withOpenClawTestState } from "../../test-utils/openclaw-test-state.js"; | |
| import { createRuntimeAgent } from "./runtime-agent.js"; | |
| const sessionKey = "agent:main:discord:channel:ingress-proof"; | |
| const label = "Voice owner admitted"; | |
| const fileName = "voice-ingress.txt"; | |
| const fileContent = "Voice tool execution reached the workspace."; | |
| function writeToolCalls(response: ServerResponse): void { | |
| const calls = [ | |
| { name: "sessions", arguments: { action: "patch", label } }, | |
| { name: "write", arguments: { path: fileName, content: fileContent } }, | |
| ].map((call, index) => ({ | |
| type: "function_call", | |
| id: `fc_voice_${index}`, | |
| call_id: `call_voice_${index}`, | |
| name: call.name, | |
| arguments: JSON.stringify(call.arguments), | |
| })); | |
| writeOpenAiResponsesSse(response, [ | |
| { | |
| type: "response.created", | |
| response: { id: "response_voice_tools", status: "in_progress", output: [] }, | |
| }, | |
| ...calls.flatMap((item, output_index) => [ | |
| { type: "response.output_item.added", output_index, item: { ...item, arguments: "" } }, | |
| { | |
| type: "response.function_call_arguments.delta", | |
| item_id: item.id, | |
| output_index, | |
| delta: item.arguments, | |
| }, | |
| { type: "response.output_item.done", output_index, item }, | |
| ]), | |
| { | |
| type: "response.completed", | |
| response: { | |
| id: "response_voice_tools", | |
| status: "completed", | |
| output: calls, | |
| usage: { input_tokens: 8, output_tokens: 8, total_tokens: 16 }, | |
| }, | |
| }, | |
| ]); | |
| } | |
| async function withIngressFixture( | |
| options: { senderIsOwner: boolean; toolsAllow: string[]; cancel?: boolean }, | |
| assertEffects: (effects: { | |
| storedLabel: string | undefined; | |
| file: string | undefined; | |
| toolResults: string; | |
| }) => void, | |
| ): Promise<void> { | |
| await withOpenClawTestState( | |
| { | |
| label: "runtime-agent-ingress", | |
| env: { OPENCLAW_DISABLE_BUNDLED_PLUGINS: "1", OPENCLAW_SKIP_PROVIDERS: undefined }, | |
| }, | |
| async (state) => { | |
| const received = createDeferred<ServerResponse>(); | |
| void received.promise.catch(() => {}); | |
| const cancelled = createDeferred(); | |
| const controller = new AbortController(); | |
| let toolResults = ""; | |
| let turn: Promise<unknown> | undefined; | |
| const server = createServer((request, response) => { | |
| void (async () => { | |
| if (request.method === "GET" && request.url === "/v1/models") { | |
| response.writeHead(200, { "content-type": "application/json" }); | |
| response.end(JSON.stringify({ data: [{ id: "voice-ingress", object: "model" }] })); | |
| return; | |
| } | |
| if (request.method !== "POST" || request.url !== "/v1/responses") { | |
| response.writeHead(404).end(); | |
| return; | |
| } | |
| const chunks: Buffer[] = []; | |
| for await (const chunk of request) { | |
| chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); | |
| } | |
| const body = Buffer.concat(chunks).toString("utf8"); | |
| if (body.includes("function_call_output")) { | |
| toolResults = body; | |
| writeOpenAiResponsesText(response, { | |
| text: "Voice turn finished.", | |
| responseId: "response_voice_done", | |
| messageId: "message_voice_done", | |
| }); | |
| return; | |
| } | |
| if (options.cancel) { | |
| response.once("close", () => { | |
| if (!response.writableFinished) { | |
| cancelled.resolve(); | |
| } | |
| }); | |
| received.resolve(response); | |
| return; | |
| } | |
| writeToolCalls(response); | |
| })().catch((error: unknown) => { | |
| received.reject(error); | |
| response.destroy(error instanceof Error ? error : new Error(String(error))); | |
| }); | |
| }); | |
| try { | |
| await new Promise<void>((resolve, reject) => { | |
| server.once("error", reject); | |
| server.listen(0, "127.0.0.1", resolve); | |
| }); | |
| const address = server.address(); | |
| if (!address || typeof address === "string") { | |
| throw new Error("Voice ingress provider did not bind a loopback port"); | |
| } | |
| const provider = buildMockOpenAiResponsesProvider( | |
| `http://127.0.0.1:${address.port}/v1`, | |
| "voice-ingress", | |
| ); | |
| const cfg: OpenClawConfig = { | |
| plugins: { enabled: false }, | |
| agents: { | |
| entries: { main: { workspace: state.workspaceDir } }, | |
| defaults: { | |
| model: { primary: provider.modelRef, fallbacks: [] }, | |
| models: { [provider.modelRef]: { agentRuntime: { id: "openclaw" } } }, | |
| skills: [], | |
| skipBootstrap: true, | |
| heartbeat: { every: "0m" }, | |
| }, | |
| }, | |
| tools: { allow: ["sessions", "write", "read"], codeMode: { enabled: false } }, | |
| models: { | |
| mode: "replace", | |
| providers: { | |
| [provider.providerId]: { | |
| ...provider.config, | |
| request: { allowPrivateNetwork: true }, | |
| }, | |
| }, | |
| }, | |
| }; | |
| await state.writeConfig(cfg); | |
| turn = withLocalGatewayRequestScope( | |
| { deps: createDefaultDeps(), getRuntimeConfig: () => cfg }, | |
| () => | |
| createRuntimeAgent().runCommandFromIngress( | |
| { | |
| agentId: "main", | |
| sessionKey, | |
| message: "Update this session label and write the requested workspace file.", | |
| messageChannel: "discord", | |
| senderIsOwner: options.senderIsOwner, | |
| toolsAllow: options.toolsAllow, | |
| abortSignal: controller.signal, | |
| allowModelOverride: false, | |
| deliver: false, | |
| timeout: "30", | |
| }, | |
| { | |
| log: () => {}, | |
| error: () => {}, | |
| exit: (code) => { | |
| throw new Error(`Agent attempted to exit with code ${code}`); | |
| }, | |
| }, | |
| ), | |
| ); | |
| if (options.cancel) { | |
| const response = await Promise.race([ | |
| received.promise, | |
| turn.then(() => { | |
| throw new Error("Agent completed before the provider received the turn"); | |
| }), | |
| ]); | |
| controller.abort(new Error("Voice participant left the room")); | |
| await withTestTimeout( | |
| Promise.all([Promise.allSettled([turn]), cancelled.promise]), | |
| 5_000, | |
| "Ingress did not cancel the agent and provider request", | |
| ); | |
| // Late provider output must never revive the cancelled run's tool authority. | |
| writeToolCalls(response); | |
| } else { | |
| await turn; | |
| expect(toolResults).toContain("function_call_output"); | |
| } | |
| const file = await fs | |
| .readFile(path.join(state.workspaceDir, fileName), "utf8") | |
| .catch((error: unknown) => { | |
| if (!hasErrnoCode(error, "ENOENT")) { | |
| throw error; | |
| } | |
| return undefined; | |
| }); | |
| assertEffects({ | |
| storedLabel: loadSessionEntry({ agentId: "main", sessionKey })?.label, | |
| file, | |
| toolResults, | |
| }); | |
| } finally { | |
| controller.abort(); | |
| server.closeAllConnections(); | |
| await new Promise<void>((resolve) => { | |
| server.close(() => resolve()); | |
| }); | |
| await Promise.allSettled(turn ? [turn] : []); | |
| } | |
| }, | |
| ); | |
| } | |
| describe("host runtime ingress agent effects", () => { | |
| it.each([ | |
| { name: "owner", senderIsOwner: true, toolsAllow: ["sessions", "write"], canPatch: true }, | |
| { name: "guest", senderIsOwner: false, toolsAllow: ["sessions", "write"], canPatch: false }, | |
| { name: "restricted owner", senderIsOwner: true, toolsAllow: ["write"], canPatch: false }, | |
| ])("enforces $name authority in the real tool loop", { timeout: 90_000 }, async (scenario) => { | |
| await withIngressFixture(scenario, ({ storedLabel, file }) => { | |
| expect(storedLabel).toBe(scenario.canPatch ? label : undefined); | |
| expect(file).toBe(fileContent); | |
| }); | |
| }); | |
| it( | |
| "cancels before tool I/O and discards late provider tool calls", | |
| { timeout: 90_000 }, | |
| async () => { | |
| await withIngressFixture( | |
| { senderIsOwner: true, toolsAllow: ["sessions", "write"], cancel: true }, | |
| ({ storedLabel, file, toolResults }) => { | |
| expect(storedLabel).toBeUndefined(); | |
| expect(file).toBeUndefined(); | |
| expect(toolResults).toBe(""); | |
| }, | |
| ); | |
| }, | |
| ); | |
| }); | |