import { expect } from "@std/expect"; import { describe, it } from "@std/testing/bdd"; import { join } from "@std/path"; import { createHarnessAgentRunExecutor } from "@commonfabric/agent-runner/agent-run-harness"; import type { HarnessPromptLoopResult } from "@commonfabric/cf-harness/prompt-loop"; import { Identity } from "@commonfabric/identity"; import { waitForCellValue } from "@commonfabric/integration/wait-for-cell-value"; import { SERVER_EXECUTION_DEFAULT_ENABLED } from "@commonfabric/memory/v2/server-execution-default"; import { StandaloneMemoryServer } from "@commonfabric/memory/v2/standalone"; import { experimentalOptionsFromEnv, getPatternEnvironment, resolveEntryIdentity, Runtime, runtimePresets, setPatternEnvironment, } from "@commonfabric/runner"; import { agentQueueIndexCell, type AgentRunRecord, AgentRunRecordSchema, } from "@commonfabric/runner/agent-run"; import { listenServingMemoryServer } from "@commonfabric/runner/executor/serving-memory-server.deno"; import { StorageManager } from "@commonfabric/runner/storage/cache.deno"; import { startAgentRunner } from "../commands/agent.ts"; import { getAcl } from "../lib/acl.ts"; import { openAgentStorageHost } from "../lib/agent-connections.ts"; import { loadIdentity } from "../lib/identity.ts"; const HOME_PATH = "/api/patterns/system/home.tsx"; /** A home pattern with the queue and its real registration handler. */ const HOME_SOURCE = ` import { handler, pattern, Writable, type PerUser } from "commonfabric"; type Runner = { host: string; tools: string[]; registrationId?: string; registeredAt: string; lastClaimAt?: string }; type Entry = { run: PerUser; host: string }; type RegisterEvent = { runner?: Runner; expectedRegistrationId?: string }; const register = handler }>( (event = {}, state) => { if (event.runner === undefined && event.expectedRegistrationId !== undefined && state.runner.get()?.registrationId !== event.expectedRegistrationId) return; state.runner.set(event.runner); }, ); export default pattern(() => { const entries = new Writable([]).for("entries"); const runner = new Writable(undefined).for("runner"); return { agentQueue: { entries, agentRunner: runner, setAgentRunner: register({ runner }) } }; }); `; /** * The posture every runtime here runs, the agent runner's included: the * environment's explicit value, else the first-party default, as a deployed * entry point resolves it. */ const serverExecution = experimentalOptionsFromEnv(Deno.env.get) .serverExecution ?? SERVER_EXECUTION_DEFAULT_ENABLED; /** * Starts a memory server standing in for one toolshed, with a serving loop * when the posture is ON, as a toolshed has one then. */ function startHost( options: { serve?: (request: Request) => Response | undefined; } = {}, ): Promise<{ url: URL; close(): Promise }> { return serverExecution ? listenServingMemoryServer(options) : Promise.resolve(StandaloneMemoryServer.start(options)); } describe("agent-connections", () => { it("registers at home and completes a run on another host through the default result session", async () => { const directory = await Deno.makeTempDir({ prefix: "agent-connections-" }); const identityPath = join(directory, "identity.key"); await Deno.writeFile(identityPath, await Identity.generatePkcs8()); const identity = await loadIdentity(identityPath); const homeIdentity = await resolveEntryIdentity( HOME_PATH, (path) => path === HOME_PATH ? Promise.resolve(HOME_SOURCE) : Promise.reject(new Error(`Unexpected pattern module: ${path}`)), ); const homeServer = await startHost({ serve: (request) => { const url = new URL(request.url); if (url.pathname === HOME_PATH) { return new Response( url.searchParams.has("identity") ? homeIdentity : HOME_SOURCE, { headers: { "content-type": "text/plain" }, }, ); } }, }); const recordServer = await startHost(); const connect = (url: URL) => new Runtime(runtimePresets.remoteClient({ apiUrl: url, storageManager: StorageManager.open({ as: identity, memoryHost: url }), experimental: { serverExecution }, })); const home = connect(homeServer.url); const remote = connect(recordServer.url); let runner: Awaited> | undefined; const messages: string[] = []; try { const execute = createHarnessAgentRunExecutor({ identityKeyPath: identityPath, requester: identity.did(), workRoot: directory, allowedTools: ["describe_handle"], readSpaceAcl: (host, space) => getAcl({ apiUrl: host, space, identity: identityPath }), report: (message) => messages.push(message), harnessDeps: { env: { CF_HARNESS_MODEL_PROVIDER: "openai-compatible-gateway", CF_HARNESS_GATEWAY_AUTH_MODE: "none", // Named, with a `runsc` and a rootfs nothing runs, so the run does // not take the default of the machine the suite runs on, which on // macOS and Linux is that machine's native runtime. CF_HARNESS_SANDBOX_RUNTIME: "runsc", CF_HARNESS_RUNSC_BINARY: "/nonexistent/agent-connections-test/runsc", CF_HARNESS_SANDBOX_ROOTFS: "/nonexistent/agent-connections-test/rootfs", }, createPromptLoop: (options) => ({ runPrompt: async () => { await Deno.writeTextFile( join(options.workspaceHostPath!, "agent-result.json"), JSON.stringify({ answer: "Solaris" }), ); return { model: "scripted", finalAssistantText: "Done.", transcript: [], modelTurns: 1, runState: { runId: "remote-result", status: "completed", createdAt: "2026-09-20T12:00:00Z", updatedAt: "2026-09-20T12:00:01Z", currentDir: "/workspace", policyEvents: [], toolOutputs: [], } as unknown as HarnessPromptLoopResult["runState"], }; }, runTranscript: () => Promise.reject(new Error("No transcript supplied")), }), }, }); runner = await startAgentRunner( { identityPath, home: identity.did(), homeHost: homeServer.url.origin, runnerHost: recordServer.url.origin, tools: ["describe_handle"], maxConcurrent: 1, leaseMs: 60_000, workRoot: directory, }, (message) => messages.push(message), undefined, execute, ); const queue = agentQueueIndexCell(home, identity.did()); await queue.sync(); expect(queue.get().agentRunner).toMatchObject({ host: recordServer.url.origin, tools: ["describe_handle"], registeredAt: expect.any(String), }); const record = remote.getCell( identity.did(), "remote-agent-run", AgentRunRecordSchema, ); await remote.editWithRetry((tx) => { const request = remote.getCell(identity.did(), "request"); record.withTx(tx).set({ request, piece: request, space: request, requestHash: "remote-request", task: "Choose a book", inputs: {}, resultSchema: { type: "object", properties: { answer: { type: "string" } }, required: ["answer"], }, state: "queued", stateSince: "2026-09-20T12:00:00Z", submittedAt: "2026-09-20T12:00:00Z", }); }); await home.editWithRetry((tx) => { queue.withTx(tx).key("entries").set([{ run: record, host: recordServer.url.origin, }]); }); const ended = await waitForCellValue( remote, record, (value) => value?.outcome !== undefined, { stuckLabel: "default deployed runner completes the remote record" }, ); expect(ended.state).toBe("completed"); expect( messages.some((message) => /agent runner: (?:a run|a queue scan) failed/.test(message) ), ).toBe(false); expect(ended.result?.get()).toEqual({ answer: "Solaris" }); expect(ended.modelTurns).toBe(1); await queue.pull(); expect(queue.get().agentRunner?.lastClaimAt).toEqual(expect.any(String)); await runner.stop(); runner = undefined; await queue.pull(); expect(queue.get().agentRunner).toBeUndefined(); } finally { await runner?.stop(); await home.dispose(); await remote.dispose(); await homeServer.close(); await recordServer.close(); await Deno.remove(directory, { recursive: true }); } }); it("keeps the home pattern environment when opening a record host", async () => { const directory = await Deno.makeTempDir({ prefix: "agent-connections-" }); const identityPath = join(directory, "identity.key"); await Deno.writeFile(identityPath, await Identity.generatePkcs8()); const recordServer = await startHost(); const originalEnvironment = getPatternEnvironment(); const homeUrl = new URL("https://home.example.test"); setPatternEnvironment({ apiUrl: homeUrl }); let storageHost: Runtime | undefined; try { storageHost = await openAgentStorageHost( identityPath, recordServer.url.origin, ); expect(getPatternEnvironment().apiUrl).toEqual(homeUrl); } finally { await storageHost?.dispose(); setPatternEnvironment(originalEnvironment); await recordServer.close(); await Deno.remove(directory, { recursive: true }); } }); });