@finalai/final-agent-provider 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HOSTING.md +4 -4
- package/README.md +94 -2
- package/dist/modules/authoring-final-channel.mjs +2 -2
- package/dist/modules/authoring-final-channel.mjs.map +2 -2
- package/dist/modules/channel-factories.d.mts +5 -7
- package/dist/modules/channel-factories.mjs +4 -50
- package/dist/modules/channel-factories.mjs.map +2 -2
- package/dist/modules/channels/channel-utils.d.mts +132 -0
- package/dist/modules/channels/channel-utils.mjs +445 -0
- package/dist/modules/channels/channel-utils.mjs.map +7 -0
- package/dist/modules/channels/delivery.d.mts +5 -5
- package/dist/modules/channels/delivery.mjs.map +1 -1
- package/dist/modules/channels/direct-messaging.d.mts +2 -2
- package/dist/modules/channels/direct-messaging.mjs.map +2 -2
- package/dist/modules/channels/discord-dispatch.d.mts +17 -0
- package/dist/modules/channels/discord-dispatch.mjs +139 -0
- package/dist/modules/channels/discord-dispatch.mjs.map +7 -0
- package/dist/modules/channels/discord-gateway.d.mts +19 -0
- package/dist/modules/channels/discord-gateway.mjs +233 -0
- package/dist/modules/channels/discord-gateway.mjs.map +7 -0
- package/dist/modules/channels/discord.d.mts +9 -0
- package/dist/modules/channels/discord.mjs +904 -0
- package/dist/modules/channels/discord.mjs.map +7 -0
- package/dist/modules/channels/fake-platform.d.mts +2 -7
- package/dist/modules/channels/fake-platform.mjs +2 -38
- package/dist/modules/channels/fake-platform.mjs.map +2 -2
- package/dist/modules/channels/github.d.mts +5 -0
- package/dist/modules/channels/github.mjs +720 -0
- package/dist/modules/channels/github.mjs.map +7 -0
- package/dist/modules/channels/group-messaging.d.mts +2 -2
- package/dist/modules/channels/group-messaging.mjs.map +2 -2
- package/dist/modules/channels/index.d.mts +7 -3
- package/dist/modules/channels/index.mjs +7 -3
- package/dist/modules/channels/index.mjs.map +2 -2
- package/dist/modules/channels/linear.d.mts +4 -0
- package/dist/modules/channels/linear.mjs +621 -0
- package/dist/modules/channels/linear.mjs.map +7 -0
- package/dist/modules/channels/messaging-channel.d.mts +3 -3
- package/dist/modules/channels/messaging-channel.mjs +2 -2
- package/dist/modules/channels/messaging-channel.mjs.map +2 -2
- package/dist/modules/channels/phone.d.mts +8 -0
- package/dist/modules/channels/phone.mjs +382 -0
- package/dist/modules/channels/phone.mjs.map +7 -0
- package/dist/modules/channels/projection.mjs.map +1 -1
- package/dist/modules/channels/reply-receipts.d.mts +31 -0
- package/dist/modules/channels/reply-receipts.mjs +63 -0
- package/dist/modules/channels/reply-receipts.mjs.map +7 -0
- package/dist/modules/channels/routing.d.mts +1 -0
- package/dist/modules/channels/routing.mjs +5 -1
- package/dist/modules/channels/routing.mjs.map +2 -2
- package/dist/modules/channels/slack.d.mts +7 -0
- package/dist/modules/channels/slack.mjs +1134 -0
- package/dist/modules/channels/slack.mjs.map +7 -0
- package/dist/modules/channels/voice-recording.d.mts +7 -0
- package/dist/modules/channels/voice-recording.mjs +49 -0
- package/dist/modules/channels/voice-recording.mjs.map +7 -0
- package/dist/modules/channels/voice.d.mts +33 -0
- package/dist/modules/channels/voice.mjs +851 -0
- package/dist/modules/channels/voice.mjs.map +7 -0
- package/dist/modules/channels/webhook.d.mts +5 -0
- package/dist/modules/channels/webhook.mjs +76 -0
- package/dist/modules/channels/webhook.mjs.map +7 -0
- package/dist/modules/harnesses/acp-describe.mjs +1 -1
- package/dist/modules/harnesses/acp-describe.mjs.map +2 -2
- package/dist/modules/harnesses/fidelity.mjs +17 -17
- package/dist/modules/harnesses/fidelity.mjs.map +2 -2
- package/dist/modules/harnesses/remote-url.mjs.map +1 -1
- package/dist/modules/runtime/remote-host.mjs.map +1 -1
- package/dist/modules/sandboxes/build-scripts.mjs.map +1 -1
- package/dist/modules/sandboxes/paths.mjs.map +1 -1
- package/dist/modules/testing/harness.mjs +2 -2
- package/dist/modules/testing/harness.mjs.map +1 -1
- package/package.json +45 -19
- package/dist/modules/channels/address-context.d.mts +0 -7
- package/dist/modules/channels/address-context.mjs +0 -80
- package/dist/modules/channels/address-context.mjs.map +0 -7
- package/dist/modules/channels/agent-events.d.mts +0 -103
- package/dist/modules/channels/agent-events.mjs +0 -341
- package/dist/modules/channels/agent-events.mjs.map +0 -7
- package/dist/modules/channels/agent-schedules.d.mts +0 -25
- package/dist/modules/channels/agent-schedules.mjs +0 -96
- package/dist/modules/channels/agent-schedules.mjs.map +0 -7
- package/dist/modules/channels/service-input.d.mts +0 -22
- package/dist/modules/channels/service-input.mjs +0 -32
- package/dist/modules/channels/service-input.mjs.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/runtime/remote-host.ts"],
|
|
4
|
-
"sourcesContent": ["import { RequestError } from '@agentclientprotocol/sdk/experimental/v2';\n\nimport {\n AcpTransport,\n BaseCapability,\n BaseToolProvision,\n CredentialDelivery,\n CredentialRoute,\n formatProviderRef,\n harnessDescriptionSchema,\n InferenceCredentialKind,\n InstructionRole,\n packageRef,\n SandboxWire,\n type HarnessClientTlsIface,\n type HarnessDescriptionIface,\n type HarnessEndpointIface,\n type HarnessHealthIface,\n type HarnessIface,\n type HarnessSessionRefIface,\n type InstructionFragmentIface,\n type JsonObject,\n type OpenHarnessSessionArgsIface,\n type ResumeHarnessSessionArgsIface,\n type SecretReaderIface,\n type SkillBundleIface,\n type ToolApproval,\n} from '@finalai/agent-provider';\n\nimport { createNodeClientTlsFetch } from '@finalai/websockets/node-client-tls';\n\nimport { createHmac } from 'node:crypto';\n\nimport * as z from 'zod';\n\nimport { toJsonObject, type SecretRefIface } from \"../harnesses/config-fields.mjs\";\n\nimport {\n resolveRemoteClientTls,\n type RemoteClientTlsInputIface,\n} from \"../harnesses/remote-client-tls.mjs\";\n\nconst unavailableSchema = z.object({\n code: z.literal('harness_unavailable'),\n executable: z.string(),\n foundVersion: z.string().nullable(),\n requiredVersion: z.string(),\n detail: z.string(),\n});\n\nconst unavailableOf = (text: string) => {\n try {\n return unavailableSchema.safeParse(JSON.parse(text)).data ?? null;\n } catch {\n return null;\n }\n};\n\nconst DEFAULT_HEALTH_TIMEOUT_MS = 5_000;\n\nconst DEFAULT_REGISTER_TIMEOUT_MS = 10_000;\n\nconst DEFAULT_CLOSE_TIMEOUT_MS = 15_000;\n\n// Mirrors @finalai/harness-runtime's serve.ts and server/auth.ts.\nexport const PROGRAM_CONFIG_HEADER = 'x-final-program-config';\n\nexport const HEALTH_TOKEN_HEADER = 'x-final-health-token';\n\nexport const CLOSE_TOKEN_HEADER = 'x-final-close-token';\n\n// The runtime's registration-scoped health credential (HMAC of the registration id under the\n// hop token): health(ref) has no secrets, so open/resume put it in the ref instead of the hop.\nexport const healthTokenFor = (args: { hop: string; id: string }): string =>\n createHmac('sha256', args.hop).update(`final-harness-health:${args.id}`).digest('base64url');\n\nexport const closeTokenFor = (args: { hop: string; id: string }): string =>\n createHmac('sha256', args.hop).update(`final-harness-close:${args.id}`).digest('base64url');\n\nconst PROGRAM_CONFIGS_PATH = '/v1/program-configs/';\n\nexport enum RemoteProgram {\n ClaudeCode = 'claude-code',\n Codex = 'codex',\n Pi = 'pi',\n}\n\nexport interface RemoteHarnessFactoryConfigIface {\n fetch?: typeof fetch;\n tlsFetch?: (tls: HarnessClientTlsIface) => typeof fetch;\n // Test seams.\n now?: () => number;\n newId?: () => string;\n healthTimeoutMs?: number;\n registerTimeoutMs?: number;\n closeTimeoutMs?: number;\n}\n\nexport interface RemoteSettingsIface {\n url: string;\n tls: RemoteClientTlsInputIface | null;\n hop: SecretRefIface;\n cwd: string | null;\n executable: string | null;\n model: string | null;\n reasoning: string | null;\n permissionMode: string | null;\n approvalPolicy: string | null;\n sandboxMode: string | null;\n allowedTools: string[] | null;\n instructions: InstructionFragmentIface[];\n skills: SkillBundleIface[];\n}\n\nexport interface RemoteProgramSpecIface {\n specifier: string;\n program: RemoteProgram;\n description: HarnessDescriptionIface;\n settings: (config: OpenHarnessSessionArgsIface['config']) => RemoteSettingsIface;\n}\n\n// The provider-private program config this harness registers with the runtime\n// See @finalai/harness-runtime's program-config.ts. Version 1.\n// `credentials`, `broker` and `refresh` carry route grants (and, for at-open\n// harnesses, the resolved model credential); they travel only between this\n// provider and the runtime, over the hop-authenticated registration.\nexport interface RemoteProgramConfigIface {\n version: 1;\n program: RemoteProgram;\n // Absolute path on the runtime host; null = the runtime's own working directory.\n cwd: string | null;\n executable: string | null;\n model: string | null;\n reasoning: string | null;\n permissionMode: string | null;\n approvalPolicy: string | null;\n sandboxMode: string | null;\n allowedTools: string[] | null;\n // System fragments only; user fragments arrive as _final/session/observe.\n instructions: Pick<InstructionFragmentIface, 'role' | 'content'>[];\n skills: SkillBundleIface[];\n // Declared capabilities this harness provides, with the target a bound one\n // routes to; null runs it natively on the host. A host-disableable capability\n // absent here must be disabled through the program's own allow-lists.\n baseTools: Record<string, { provision: BaseToolProvision; target: string | null }>;\n sandboxes: Record<\n string,\n {\n bindingId: string;\n capabilities: string[];\n rpc: { url: string; token: string; expiresAt: string } | null;\n mcp: { url: string; token: string; expiresAt: string } | null;\n }\n >;\n toolPolicy: Record<string, ToolApproval>;\n attachments: { url: string; token: string } | null;\n // Matches @finalai/harness-runtime's program config: the model credential\n // handed over at open (claude-code, codex), or the broker `model` route grant\n // for per-request programs (pi), which post to `<broker.url>/model`.\n credentials: OpenHarnessSessionArgsIface['credentials']['atOpen'];\n // `sandboxToken` is the broker `sandbox` route grant, for renewing sandbox endpoints.\n broker: {\n url: string;\n token: string;\n sandboxToken: string | null;\n harnessSessionId: string;\n } | null;\n // The grant's standard refresh route: the runtime pulls the next generation\n // of `credentials` and `broker` from it before they expire.\n refresh: OpenHarnessSessionArgsIface['credentials']['refresh'];\n}\n\nexport type RemoteOpenArgsIface = OpenHarnessSessionArgsIface;\n\nexport type RemoteHarnessIface = HarnessIface;\n\n// Scoped capabilities survive a session-service restart without retaining the hop or TLS keys.\nexport const formatRemoteRef = (args: {\n id: string;\n url: string;\n healthToken: string | null;\n closeToken?: string | null;\n}): string =>\n args.closeToken != null && args.healthToken != null\n ? `${args.id}|${args.healthToken}|${args.closeToken}|${args.url}`\n : args.healthToken == null\n ? `${args.id}|${args.url}`\n : `${args.id}|${args.healthToken}|${args.url}`;\n\nconst HEALTH_TOKEN_PATTERN = /^[A-Za-z0-9_-]{43}$/u;\n\nexport interface RemoteRefIface {\n id: string;\n url: string | null;\n healthToken: string | null;\n closeToken: string | null;\n}\n\nexport const parseRemoteRef = (ref: string): RemoteRefIface => {\n const bar = ref.indexOf('|');\n if (bar < 0) return { id: ref, url: null, healthToken: null, closeToken: null };\n const id = ref.slice(0, bar);\n const rest = ref.slice(bar + 1);\n const next = rest.indexOf('|');\n const token = next < 0 ? null : rest.slice(0, next);\n if (token == null || !HEALTH_TOKEN_PATTERN.test(token))\n return { id, url: rest, healthToken: null, closeToken: null };\n const remaining = rest.slice(next + 1);\n const separator = remaining.indexOf('|');\n const closeToken = separator < 0 ? null : remaining.slice(0, separator);\n return closeToken != null && HEALTH_TOKEN_PATTERN.test(closeToken)\n ? { id, url: remaining.slice(separator + 1), healthToken: token, closeToken }\n : { id, url: remaining, healthToken: token, closeToken: null };\n};\n\nexport const transportForUrl = (url: string): AcpTransport.Ws | AcpTransport.Http =>\n /^wss?:\\/\\//.test(url) ? AcpTransport.Ws : AcpTransport.Http;\n\nconst httpUrlOf = (url: string): string =>\n url.replace(/^ws(s?):\\/\\//, (_match, secure) => `http${secure}://`);\n\n// Lifecycle routes are siblings of /acp, including a reverse proxy's path prefix.\nconst runtimeUrlFor = (args: { url: string; path: string }): string => {\n const endpoint = new URL(httpUrlOf(args.url));\n if (endpoint.pathname !== '/') endpoint.pathname = endpoint.pathname.replace(/\\/+$/, '');\n return new URL(args.path.replace(/^\\/+/, ''), endpoint).toString();\n};\n\nexport const healthUrlFor = (url: string): string => runtimeUrlFor({ url, path: 'healthz' });\n\nexport const programConfigUrlFor = (args: { url: string; id: string }): string =>\n runtimeUrlFor({ url: args.url, path: `${PROGRAM_CONFIGS_PATH}${encodeURIComponent(args.id)}` });\n\nexport const resolveSecretRef = async (args: {\n specifier: string;\n field: string;\n ref: SecretRefIface;\n secrets: SecretReaderIface;\n}): Promise<string> => {\n const value = await args.secrets.get(args.ref.secretKey);\n if (value == null || value.length === 0) {\n throw new Error(\n `${args.specifier}: secret '${args.ref.secretKey}' for ${args.field} is not bound`,\n );\n }\n return value;\n};\n\nexport const buildRemoteProgramConfig = (args: {\n spec: RemoteProgramSpecIface;\n open: OpenHarnessSessionArgsIface;\n}): RemoteProgramConfigIface => {\n const settings = args.spec.settings(args.open.config);\n const description = args.spec.description;\n // A capability bound to a resolved target routes there. One declared on the\n // harness host (`harnessHost`), or bound to a target a harness that cannot\n // route it ignores (not reboundable), runs natively on the host.\n const routesTargets = description.consumes.includes(SandboxWire.HandleRpc);\n const baseTools: RemoteProgramConfigIface['baseTools'] = {};\n for (const capability of Object.values(BaseCapability)) {\n const endpoint = args.open.baseTools[capability];\n const declaration = description.baseTools[capability];\n if (declaration == null) continue;\n if (endpoint != null) {\n baseTools[capability] = { provision: declaration.provision, target: endpoint.target };\n continue;\n }\n if (declaration.provision === BaseToolProvision.Bound) continue;\n const onHost = args.open.manifest.tools.host?.includes(capability) === true;\n const unroutedTarget = args.open.manifest.tools.base[capability] != null && !routesTargets;\n if (onHost || unroutedTarget) {\n baseTools[capability] = { provision: declaration.provision, target: null };\n }\n }\n const delivery = description.inference.delivery;\n const modelGrant = args.open.credentials.grants.find(\n (grant) => grant.route === CredentialRoute.Model,\n );\n // The broker's sandbox route renews sandbox endpoints; it accepts only this grant.\n const sandboxGrant = args.open.credentials.grants.find(\n (grant) => grant.route === CredentialRoute.Sandbox,\n );\n return {\n attachments: (() => {\n const grant = args.open.credentials.grants.find(\n (entry) => entry.route === CredentialRoute.Mcp,\n );\n return grant == null\n ? null\n : {\n url: `${args.open.credentials.brokerUrl.replace(/\\/+$/, '')}/attachment`,\n token: grant.token,\n };\n })(),\n version: 1,\n program: args.spec.program,\n cwd: settings.cwd,\n executable: settings.executable,\n model: settings.model,\n reasoning: settings.reasoning,\n permissionMode: settings.permissionMode,\n approvalPolicy: settings.approvalPolicy,\n sandboxMode: settings.sandboxMode,\n allowedTools: settings.allowedTools,\n instructions: settings.instructions\n .filter((fragment) => fragment.role === InstructionRole.System)\n .map((fragment) => ({ role: fragment.role, content: fragment.content })),\n skills: settings.skills,\n baseTools,\n sandboxes: Object.fromEntries(\n Object.entries(args.open.sandboxes).map(([target, endpoint]) => [\n target,\n {\n bindingId: endpoint.bindingId,\n capabilities: [...endpoint.capabilities],\n rpc: endpoint.rpc,\n mcp: endpoint.mcp,\n },\n ]),\n ),\n toolPolicy: { ...args.open.manifest.toolPolicy },\n // The harness's own login (`credentials.harness()`) is configured by its\n // user, not by Final: nothing is handed over and the CLI's settings apply.\n credentials:\n delivery === CredentialDelivery.AtOpen &&\n args.open.credentials.atOpen?.kind !== InferenceCredentialKind.HarnessOwned\n ? args.open.credentials.atOpen\n : null,\n broker:\n delivery === CredentialDelivery.PerRequest && modelGrant != null\n ? {\n url: args.open.credentials.brokerUrl,\n token: modelGrant.token,\n sandboxToken: sandboxGrant?.token ?? null,\n harnessSessionId: args.open.harnessSessionId,\n }\n : null,\n refresh: args.open.credentials.refresh,\n };\n};\n\nexport const createRemoteHarness = (\n spec: RemoteProgramSpecIface,\n config: RemoteHarnessFactoryConfigIface = {},\n): RemoteHarnessIface => {\n const fetchImpl = config.fetch ?? fetch;\n const fetchFor = (tls: HarnessClientTlsIface | undefined) =>\n tls == null ? fetchImpl : (config.tlsFetch?.(tls) ?? createNodeClientTlsFetch({ tls }));\n const now = config.now ?? Date.now;\n const healthTimeoutMs = config.healthTimeoutMs ?? DEFAULT_HEALTH_TIMEOUT_MS;\n const registerTimeoutMs = config.registerTimeoutMs ?? DEFAULT_REGISTER_TIMEOUT_MS;\n const clientTls = new Map<string, HarnessClientTlsIface>();\n\n // Registers the program config (fresh credentials included) under the\n // harness session's id; the runtime applies it to session/new and\n // session/resume on connections that name it.\n const register = async (args: {\n url: string;\n hop: string;\n id: string;\n open: OpenHarnessSessionArgsIface;\n tls?: HarnessClientTlsIface;\n }): Promise<void> => {\n const source = args.open.forkSource;\n const forkSource = source == null ? null : parseRemoteRef(source.ref.harnessSessionRef);\n if (\n source != null &&\n (!spec.description.supports.fork ||\n formatProviderRef(source.ref.harness) !== formatProviderRef(packageRef(spec.specifier)))\n )\n throw new Error(`${spec.specifier}: the source does not support this harness's native fork`);\n if (forkSource != null && (forkSource.id === args.id || forkSource.url !== args.url))\n throw new Error(\n `${spec.specifier}: a fork requires a distinct registration on the source host`,\n );\n const target = programConfigUrlFor({ url: args.url, id: args.id });\n const registration: JsonObject = {\n program: toJsonObject(buildRemoteProgramConfig({ spec, open: args.open })),\n };\n if (source != null && forkSource != null)\n registration['forkSource'] = {\n programConfigId: forkSource.id,\n sessionId: source.acpSessionId,\n childSessionId: args.open.session.sessionId,\n };\n let response: Response;\n try {\n response = await fetchFor(args.tls)(target, {\n method: 'PUT',\n headers: { authorization: `Bearer ${args.hop}`, 'content-type': 'application/json' },\n body: JSON.stringify(registration),\n signal: AbortSignal.timeout(registerTimeoutMs),\n });\n } catch (error) {\n throw new Error(\n `${spec.specifier}: registering the program config failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n const body = await response.text().catch(() => '');\n if (!response.ok) {\n const unavailable = unavailableOf(body);\n if (unavailable != null) throw RequestError.internalError(unavailable, unavailable.detail);\n throw new Error(\n `${spec.specifier}: the runtime refused the program config (HTTP ${response.status}) ${body.slice(0, 200)}`.trim(),\n );\n }\n };\n\n const endpointFor = async (args: {\n open: OpenHarnessSessionArgsIface;\n ref: HarnessSessionRefIface;\n }): Promise<HarnessEndpointIface> => {\n const settings = spec.settings(args.open.config);\n const hop = await resolveSecretRef({\n specifier: spec.specifier,\n field: 'hop',\n ref: settings.hop,\n secrets: args.open.secrets,\n });\n const { id } = parseRemoteRef(args.ref.harnessSessionRef);\n const tls = await resolveRemoteClientTls({\n config: settings.tls,\n secrets: args.open.secrets,\n url: settings.url,\n });\n await register({ url: settings.url, hop, id, open: args.open, tls });\n if (tls != null) clientTls.set(id, tls);\n else clientTls.delete(id);\n return {\n // Re-minted on every open and resume: a rotated hop or a legacy ref gets a current token.\n ref: {\n ...args.ref,\n harnessSessionRef: formatRemoteRef({\n id,\n url: settings.url,\n healthToken: healthTokenFor({ hop, id }),\n closeToken: closeTokenFor({ hop, id }),\n }),\n },\n transport: transportForUrl(settings.url),\n url: settings.url,\n tls,\n headers: { authorization: `Bearer ${hop}`, [PROGRAM_CONFIG_HEADER]: id },\n };\n };\n\n return {\n describe: async (binding) => {\n if (binding == null) return spec.description;\n const settings = spec.settings(binding.config);\n const hop = await resolveSecretRef({\n specifier: spec.specifier,\n field: 'hop',\n ref: settings.hop,\n secrets: binding.secrets,\n });\n const tls = await resolveRemoteClientTls({\n config: settings.tls,\n secrets: binding.secrets,\n url: settings.url,\n });\n const response = await fetchFor(tls)(\n runtimeUrlFor({ url: settings.url, path: 'v1/describe' }),\n {\n method: 'POST',\n headers: { authorization: `Bearer ${hop}`, 'content-type': 'application/json' },\n body: JSON.stringify({ program: { executable: settings.executable } }),\n signal: AbortSignal.timeout(registerTimeoutMs),\n },\n );\n const text = await response.text();\n if (!response.ok) {\n const unavailable = unavailableOf(text);\n if (unavailable != null) throw RequestError.internalError(unavailable, unavailable.detail);\n throw new Error(\n `${spec.specifier}: describe failed (HTTP ${response.status}) ${text.slice(0, 200)}`,\n );\n }\n const description = harnessDescriptionSchema.parse(JSON.parse(text));\n return {\n ...description,\n configSchema: spec.description.configSchema,\n trust: spec.description.trust,\n inference: spec.description.inference,\n consumes: spec.description.consumes,\n };\n },\n open: async (args) => {\n const ref: HarnessSessionRefIface = {\n harness: packageRef(spec.specifier),\n // endpointFor() completes the ref with the url and health token.\n harnessSessionRef: args.harnessSessionId,\n generation: 1,\n };\n return endpointFor({ open: args, ref });\n },\n // The runtime resumes the program's own session (Claude Code session, Codex\n // rollout); re-registering hands it the fresh grants.\n resume: async (args: ResumeHarnessSessionArgsIface) =>\n endpointFor({ open: args, ref: args.ref }),\n park: async () => undefined,\n close: async (ref, options) => {\n const { id, url: retainedUrl, closeToken } = parseRemoteRef(ref.harnessSessionRef);\n const context = options?.context;\n const settings = context == null ? null : spec.settings(context.config);\n const url = retainedUrl ?? settings?.url ?? null;\n if (url == null) {\n if (options?.force === true)\n throw new Error(`${spec.specifier}: the legacy ref must be resumed before forced close`);\n return;\n }\n const hop =\n context == null || settings == null\n ? null\n : await context.secrets.get(settings.hop.secretKey);\n const scopedToken = hop == null || hop.length === 0 ? closeToken : closeTokenFor({ hop, id });\n if (scopedToken == null) {\n if (options?.force === true)\n throw new Error(\n `${spec.specifier}: the legacy ref needs close context or resume before forced close`,\n );\n return;\n }\n const tls =\n context == null || settings == null\n ? clientTls.get(id)\n : await resolveRemoteClientTls({\n config: settings.tls,\n secrets: context.secrets,\n url,\n });\n const response = await fetchFor(tls)(programConfigUrlFor({ url, id }), {\n method: 'DELETE',\n headers: { [CLOSE_TOKEN_HEADER]: scopedToken, 'content-type': 'application/json' },\n body: JSON.stringify({ force: options?.force === true }),\n signal: AbortSignal.timeout(config.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS),\n });\n const body = await response.text();\n if (!response.ok && response.status !== 404)\n throw new Error(\n `${spec.specifier}: remote close failed (HTTP ${response.status}) ${body.slice(0, 200)}`,\n );\n clientTls.delete(id);\n },\n health: async (ref, context): Promise<HarnessHealthIface> => {\n const { id, url, healthToken } = parseRemoteRef(ref.harnessSessionRef);\n const checkedAt = new Date(now()).toISOString();\n if (url == null)\n return { ok: false, detail: 'harness session ref has no runtime url', checkedAt };\n try {\n const headers = new Headers({ [PROGRAM_CONFIG_HEADER]: id });\n if (healthToken != null) headers.set(HEALTH_TOKEN_HEADER, healthToken);\n const tls =\n context == null\n ? undefined\n : await resolveRemoteClientTls({\n config: spec.settings(context.config).tls,\n secrets: context.secrets,\n url,\n });\n const response = await fetchFor(tls)(healthUrlFor(url), {\n method: 'GET',\n headers,\n signal: AbortSignal.timeout(healthTimeoutMs),\n });\n const body = await response.text();\n const unavailable = response.ok ? null : unavailableOf(body);\n return response.ok\n ? { ok: true, checkedAt }\n : {\n ok: false,\n detail: unavailable?.detail ?? `healthz returned HTTP ${response.status}`,\n checkedAt,\n };\n } catch (error) {\n return {\n ok: false,\n detail: `healthz failed: ${error instanceof Error ? error.message : String(error)}`,\n checkedAt,\n };\n }\n },\n };\n};\nexport { REMOTE_URL_SCHEMES, remoteUrlJson, remoteUrlZod } from \"../harnesses/remote-url.mjs\";\n"],
|
|
4
|
+
"sourcesContent": ["import { RequestError } from '@agentclientprotocol/sdk/experimental/v2';\n\nimport {\n AcpTransport,\n BaseCapability,\n BaseToolProvision,\n CredentialDelivery,\n CredentialRoute,\n formatProviderRef,\n harnessDescriptionSchema,\n InferenceCredentialKind,\n InstructionRole,\n packageRef,\n SandboxWire,\n type HarnessClientTlsIface,\n type HarnessDescriptionIface,\n type HarnessEndpointIface,\n type HarnessHealthIface,\n type HarnessIface,\n type HarnessSessionRefIface,\n type InstructionFragmentIface,\n type JsonObject,\n type OpenHarnessSessionArgsIface,\n type ResumeHarnessSessionArgsIface,\n type SecretReaderIface,\n type SkillBundleIface,\n type ToolApproval,\n} from '@finalai/agent-provider';\n\nimport { createNodeClientTlsFetch } from '@finalai/websockets/node-client-tls';\n\nimport { createHmac } from 'node:crypto';\n\nimport * as z from 'zod';\n\nimport { toJsonObject, type SecretRefIface } from \"../harnesses/config-fields.mjs\";\n\nimport {\n resolveRemoteClientTls,\n type RemoteClientTlsInputIface,\n} from \"../harnesses/remote-client-tls.mjs\";\n\nconst unavailableSchema = z.object({\n code: z.literal('harness_unavailable'),\n executable: z.string(),\n foundVersion: z.string().nullable(),\n requiredVersion: z.string(),\n detail: z.string(),\n});\n\nconst unavailableOf = (text: string) => {\n try {\n return unavailableSchema.safeParse(JSON.parse(text)).data ?? null;\n } catch {\n return null;\n }\n};\n\nconst DEFAULT_HEALTH_TIMEOUT_MS = 5_000;\n\nconst DEFAULT_REGISTER_TIMEOUT_MS = 10_000;\n\nconst DEFAULT_CLOSE_TIMEOUT_MS = 15_000;\n\n// Authentication modes supported by remote harness servers.\nexport const PROGRAM_CONFIG_HEADER = 'x-final-program-config';\n\nexport const HEALTH_TOKEN_HEADER = 'x-final-health-token';\n\nexport const CLOSE_TOKEN_HEADER = 'x-final-close-token';\n\n// The runtime's registration-scoped health credential (HMAC of the registration id under the\n// hop token): health(ref) has no secrets, so open/resume put it in the ref instead of the hop.\nexport const healthTokenFor = (args: { hop: string; id: string }): string =>\n createHmac('sha256', args.hop).update(`final-harness-health:${args.id}`).digest('base64url');\n\nexport const closeTokenFor = (args: { hop: string; id: string }): string =>\n createHmac('sha256', args.hop).update(`final-harness-close:${args.id}`).digest('base64url');\n\nconst PROGRAM_CONFIGS_PATH = '/v1/program-configs/';\n\nexport enum RemoteProgram {\n ClaudeCode = 'claude-code',\n Codex = 'codex',\n Pi = 'pi',\n}\n\nexport interface RemoteHarnessFactoryConfigIface {\n fetch?: typeof fetch;\n tlsFetch?: (tls: HarnessClientTlsIface) => typeof fetch;\n // Test seams.\n now?: () => number;\n newId?: () => string;\n healthTimeoutMs?: number;\n registerTimeoutMs?: number;\n closeTimeoutMs?: number;\n}\n\nexport interface RemoteSettingsIface {\n url: string;\n tls: RemoteClientTlsInputIface | null;\n hop: SecretRefIface;\n cwd: string | null;\n executable: string | null;\n model: string | null;\n reasoning: string | null;\n permissionMode: string | null;\n approvalPolicy: string | null;\n sandboxMode: string | null;\n allowedTools: string[] | null;\n instructions: InstructionFragmentIface[];\n skills: SkillBundleIface[];\n}\n\nexport interface RemoteProgramSpecIface {\n specifier: string;\n program: RemoteProgram;\n description: HarnessDescriptionIface;\n settings: (config: OpenHarnessSessionArgsIface['config']) => RemoteSettingsIface;\n}\n\n// The provider-private program config this harness registers with the runtime\n// Remote harness program configuration, version 1.\n// `credentials`, `broker` and `refresh` carry route grants (and, for at-open\n// harnesses, the resolved model credential); they travel only between this\n// provider and the runtime, over the hop-authenticated registration.\nexport interface RemoteProgramConfigIface {\n version: 1;\n program: RemoteProgram;\n // Absolute path on the runtime host; null = the runtime's own working directory.\n cwd: string | null;\n executable: string | null;\n model: string | null;\n reasoning: string | null;\n permissionMode: string | null;\n approvalPolicy: string | null;\n sandboxMode: string | null;\n allowedTools: string[] | null;\n // System fragments only; user fragments arrive as _final/session/observe.\n instructions: Pick<InstructionFragmentIface, 'role' | 'content'>[];\n skills: SkillBundleIface[];\n // Declared capabilities this harness provides, with the target a bound one\n // routes to; null runs it natively on the host. A host-disableable capability\n // absent here must be disabled through the program's own allow-lists.\n baseTools: Record<string, { provision: BaseToolProvision; target: string | null }>;\n sandboxes: Record<\n string,\n {\n bindingId: string;\n capabilities: string[];\n rpc: { url: string; token: string; expiresAt: string } | null;\n mcp: { url: string; token: string; expiresAt: string } | null;\n }\n >;\n toolPolicy: Record<string, ToolApproval>;\n attachments: { url: string; token: string } | null;\n // In the remote program configuration, the model credential\n // handed over at open (claude-code, codex), or the broker `model` route grant\n // for per-request programs (pi), which post to `<broker.url>/model`.\n credentials: OpenHarnessSessionArgsIface['credentials']['atOpen'];\n // `sandboxToken` is the broker `sandbox` route grant, for renewing sandbox endpoints.\n broker: {\n url: string;\n token: string;\n sandboxToken: string | null;\n harnessSessionId: string;\n } | null;\n // The grant's standard refresh route: the runtime pulls the next generation\n // of `credentials` and `broker` from it before they expire.\n refresh: OpenHarnessSessionArgsIface['credentials']['refresh'];\n}\n\nexport type RemoteOpenArgsIface = OpenHarnessSessionArgsIface;\n\nexport type RemoteHarnessIface = HarnessIface;\n\n// Scoped capabilities survive a session-service restart without retaining the hop or TLS keys.\nexport const formatRemoteRef = (args: {\n id: string;\n url: string;\n healthToken: string | null;\n closeToken?: string | null;\n}): string =>\n args.closeToken != null && args.healthToken != null\n ? `${args.id}|${args.healthToken}|${args.closeToken}|${args.url}`\n : args.healthToken == null\n ? `${args.id}|${args.url}`\n : `${args.id}|${args.healthToken}|${args.url}`;\n\nconst HEALTH_TOKEN_PATTERN = /^[A-Za-z0-9_-]{43}$/u;\n\nexport interface RemoteRefIface {\n id: string;\n url: string | null;\n healthToken: string | null;\n closeToken: string | null;\n}\n\nexport const parseRemoteRef = (ref: string): RemoteRefIface => {\n const bar = ref.indexOf('|');\n if (bar < 0) return { id: ref, url: null, healthToken: null, closeToken: null };\n const id = ref.slice(0, bar);\n const rest = ref.slice(bar + 1);\n const next = rest.indexOf('|');\n const token = next < 0 ? null : rest.slice(0, next);\n if (token == null || !HEALTH_TOKEN_PATTERN.test(token))\n return { id, url: rest, healthToken: null, closeToken: null };\n const remaining = rest.slice(next + 1);\n const separator = remaining.indexOf('|');\n const closeToken = separator < 0 ? null : remaining.slice(0, separator);\n return closeToken != null && HEALTH_TOKEN_PATTERN.test(closeToken)\n ? { id, url: remaining.slice(separator + 1), healthToken: token, closeToken }\n : { id, url: remaining, healthToken: token, closeToken: null };\n};\n\nexport const transportForUrl = (url: string): AcpTransport.Ws | AcpTransport.Http =>\n /^wss?:\\/\\//.test(url) ? AcpTransport.Ws : AcpTransport.Http;\n\nconst httpUrlOf = (url: string): string =>\n url.replace(/^ws(s?):\\/\\//, (_match, secure) => `http${secure}://`);\n\n// Lifecycle routes are siblings of /acp, including a reverse proxy's path prefix.\nconst runtimeUrlFor = (args: { url: string; path: string }): string => {\n const endpoint = new URL(httpUrlOf(args.url));\n if (endpoint.pathname !== '/') endpoint.pathname = endpoint.pathname.replace(/\\/+$/, '');\n return new URL(args.path.replace(/^\\/+/, ''), endpoint).toString();\n};\n\nexport const healthUrlFor = (url: string): string => runtimeUrlFor({ url, path: 'healthz' });\n\nexport const programConfigUrlFor = (args: { url: string; id: string }): string =>\n runtimeUrlFor({ url: args.url, path: `${PROGRAM_CONFIGS_PATH}${encodeURIComponent(args.id)}` });\n\nexport const resolveSecretRef = async (args: {\n specifier: string;\n field: string;\n ref: SecretRefIface;\n secrets: SecretReaderIface;\n}): Promise<string> => {\n const value = await args.secrets.get(args.ref.secretKey);\n if (value == null || value.length === 0) {\n throw new Error(\n `${args.specifier}: secret '${args.ref.secretKey}' for ${args.field} is not bound`,\n );\n }\n return value;\n};\n\nexport const buildRemoteProgramConfig = (args: {\n spec: RemoteProgramSpecIface;\n open: OpenHarnessSessionArgsIface;\n}): RemoteProgramConfigIface => {\n const settings = args.spec.settings(args.open.config);\n const description = args.spec.description;\n // A capability bound to a resolved target routes there. One declared on the\n // harness host (`harnessHost`), or bound to a target a harness that cannot\n // route it ignores (not reboundable), runs natively on the host.\n const routesTargets = description.consumes.includes(SandboxWire.HandleRpc);\n const baseTools: RemoteProgramConfigIface['baseTools'] = {};\n for (const capability of Object.values(BaseCapability)) {\n const endpoint = args.open.baseTools[capability];\n const declaration = description.baseTools[capability];\n if (declaration == null) continue;\n if (endpoint != null) {\n baseTools[capability] = { provision: declaration.provision, target: endpoint.target };\n continue;\n }\n if (declaration.provision === BaseToolProvision.Bound) continue;\n const onHost = args.open.manifest.tools.host?.includes(capability) === true;\n const unroutedTarget = args.open.manifest.tools.base[capability] != null && !routesTargets;\n if (onHost || unroutedTarget) {\n baseTools[capability] = { provision: declaration.provision, target: null };\n }\n }\n const delivery = description.inference.delivery;\n const modelGrant = args.open.credentials.grants.find(\n (grant) => grant.route === CredentialRoute.Model,\n );\n // The broker's sandbox route renews sandbox endpoints; it accepts only this grant.\n const sandboxGrant = args.open.credentials.grants.find(\n (grant) => grant.route === CredentialRoute.Sandbox,\n );\n return {\n attachments: (() => {\n const grant = args.open.credentials.grants.find(\n (entry) => entry.route === CredentialRoute.Mcp,\n );\n return grant == null\n ? null\n : {\n url: `${args.open.credentials.brokerUrl.replace(/\\/+$/, '')}/attachment`,\n token: grant.token,\n };\n })(),\n version: 1,\n program: args.spec.program,\n cwd: settings.cwd,\n executable: settings.executable,\n model: settings.model,\n reasoning: settings.reasoning,\n permissionMode: settings.permissionMode,\n approvalPolicy: settings.approvalPolicy,\n sandboxMode: settings.sandboxMode,\n allowedTools: settings.allowedTools,\n instructions: settings.instructions\n .filter((fragment) => fragment.role === InstructionRole.System)\n .map((fragment) => ({ role: fragment.role, content: fragment.content })),\n skills: settings.skills,\n baseTools,\n sandboxes: Object.fromEntries(\n Object.entries(args.open.sandboxes).map(([target, endpoint]) => [\n target,\n {\n bindingId: endpoint.bindingId,\n capabilities: [...endpoint.capabilities],\n rpc: endpoint.rpc,\n mcp: endpoint.mcp,\n },\n ]),\n ),\n toolPolicy: { ...args.open.manifest.toolPolicy },\n // The harness's own login (`credentials.harness()`) is configured by its\n // user, not by Final: nothing is handed over and the CLI's settings apply.\n credentials:\n delivery === CredentialDelivery.AtOpen &&\n args.open.credentials.atOpen?.kind !== InferenceCredentialKind.HarnessOwned\n ? args.open.credentials.atOpen\n : null,\n broker:\n delivery === CredentialDelivery.PerRequest && modelGrant != null\n ? {\n url: args.open.credentials.brokerUrl,\n token: modelGrant.token,\n sandboxToken: sandboxGrant?.token ?? null,\n harnessSessionId: args.open.harnessSessionId,\n }\n : null,\n refresh: args.open.credentials.refresh,\n };\n};\n\nexport const createRemoteHarness = (\n spec: RemoteProgramSpecIface,\n config: RemoteHarnessFactoryConfigIface = {},\n): RemoteHarnessIface => {\n const fetchImpl = config.fetch ?? fetch;\n const fetchFor = (tls: HarnessClientTlsIface | undefined) =>\n tls == null ? fetchImpl : (config.tlsFetch?.(tls) ?? createNodeClientTlsFetch({ tls }));\n const now = config.now ?? Date.now;\n const healthTimeoutMs = config.healthTimeoutMs ?? DEFAULT_HEALTH_TIMEOUT_MS;\n const registerTimeoutMs = config.registerTimeoutMs ?? DEFAULT_REGISTER_TIMEOUT_MS;\n const clientTls = new Map<string, HarnessClientTlsIface>();\n\n // Registers the program config (fresh credentials included) under the\n // harness session's id; the runtime applies it to session/new and\n // session/resume on connections that name it.\n const register = async (args: {\n url: string;\n hop: string;\n id: string;\n open: OpenHarnessSessionArgsIface;\n tls?: HarnessClientTlsIface;\n }): Promise<void> => {\n const source = args.open.forkSource;\n const forkSource = source == null ? null : parseRemoteRef(source.ref.harnessSessionRef);\n if (\n source != null &&\n (!spec.description.supports.fork ||\n formatProviderRef(source.ref.harness) !== formatProviderRef(packageRef(spec.specifier)))\n )\n throw new Error(`${spec.specifier}: the source does not support this harness's native fork`);\n if (forkSource != null && (forkSource.id === args.id || forkSource.url !== args.url))\n throw new Error(\n `${spec.specifier}: a fork requires a distinct registration on the source host`,\n );\n const target = programConfigUrlFor({ url: args.url, id: args.id });\n const registration: JsonObject = {\n program: toJsonObject(buildRemoteProgramConfig({ spec, open: args.open })),\n };\n if (source != null && forkSource != null)\n registration['forkSource'] = {\n programConfigId: forkSource.id,\n sessionId: source.acpSessionId,\n childSessionId: args.open.session.sessionId,\n };\n let response: Response;\n try {\n response = await fetchFor(args.tls)(target, {\n method: 'PUT',\n headers: { authorization: `Bearer ${args.hop}`, 'content-type': 'application/json' },\n body: JSON.stringify(registration),\n signal: AbortSignal.timeout(registerTimeoutMs),\n });\n } catch (error) {\n throw new Error(\n `${spec.specifier}: registering the program config failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n const body = await response.text().catch(() => '');\n if (!response.ok) {\n const unavailable = unavailableOf(body);\n if (unavailable != null) throw RequestError.internalError(unavailable, unavailable.detail);\n throw new Error(\n `${spec.specifier}: the runtime refused the program config (HTTP ${response.status}) ${body.slice(0, 200)}`.trim(),\n );\n }\n };\n\n const endpointFor = async (args: {\n open: OpenHarnessSessionArgsIface;\n ref: HarnessSessionRefIface;\n }): Promise<HarnessEndpointIface> => {\n const settings = spec.settings(args.open.config);\n const hop = await resolveSecretRef({\n specifier: spec.specifier,\n field: 'hop',\n ref: settings.hop,\n secrets: args.open.secrets,\n });\n const { id } = parseRemoteRef(args.ref.harnessSessionRef);\n const tls = await resolveRemoteClientTls({\n config: settings.tls,\n secrets: args.open.secrets,\n url: settings.url,\n });\n await register({ url: settings.url, hop, id, open: args.open, tls });\n if (tls != null) clientTls.set(id, tls);\n else clientTls.delete(id);\n return {\n // Re-minted on every open and resume: a rotated hop or a legacy ref gets a current token.\n ref: {\n ...args.ref,\n harnessSessionRef: formatRemoteRef({\n id,\n url: settings.url,\n healthToken: healthTokenFor({ hop, id }),\n closeToken: closeTokenFor({ hop, id }),\n }),\n },\n transport: transportForUrl(settings.url),\n url: settings.url,\n tls,\n headers: { authorization: `Bearer ${hop}`, [PROGRAM_CONFIG_HEADER]: id },\n };\n };\n\n return {\n describe: async (binding) => {\n if (binding == null) return spec.description;\n const settings = spec.settings(binding.config);\n const hop = await resolveSecretRef({\n specifier: spec.specifier,\n field: 'hop',\n ref: settings.hop,\n secrets: binding.secrets,\n });\n const tls = await resolveRemoteClientTls({\n config: settings.tls,\n secrets: binding.secrets,\n url: settings.url,\n });\n const response = await fetchFor(tls)(\n runtimeUrlFor({ url: settings.url, path: 'v1/describe' }),\n {\n method: 'POST',\n headers: { authorization: `Bearer ${hop}`, 'content-type': 'application/json' },\n body: JSON.stringify({ program: { executable: settings.executable } }),\n signal: AbortSignal.timeout(registerTimeoutMs),\n },\n );\n const text = await response.text();\n if (!response.ok) {\n const unavailable = unavailableOf(text);\n if (unavailable != null) throw RequestError.internalError(unavailable, unavailable.detail);\n throw new Error(\n `${spec.specifier}: describe failed (HTTP ${response.status}) ${text.slice(0, 200)}`,\n );\n }\n const description = harnessDescriptionSchema.parse(JSON.parse(text));\n return {\n ...description,\n configSchema: spec.description.configSchema,\n trust: spec.description.trust,\n inference: spec.description.inference,\n consumes: spec.description.consumes,\n };\n },\n open: async (args) => {\n const ref: HarnessSessionRefIface = {\n harness: packageRef(spec.specifier),\n // endpointFor() completes the ref with the url and health token.\n harnessSessionRef: args.harnessSessionId,\n generation: 1,\n };\n return endpointFor({ open: args, ref });\n },\n // The runtime resumes the program's own session (Claude Code session, Codex\n // rollout); re-registering hands it the fresh grants.\n resume: async (args: ResumeHarnessSessionArgsIface) =>\n endpointFor({ open: args, ref: args.ref }),\n park: async () => undefined,\n close: async (ref, options) => {\n const { id, url: retainedUrl, closeToken } = parseRemoteRef(ref.harnessSessionRef);\n const context = options?.context;\n const settings = context == null ? null : spec.settings(context.config);\n const url = retainedUrl ?? settings?.url ?? null;\n if (url == null) {\n if (options?.force === true)\n throw new Error(`${spec.specifier}: the legacy ref must be resumed before forced close`);\n return;\n }\n const hop =\n context == null || settings == null\n ? null\n : await context.secrets.get(settings.hop.secretKey);\n const scopedToken = hop == null || hop.length === 0 ? closeToken : closeTokenFor({ hop, id });\n if (scopedToken == null) {\n if (options?.force === true)\n throw new Error(\n `${spec.specifier}: the legacy ref needs close context or resume before forced close`,\n );\n return;\n }\n const tls =\n context == null || settings == null\n ? clientTls.get(id)\n : await resolveRemoteClientTls({\n config: settings.tls,\n secrets: context.secrets,\n url,\n });\n const response = await fetchFor(tls)(programConfigUrlFor({ url, id }), {\n method: 'DELETE',\n headers: { [CLOSE_TOKEN_HEADER]: scopedToken, 'content-type': 'application/json' },\n body: JSON.stringify({ force: options?.force === true }),\n signal: AbortSignal.timeout(config.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS),\n });\n const body = await response.text();\n if (!response.ok && response.status !== 404)\n throw new Error(\n `${spec.specifier}: remote close failed (HTTP ${response.status}) ${body.slice(0, 200)}`,\n );\n clientTls.delete(id);\n },\n health: async (ref, context): Promise<HarnessHealthIface> => {\n const { id, url, healthToken } = parseRemoteRef(ref.harnessSessionRef);\n const checkedAt = new Date(now()).toISOString();\n if (url == null)\n return { ok: false, detail: 'harness session ref has no runtime url', checkedAt };\n try {\n const headers = new Headers({ [PROGRAM_CONFIG_HEADER]: id });\n if (healthToken != null) headers.set(HEALTH_TOKEN_HEADER, healthToken);\n const tls =\n context == null\n ? undefined\n : await resolveRemoteClientTls({\n config: spec.settings(context.config).tls,\n secrets: context.secrets,\n url,\n });\n const response = await fetchFor(tls)(healthUrlFor(url), {\n method: 'GET',\n headers,\n signal: AbortSignal.timeout(healthTimeoutMs),\n });\n const body = await response.text();\n const unavailable = response.ok ? null : unavailableOf(body);\n return response.ok\n ? { ok: true, checkedAt }\n : {\n ok: false,\n detail: unavailable?.detail ?? `healthz returned HTTP ${response.status}`,\n checkedAt,\n };\n } catch (error) {\n return {\n ok: false,\n detail: `healthz failed: ${error instanceof Error ? error.message : String(error)}`,\n checkedAt,\n };\n }\n },\n };\n};\nexport { REMOTE_URL_SCHEMES, remoteUrlJson, remoteUrlZod } from \"../harnesses/remote-url.mjs\";\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["RemoteProgram"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/build-scripts.ts"],
|
|
4
|
-
"sourcesContent": ["import { shellQuote } from \"./paths.mjs\";\n\n// The template builder's check that a guide build leaves nothing under /home or\n// /workspaces: a computer's user volume is mounted over both, so anything a build\n// step put there (~/.cargo, ~/.local, a clone in /workspaces) is hidden at run\n// time. Home content belongs in /usr/share/final-vm/home-skel\n//
|
|
4
|
+
"sourcesContent": ["import { shellQuote } from \"./paths.mjs\";\n\n// The template builder's check that a guide build leaves nothing under /home or\n// /workspaces: a computer's user volume is mounted over both, so anything a build\n// step put there (~/.cargo, ~/.local, a clone in /workspaces) is hidden at run\n// time. Home content belongs in /usr/share/final-vm/home-skel\n// so it remains available when the user volume is mounted.\n\nexport const HOME_SKELETON_ROOT = '/usr/share/final-vm/home-skel';\nexport const USER_VOLUME_ROOTS = ['/home', '/workspaces'];\n// Under /var/tmp, which the pre-clean and the capture scrub both remove.\nexport const HOME_BASELINE_ROOT = '/var/tmp/final-template-build/home-baseline';\nexport const HOME_CONTENT_LIMIT = 50;\nexport const HOME_BASELINE_MISSING_EXIT_CODE = 3;\n\nexport interface HomeContentScriptOptionsIface {\n // Paths the runner stages or the capture scrub removes; skipped with their subtrees.\n excludedPaths: string[];\n roots?: string[];\n homeRoot?: string;\n skeletonRoot?: string;\n baselineRoot?: string;\n}\n\nconst volumePathPrefixes = (roots: string[]): string[] => roots.map((root) => `${root}/`);\n\n// Snapshot of what the platform put under /home and /workspaces before any build\n// step ran, such as the guest agent's home marker.\nexport const homeBaselineScript = (\n args: { roots?: string[]; baselineRoot?: string } = {},\n): string => {\n const roots = args.roots ?? USER_VOLUME_ROOTS;\n const baselineRoot = shellQuote(args.baselineRoot ?? HOME_BASELINE_ROOT);\n return `\nset -eu\nrm -rf ${baselineRoot}\nmkdir -p ${baselineRoot}\nfor root in ${roots.map(shellQuote).join(' ')}; do\n if [ -d \"$root\" ]; then\n mkdir -p ${baselineRoot}\"$(dirname \"$root\")\"\n cp -PRp \"$root\" ${baselineRoot}\"$root\" 2>/dev/null || true\n fi\ndone\n`;\n};\n\n// A VM's user volume is mounted over /home/user and /workspaces, so the layer\n// must leave nothing there. Prints up to 50 entries the build steps created or\n// changed that neither the home skeleton nor the pre-build baseline has. A\n// directory neither has is reported once, when it holds anything but directories.\nexport const homeContentScript = (options: HomeContentScriptOptionsIface): string => {\n const roots = options.roots ?? USER_VOLUME_ROOTS;\n const homeRoot = options.homeRoot ?? '/home/user';\n const skeletonRoot = options.skeletonRoot ?? HOME_SKELETON_ROOT;\n const baselineRoot = options.baselineRoot ?? HOME_BASELINE_ROOT;\n const excluded = options.excludedPaths.filter((path) =>\n volumePathPrefixes(roots).some((prefix) => path.startsWith(prefix)),\n );\n const prune =\n excluded.length === 0\n ? ''\n : `\\\\( ${excluded.map((path) => `-path ${shellQuote(path)}`).join(' -o ')} \\\\) -prune -o`;\n return `\nset -u\nif [ ! -d ${shellQuote(baselineRoot)} ]; then\n echo \"the pre-build home baseline ${baselineRoot} is missing\"\n exit ${HOME_BASELINE_MISSING_EXIT_CODE}\nfi\nsame_entry() {\n if [ -L \"$1\" ]; then\n [ -L \"$2\" ] && [ \"$(readlink \"$1\")\" = \"$(readlink \"$2\")\" ]\n return\n fi\n if [ -L \"$2\" ]; then\n return 1\n fi\n if [ -d \"$1\" ]; then\n [ -d \"$2\" ]\n return\n fi\n [ -f \"$1\" ] && [ -f \"$2\" ] && cmp -s \"$1\" \"$2\"\n}\nhome_root=${shellQuote(homeRoot)}\nskeleton_root=${shellQuote(skeletonRoot)}\nskeleton_entry() {\n case \"$1\" in\n (\"$home_root\") printf '%s\\\\n' \"$skeleton_root\" ;;\n (\"$home_root\"/*) printf '%s/%s\\\\n' \"$skeleton_root\" \"\\${1#\"$home_root\"/}\" ;;\n (*) printf '%s\\\\n' /nonexistent/final-home-skeleton-entry ;;\n esac\n}\nhas_content() {\n if [ ! -r \"$1\" ] || [ ! -x \"$1\" ]; then\n return 0\n fi\n [ -n \"$(find \"$1\" -xdev -mindepth 1 ${prune} ! -type d -print 2>/dev/null | head -n 1)\" ]\n}\nscan() {\n reported=''\n find ${roots.map(shellQuote).join(' ')} -xdev -mindepth 1 ${prune} -print 2>/dev/null | while IFS= read -r path; do\n if [ -n \"$reported\" ]; then\n case \"$path\" in\n (\"$reported\"/*) continue ;;\n esac\n fi\n if same_entry \"$path\" \"$(skeleton_entry \"$path\")\" || same_entry \"$path\" ${shellQuote(baselineRoot)}\"$path\"; then\n continue\n fi\n if [ -d \"$path\" ] && [ ! -L \"$path\" ]; then\n if ! has_content \"$path\"; then\n continue\n fi\n reported=\"$path\"\n fi\n printf '%s\\\\n' \"$path\"\n done\n}\nhidden=\"$(scan | head -n ${HOME_CONTENT_LIMIT})\"\nif [ -n \"$hidden\" ]; then\n printf '%s\\\\n' \"$hidden\"\n exit 1\nfi\n`;\n};\n"],
|
|
5
5
|
"mappings": "AAAA,SAAS,kBAAkB;AAQpB,MAAM,qBAAqB;AAC3B,MAAM,oBAAoB,CAAC,SAAS,aAAa;AAEjD,MAAM,qBAAqB;AAC3B,MAAM,qBAAqB;AAC3B,MAAM,kCAAkC;AAW/C,MAAM,qBAAqB,CAAC,UAA8B,MAAM,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG;AAIjF,MAAM,qBAAqB,CAChC,OAAoD,CAAC,MAC1C;AACX,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,eAAe,WAAW,KAAK,gBAAgB,kBAAkB;AACvE,SAAO;AAAA;AAAA,SAEA,YAAY;AAAA,WACV,YAAY;AAAA,cACT,MAAM,IAAI,UAAU,EAAE,KAAK,GAAG,CAAC;AAAA;AAAA,eAE9B,YAAY;AAAA,sBACL,YAAY;AAAA;AAAA;AAAA;AAIlC;AAMO,MAAM,oBAAoB,CAAC,YAAmD;AACnF,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,WAAW,QAAQ,cAAc;AAAA,IAAO,CAAC,SAC7C,mBAAmB,KAAK,EAAE,KAAK,CAAC,WAAW,KAAK,WAAW,MAAM,CAAC;AAAA,EACpE;AACA,QAAM,QACJ,SAAS,WAAW,IAChB,KACA,OAAO,SAAS,IAAI,CAAC,SAAS,SAAS,WAAW,IAAI,CAAC,EAAE,EAAE,KAAK,MAAM,CAAC;AAC7E,SAAO;AAAA;AAAA,YAEG,WAAW,YAAY,CAAC;AAAA,sCACE,YAAY;AAAA,SACzC,+BAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAgB5B,WAAW,QAAQ,CAAC;AAAA,gBAChB,WAAW,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAYA,KAAK;AAAA;AAAA;AAAA;AAAA,SAIpC,MAAM,IAAI,UAAU,EAAE,KAAK,GAAG,CAAC,sBAAsB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8EAMW,WAAW,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAY3E,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAM7C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/paths.ts"],
|
|
4
|
-
"sourcesContent": ["import { quoteShellArgument } from '@finalai/computers/shell';\nimport { posix, win32 } from 'node:path';\n\n// Sandbox paths, by the sandbox's platform: computers and Unix Devices are\n// POSIX; a Windows Device's workspace is a drive path (`C:\\
|
|
4
|
+
"sourcesContent": ["import { quoteShellArgument } from '@finalai/computers/shell';\nimport { posix, win32 } from 'node:path';\n\n// Sandbox paths, by the sandbox's platform: computers and Unix Devices are\n// POSIX; a Windows Device's workspace is a drive path (`C:\\workspaces\\chat`).\n// Resolving with the wrong flavour turns the root into a relative path under this\n// process's cwd, so every operation would land outside the workspace.\n\nexport enum SandboxPlatform {\n Posix = 'posix',\n Windows = 'windows',\n}\n\nexport interface SandboxPathsIface {\n readonly platform: SandboxPlatform;\n readonly separator: string;\n // Absolute, normalized, without a trailing separator (except a root).\n resolve(root: string, path: string): string;\n join(...parts: string[]): string;\n dirname(path: string): string;\n basename(path: string): string;\n // Whether `path` is `root` or below it.\n isWithin(root: string, path: string): boolean;\n}\n\nconst posixPaths: SandboxPathsIface = {\n platform: SandboxPlatform.Posix,\n separator: '/',\n resolve: (root, path) => {\n const resolved = posix.resolve(root, path);\n return resolved === '/' ? resolved : resolved.replace(/\\/+$/, '');\n },\n join: (...parts) => posix.join(...parts),\n dirname: (path) => posix.dirname(path),\n basename: (path) => posix.basename(path),\n isWithin: (root, path) => {\n const relative = posix.relative(root, path);\n return (\n relative === '' ||\n (relative !== '..' && !relative.startsWith('../') && !posix.isAbsolute(relative))\n );\n },\n};\n\nconst DRIVE_ROOT = /^[A-Za-z]:\\\\$/;\n\n// `\\\\server\\share` and `\\\\?\\` / `\\\\.\\` device paths.\nexport const isUncPath = (path: string): boolean => /^[\\\\/]{2}/.test(path);\n\nexport const isWindowsDrivePath = (path: string): boolean => /^[A-Za-z]:[\\\\/]/.test(path);\n\nconst refuseUnc = (path: string): string => {\n if (isUncPath(path))\n throw new Error(`UNC paths are not supported in a Device workspace: ${path}`);\n return path;\n};\n\nconst windowsPaths: SandboxPathsIface = {\n platform: SandboxPlatform.Windows,\n separator: '\\\\',\n resolve: (root, path) => {\n refuseUnc(path);\n const resolved = refuseUnc(win32.resolve(refuseUnc(root), path));\n return DRIVE_ROOT.test(resolved) ? resolved : resolved.replace(/\\\\+$/, '');\n },\n join: (...parts) => win32.join(...parts),\n dirname: (path) => win32.dirname(path),\n basename: (path) => win32.basename(path),\n // win32.relative compares case-insensitively and across separators; a\n // different drive comes back absolute.\n isWithin: (root, path) => {\n if (isUncPath(root) || isUncPath(path)) return false;\n const relative = win32.relative(root, path);\n return (\n relative === '' ||\n (relative !== '..' && !relative.startsWith('..\\\\') && !win32.isAbsolute(relative))\n );\n },\n};\n\nexport const sandboxPathsFor = (platform: SandboxPlatform): SandboxPathsIface =>\n platform === SandboxPlatform.Windows ? windowsPaths : posixPaths;\n\n// A platform a Device did not report, from the shape of its workspace root.\nexport const platformOfRoot = (root: string): SandboxPlatform =>\n isWindowsDrivePath(root) || isUncPath(root) ? SandboxPlatform.Windows : SandboxPlatform.Posix;\n\nexport const POSIX_PATHS = posixPaths;\n\n// Preserve arguments through both POSIX shells and a Unix Device's fish shell.\nexport const shellQuote = quoteShellArgument;\n"],
|
|
5
5
|
"mappings": "AAAA,SAAS,0BAA0B;AACnC,SAAS,OAAO,aAAa;AAOtB,IAAK,kBAAL,kBAAKA,qBAAL;AACL,EAAAA,iBAAA,WAAQ;AACR,EAAAA,iBAAA,aAAU;AAFA,SAAAA;AAAA,GAAA;AAiBZ,MAAM,aAAgC;AAAA,EACpC,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS,CAAC,MAAM,SAAS;AACvB,UAAM,WAAW,MAAM,QAAQ,MAAM,IAAI;AACzC,WAAO,aAAa,MAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAAA,EAClE;AAAA,EACA,MAAM,IAAI,UAAU,MAAM,KAAK,GAAG,KAAK;AAAA,EACvC,SAAS,CAAC,SAAS,MAAM,QAAQ,IAAI;AAAA,EACrC,UAAU,CAAC,SAAS,MAAM,SAAS,IAAI;AAAA,EACvC,UAAU,CAAC,MAAM,SAAS;AACxB,UAAM,WAAW,MAAM,SAAS,MAAM,IAAI;AAC1C,WACE,aAAa,MACZ,aAAa,QAAQ,CAAC,SAAS,WAAW,KAAK,KAAK,CAAC,MAAM,WAAW,QAAQ;AAAA,EAEnF;AACF;AAEA,MAAM,aAAa;AAGZ,MAAM,YAAY,CAAC,SAA0B,YAAY,KAAK,IAAI;AAElE,MAAM,qBAAqB,CAAC,SAA0B,kBAAkB,KAAK,IAAI;AAExF,MAAM,YAAY,CAAC,SAAyB;AAC1C,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI,MAAM,sDAAsD,IAAI,EAAE;AAC9E,SAAO;AACT;AAEA,MAAM,eAAkC;AAAA,EACtC,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS,CAAC,MAAM,SAAS;AACvB,cAAU,IAAI;AACd,UAAM,WAAW,UAAU,MAAM,QAAQ,UAAU,IAAI,GAAG,IAAI,CAAC;AAC/D,WAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAAA,EAC3E;AAAA,EACA,MAAM,IAAI,UAAU,MAAM,KAAK,GAAG,KAAK;AAAA,EACvC,SAAS,CAAC,SAAS,MAAM,QAAQ,IAAI;AAAA,EACrC,UAAU,CAAC,SAAS,MAAM,SAAS,IAAI;AAAA;AAAA;AAAA,EAGvC,UAAU,CAAC,MAAM,SAAS;AACxB,QAAI,UAAU,IAAI,KAAK,UAAU,IAAI,EAAG,QAAO;AAC/C,UAAM,WAAW,MAAM,SAAS,MAAM,IAAI;AAC1C,WACE,aAAa,MACZ,aAAa,QAAQ,CAAC,SAAS,WAAW,MAAM,KAAK,CAAC,MAAM,WAAW,QAAQ;AAAA,EAEpF;AACF;AAEO,MAAM,kBAAkB,CAAC,aAC9B,aAAa,0BAA0B,eAAe;AAGjD,MAAM,iBAAiB,CAAC,SAC7B,mBAAmB,IAAI,KAAK,UAAU,IAAI,IAAI,0BAA0B;AAEnE,MAAM,cAAc;AAGpB,MAAM,aAAa;",
|
|
6
6
|
"names": ["SandboxPlatform"]
|
|
7
7
|
}
|
|
@@ -84,14 +84,14 @@ const openArgs = (config, secrets = {}) => ({
|
|
|
84
84
|
},
|
|
85
85
|
sandboxes: { computer: computerEndpoint, device: deviceEndpoint },
|
|
86
86
|
credentials: {
|
|
87
|
-
brokerUrl: "https://
|
|
87
|
+
brokerUrl: "https://credentials.example.com/provider",
|
|
88
88
|
grants: [
|
|
89
89
|
{ route: CredentialRoute.Model, token: "grant-model", expiresAt: EXPIRES_AT },
|
|
90
90
|
{ route: CredentialRoute.Mcp, token: "grant-mcp", expiresAt: EXPIRES_AT }
|
|
91
91
|
],
|
|
92
92
|
atOpen: null,
|
|
93
93
|
refresh: {
|
|
94
|
-
url: "https://
|
|
94
|
+
url: "https://credentials.example.com/provider/refresh",
|
|
95
95
|
token: "grant-model",
|
|
96
96
|
harnessSessionId: "0192f7a0-0000-7000-8000-0000000000a1",
|
|
97
97
|
expiresAt: EXPIRES_AT
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/testing/harness.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n BaseCapability,\n CredentialRoute,\n credentials,\n jsonObjectSchema,\n MANIFEST_VERSION,\n packageRef,\n ToolApproval,\n type OpenHarnessSessionArgsIface,\n type ResolvedAgentManifestIface,\n type SandboxTargetEndpointIface,\n} from '@finalai/agent-provider';\n\n// Shared fixtures for the harness tests (no module mocks: fakes go in through\n// each factory's fetch/now/newId seams).\n\nexport const SESSION_ID = '0192f7a0-0000-7000-8000-000000000001';\nexport const HARNESS_SESSION_ID = '0192f7a0-0000-7000-8000-0000000000aa';\nexport const EXPIRES_AT = '2026-10-10T00:15:00.000Z';\n\nexport const computerEndpoint: SandboxTargetEndpointIface = {\n target: 'computer',\n bindingId: '0192f7a0-0000-7000-8000-0000000000c1',\n capabilities: ['shell', 'files', 'process'],\n rpc: { url: 'wss://agent-session.test/sandboxes/b/c1', token: 'rpc-c1', expiresAt: EXPIRES_AT },\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/c1/mcp',\n token: 'mcp-c1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const deviceEndpoint: SandboxTargetEndpointIface = {\n target: 'device',\n bindingId: '0192f7a0-0000-7000-8000-0000000000d1',\n capabilities: ['computerUse'],\n rpc: null,\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/d1/mcp',\n token: 'mcp-d1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const resolvedManifest = (): ResolvedAgentManifestIface => ({\n version: MANIFEST_VERSION,\n identity: { name: 'Release Scout', description: null },\n harness: {\n harness: packageRef('@finalai/final-agent-provider/harnesses/serverless-pi'),\n config: {},\n },\n mcpServers: [],\n sandboxes: {},\n tools: {\n base: {\n shell: { target: 'computer' },\n files: { target: 'computer' },\n computerUse: { target: 'device' },\n },\n },\n secrets: [],\n toolPolicy: {\n shell: ToolApproval.Ask,\n 'files.write': ToolApproval.Ask,\n create_issue: ToolApproval.Allow,\n },\n channels: [],\n hooks: [],\n schedules: [],\n bundle: null,\n});\n\nexport const openArgs = (\n config: unknown,\n secrets: Record<string, string> = {},\n): OpenHarnessSessionArgsIface => ({\n harnessSessionId: '0192f7a0-0000-7000-8000-0000000000a1',\n session: {\n sessionId: SESSION_ID,\n organizationId: '0192f7a0-0000-7000-8000-0000000000o1',\n definitionId: '0192f7a0-0000-7000-8000-0000000000e1',\n revisionId: '0192f7a0-0000-7000-8000-0000000000r1',\n sessionServiceUrl: 'https://agent-session.test',\n },\n config: {\n credentials: credentials.chain({\n payer: 'organization',\n tryInOrder: [credentials.apiKey({ owner: 'organization' }), credentials.platform()],\n }),\n ...jsonObjectSchema.parse(config),\n },\n manifest: resolvedManifest(),\n mcpServers: [],\n baseTools: {\n [BaseCapability.Shell]: computerEndpoint,\n [BaseCapability.Files]: computerEndpoint,\n [BaseCapability.ComputerUse]: deviceEndpoint,\n },\n sandboxes: { computer: computerEndpoint, device: deviceEndpoint },\n credentials: {\n brokerUrl: 'https://
|
|
4
|
+
"sourcesContent": ["import {\n BaseCapability,\n CredentialRoute,\n credentials,\n jsonObjectSchema,\n MANIFEST_VERSION,\n packageRef,\n ToolApproval,\n type OpenHarnessSessionArgsIface,\n type ResolvedAgentManifestIface,\n type SandboxTargetEndpointIface,\n} from '@finalai/agent-provider';\n\n// Shared fixtures for the harness tests (no module mocks: fakes go in through\n// each factory's fetch/now/newId seams).\n\nexport const SESSION_ID = '0192f7a0-0000-7000-8000-000000000001';\nexport const HARNESS_SESSION_ID = '0192f7a0-0000-7000-8000-0000000000aa';\nexport const EXPIRES_AT = '2026-10-10T00:15:00.000Z';\n\nexport const computerEndpoint: SandboxTargetEndpointIface = {\n target: 'computer',\n bindingId: '0192f7a0-0000-7000-8000-0000000000c1',\n capabilities: ['shell', 'files', 'process'],\n rpc: { url: 'wss://agent-session.test/sandboxes/b/c1', token: 'rpc-c1', expiresAt: EXPIRES_AT },\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/c1/mcp',\n token: 'mcp-c1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const deviceEndpoint: SandboxTargetEndpointIface = {\n target: 'device',\n bindingId: '0192f7a0-0000-7000-8000-0000000000d1',\n capabilities: ['computerUse'],\n rpc: null,\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/d1/mcp',\n token: 'mcp-d1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const resolvedManifest = (): ResolvedAgentManifestIface => ({\n version: MANIFEST_VERSION,\n identity: { name: 'Release Scout', description: null },\n harness: {\n harness: packageRef('@finalai/final-agent-provider/harnesses/serverless-pi'),\n config: {},\n },\n mcpServers: [],\n sandboxes: {},\n tools: {\n base: {\n shell: { target: 'computer' },\n files: { target: 'computer' },\n computerUse: { target: 'device' },\n },\n },\n secrets: [],\n toolPolicy: {\n shell: ToolApproval.Ask,\n 'files.write': ToolApproval.Ask,\n create_issue: ToolApproval.Allow,\n },\n channels: [],\n hooks: [],\n schedules: [],\n bundle: null,\n});\n\nexport const openArgs = (\n config: unknown,\n secrets: Record<string, string> = {},\n): OpenHarnessSessionArgsIface => ({\n harnessSessionId: '0192f7a0-0000-7000-8000-0000000000a1',\n session: {\n sessionId: SESSION_ID,\n organizationId: '0192f7a0-0000-7000-8000-0000000000o1',\n definitionId: '0192f7a0-0000-7000-8000-0000000000e1',\n revisionId: '0192f7a0-0000-7000-8000-0000000000r1',\n sessionServiceUrl: 'https://agent-session.test',\n },\n config: {\n credentials: credentials.chain({\n payer: 'organization',\n tryInOrder: [credentials.apiKey({ owner: 'organization' }), credentials.platform()],\n }),\n ...jsonObjectSchema.parse(config),\n },\n manifest: resolvedManifest(),\n mcpServers: [],\n baseTools: {\n [BaseCapability.Shell]: computerEndpoint,\n [BaseCapability.Files]: computerEndpoint,\n [BaseCapability.ComputerUse]: deviceEndpoint,\n },\n sandboxes: { computer: computerEndpoint, device: deviceEndpoint },\n credentials: {\n brokerUrl: 'https://credentials.example.com/provider',\n grants: [\n { route: CredentialRoute.Model, token: 'grant-model', expiresAt: EXPIRES_AT },\n { route: CredentialRoute.Mcp, token: 'grant-mcp', expiresAt: EXPIRES_AT },\n ],\n atOpen: null,\n refresh: {\n url: 'https://credentials.example.com/provider/refresh',\n token: 'grant-model',\n harnessSessionId: '0192f7a0-0000-7000-8000-0000000000a1',\n expiresAt: EXPIRES_AT,\n },\n },\n secrets: { get: async (name) => secrets[name] ?? null },\n trace: {\n traceparent: '00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01',\n tracestate: null,\n },\n});\n\n// Monotonic ids so assertions can name them.\nexport const idSequence = (prefix: string): (() => string) => {\n let next = 0;\n return () => {\n next += 1;\n return `${prefix}-7000-8000-${String(next).padStart(12, '0')}`;\n };\n};\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finalai/final-agent-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "Final
|
|
5
|
+
"description": "Final provider helpers for harnesses, computer and device sandboxes, the Final room surface, and external provider channels.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
@@ -101,16 +101,6 @@
|
|
|
101
101
|
"import": "./dist/modules/channels/group-messaging.mjs",
|
|
102
102
|
"default": "./dist/modules/channels/group-messaging.mjs"
|
|
103
103
|
},
|
|
104
|
-
"./channels/agent-schedules": {
|
|
105
|
-
"types": "./dist/modules/channels/agent-schedules.d.mts",
|
|
106
|
-
"import": "./dist/modules/channels/agent-schedules.mjs",
|
|
107
|
-
"default": "./dist/modules/channels/agent-schedules.mjs"
|
|
108
|
-
},
|
|
109
|
-
"./channels/agent-events": {
|
|
110
|
-
"types": "./dist/modules/channels/agent-events.d.mts",
|
|
111
|
-
"import": "./dist/modules/channels/agent-events.mjs",
|
|
112
|
-
"default": "./dist/modules/channels/agent-events.mjs"
|
|
113
|
-
},
|
|
114
104
|
"./package.json": "./package.json",
|
|
115
105
|
"./channel-factories": {
|
|
116
106
|
"types": "./dist/modules/channel-factories.d.mts",
|
|
@@ -211,6 +201,41 @@
|
|
|
211
201
|
"types": "./dist/modules/sandboxes/egress-bootstrap.d.mts",
|
|
212
202
|
"import": "./dist/modules/sandboxes/egress-bootstrap.mjs",
|
|
213
203
|
"default": "./dist/modules/sandboxes/egress-bootstrap.mjs"
|
|
204
|
+
},
|
|
205
|
+
"./channels/slack": {
|
|
206
|
+
"types": "./dist/modules/channels/slack.d.mts",
|
|
207
|
+
"import": "./dist/modules/channels/slack.mjs",
|
|
208
|
+
"default": "./dist/modules/channels/slack.mjs"
|
|
209
|
+
},
|
|
210
|
+
"./channels/discord": {
|
|
211
|
+
"types": "./dist/modules/channels/discord.d.mts",
|
|
212
|
+
"import": "./dist/modules/channels/discord.mjs",
|
|
213
|
+
"default": "./dist/modules/channels/discord.mjs"
|
|
214
|
+
},
|
|
215
|
+
"./channels/github": {
|
|
216
|
+
"types": "./dist/modules/channels/github.d.mts",
|
|
217
|
+
"import": "./dist/modules/channels/github.mjs",
|
|
218
|
+
"default": "./dist/modules/channels/github.mjs"
|
|
219
|
+
},
|
|
220
|
+
"./channels/linear": {
|
|
221
|
+
"types": "./dist/modules/channels/linear.d.mts",
|
|
222
|
+
"import": "./dist/modules/channels/linear.mjs",
|
|
223
|
+
"default": "./dist/modules/channels/linear.mjs"
|
|
224
|
+
},
|
|
225
|
+
"./channels/webhook": {
|
|
226
|
+
"types": "./dist/modules/channels/webhook.d.mts",
|
|
227
|
+
"import": "./dist/modules/channels/webhook.mjs",
|
|
228
|
+
"default": "./dist/modules/channels/webhook.mjs"
|
|
229
|
+
},
|
|
230
|
+
"./channels/voice": {
|
|
231
|
+
"types": "./dist/modules/channels/voice.d.mts",
|
|
232
|
+
"import": "./dist/modules/channels/voice.mjs",
|
|
233
|
+
"default": "./dist/modules/channels/voice.mjs"
|
|
234
|
+
},
|
|
235
|
+
"./channels/phone": {
|
|
236
|
+
"types": "./dist/modules/channels/phone.d.mts",
|
|
237
|
+
"import": "./dist/modules/channels/phone.mjs",
|
|
238
|
+
"default": "./dist/modules/channels/phone.mjs"
|
|
214
239
|
}
|
|
215
240
|
},
|
|
216
241
|
"publishConfig": {
|
|
@@ -219,14 +244,15 @@
|
|
|
219
244
|
},
|
|
220
245
|
"dependencies": {
|
|
221
246
|
"@agentclientprotocol/sdk": "1.8.0",
|
|
222
|
-
"@finalai/acp-session": "0.1.
|
|
223
|
-
"@finalai/agent-protocol": "0.
|
|
224
|
-
"@finalai/agent-provider": "0.
|
|
225
|
-
"@finalai/computers": "0.3.
|
|
226
|
-
"@finalai/websockets": "0.1.
|
|
247
|
+
"@finalai/acp-session": "0.1.11",
|
|
248
|
+
"@finalai/agent-protocol": "0.7.0",
|
|
249
|
+
"@finalai/agent-provider": "0.6.0",
|
|
250
|
+
"@finalai/computers": "0.3.1",
|
|
251
|
+
"@finalai/websockets": "0.1.7",
|
|
227
252
|
"ws": "^8.21.3",
|
|
228
|
-
"zod": "4.6.
|
|
229
|
-
"@finalai/agent-definition": "0.
|
|
253
|
+
"zod": "4.6.6",
|
|
254
|
+
"@finalai/agent-definition": "0.6.0",
|
|
255
|
+
"gemoji": "^8.1.0"
|
|
230
256
|
},
|
|
231
257
|
"engines": {
|
|
232
258
|
"node": ">=26"
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { TurnPolicy, type ChannelAddressContextIface, type ChannelPlatformIface } from '@finalai/agent-provider';
|
|
2
|
-
export interface FinalAddressContextArgsIface {
|
|
3
|
-
platform: ChannelPlatformIface;
|
|
4
|
-
definitionId: string;
|
|
5
|
-
turnPolicy: TurnPolicy;
|
|
6
|
-
}
|
|
7
|
-
export declare const finalAddressContext: (args: FinalAddressContextArgsIface) => ChannelAddressContextIface;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
channelAccessors,
|
|
3
|
-
ParticipantKind,
|
|
4
|
-
TurnPolicy
|
|
5
|
-
} from "@finalai/agent-provider";
|
|
6
|
-
const finalAddressContext = (args) => {
|
|
7
|
-
const generic = channelAccessors(args.platform);
|
|
8
|
-
const operations = () => {
|
|
9
|
-
if (args.platform.channelSessions == null)
|
|
10
|
-
throw new Error("channel session operations are unavailable");
|
|
11
|
-
return args.platform.channelSessions;
|
|
12
|
-
};
|
|
13
|
-
const agentIn = async (address) => {
|
|
14
|
-
const participants = await args.platform.conversations.participants(address);
|
|
15
|
-
return participants.find(
|
|
16
|
-
(participant) => !participant.left && participant.kind === ParticipantKind.Agent && participant.definitionId === args.definitionId
|
|
17
|
-
) ?? null;
|
|
18
|
-
};
|
|
19
|
-
const handle = (address, pinnedId) => {
|
|
20
|
-
const resolve = async () => {
|
|
21
|
-
if (pinnedId != null) return generic.attachSession(pinnedId).resolveSession();
|
|
22
|
-
const room = await address();
|
|
23
|
-
return room == null ? null : (await agentIn(room))?.sessionId ?? null;
|
|
24
|
-
};
|
|
25
|
-
const existing = async () => {
|
|
26
|
-
const sessionId = await resolve();
|
|
27
|
-
if (sessionId == null) throw new Error("Final channel address has no session");
|
|
28
|
-
return generic.attachSession(sessionId);
|
|
29
|
-
};
|
|
30
|
-
return {
|
|
31
|
-
inspect: async () => {
|
|
32
|
-
const sessionId = await resolve();
|
|
33
|
-
return sessionId == null ? null : generic.attachSession(sessionId).inspect();
|
|
34
|
-
},
|
|
35
|
-
resolveSession: resolve,
|
|
36
|
-
// Input to the room's agent from the sender's principal, never a message:
|
|
37
|
-
// accepted at once, delivered by the platform, the reply captioned in the room.
|
|
38
|
-
send: async (input) => {
|
|
39
|
-
const room = await address();
|
|
40
|
-
if (room == null) throw new Error("Final channel session has no room");
|
|
41
|
-
const agent = await agentIn(room);
|
|
42
|
-
if (agent == null) throw new Error("Final channel address is unavailable");
|
|
43
|
-
if (pinnedId != null && agent.sessionId !== pinnedId)
|
|
44
|
-
throw new Error("pinned Final session no longer owns this room");
|
|
45
|
-
return operations().send(
|
|
46
|
-
{ conversationId: room, participantId: agent.id },
|
|
47
|
-
{
|
|
48
|
-
...input,
|
|
49
|
-
turnPolicy: input.turnPolicy ?? args.turnPolicy,
|
|
50
|
-
source: input.source
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
},
|
|
54
|
-
respond: async (input) => (await existing()).respond(input),
|
|
55
|
-
cancel: async () => {
|
|
56
|
-
const sessionId = await resolve();
|
|
57
|
-
return sessionId == null ? { accepted: false } : generic.attachSession(sessionId).cancel();
|
|
58
|
-
},
|
|
59
|
-
close: async () => {
|
|
60
|
-
const sessionId = await resolve();
|
|
61
|
-
if (sessionId != null) await generic.attachSession(sessionId).close();
|
|
62
|
-
},
|
|
63
|
-
observe: async (input) => (await existing()).observe(input),
|
|
64
|
-
setConfigOption: async (input) => (await existing()).setConfigOption(input),
|
|
65
|
-
park: async () => (await existing()).park(),
|
|
66
|
-
getState: async () => (await existing()).getState(),
|
|
67
|
-
setState: async (state) => (await existing()).setState(state)
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
return {
|
|
71
|
-
from: (address) => handle(async () => address),
|
|
72
|
-
resolveSession: async (address) => (await agentIn(address))?.sessionId ?? null,
|
|
73
|
-
attachSession: (id) => handle(async () => (await generic.attachSession(id).inspect())?.conversationId ?? null, id),
|
|
74
|
-
to: generic.to
|
|
75
|
-
};
|
|
76
|
-
};
|
|
77
|
-
export {
|
|
78
|
-
finalAddressContext
|
|
79
|
-
};
|
|
80
|
-
//# sourceMappingURL=address-context.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/channels/address-context.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n channelAccessors,\n ParticipantKind,\n TurnPolicy,\n type ChannelAddressContextIface,\n type ChannelPlatformIface,\n type ChannelSessionHandleIface,\n} from '@finalai/agent-provider';\n\nexport interface FinalAddressContextArgsIface {\n platform: ChannelPlatformIface;\n definitionId: string;\n turnPolicy: TurnPolicy;\n}\n\n// Final addresses are room IDs. The existing participant/session association\n// owns the room's session; a pinned handle never follows a replacement.\nexport const finalAddressContext = (\n args: FinalAddressContextArgsIface,\n): ChannelAddressContextIface => {\n const generic = channelAccessors(args.platform);\n const operations = () => {\n if (args.platform.channelSessions == null)\n throw new Error('channel session operations are unavailable');\n return args.platform.channelSessions;\n };\n const agentIn = async (address: string) => {\n const participants = await args.platform.conversations.participants(address);\n return (\n participants.find(\n (participant) =>\n !participant.left &&\n participant.kind === ParticipantKind.Agent &&\n participant.definitionId === args.definitionId,\n ) ?? null\n );\n };\n const handle = (\n address: () => Promise<string | null>,\n pinnedId?: string,\n ): ChannelSessionHandleIface => {\n const resolve = async () => {\n if (pinnedId != null) return generic.attachSession(pinnedId).resolveSession();\n const room = await address();\n return room == null ? null : ((await agentIn(room))?.sessionId ?? null);\n };\n const existing = async () => {\n const sessionId = await resolve();\n if (sessionId == null) throw new Error('Final channel address has no session');\n return generic.attachSession(sessionId);\n };\n return {\n inspect: async () => {\n const sessionId = await resolve();\n return sessionId == null ? null : generic.attachSession(sessionId).inspect();\n },\n resolveSession: resolve,\n // Input to the room's agent from the sender's principal, never a message:\n // accepted at once, delivered by the platform, the reply captioned in the room.\n send: async (input) => {\n const room = await address();\n if (room == null) throw new Error('Final channel session has no room');\n const agent = await agentIn(room);\n if (agent == null) throw new Error('Final channel address is unavailable');\n if (pinnedId != null && agent.sessionId !== pinnedId)\n throw new Error('pinned Final session no longer owns this room');\n return operations().send(\n { conversationId: room, participantId: agent.id },\n {\n ...input,\n turnPolicy: input.turnPolicy ?? args.turnPolicy,\n source: input.source,\n },\n );\n },\n respond: async (input) => (await existing()).respond(input),\n cancel: async () => {\n const sessionId = await resolve();\n return sessionId == null ? { accepted: false } : generic.attachSession(sessionId).cancel();\n },\n close: async () => {\n const sessionId = await resolve();\n if (sessionId != null) await generic.attachSession(sessionId).close();\n },\n observe: async (input) => (await existing()).observe(input),\n setConfigOption: async (input) => (await existing()).setConfigOption(input),\n park: async () => (await existing()).park(),\n getState: async () => (await existing()).getState(),\n setState: async (state) => (await existing()).setState(state),\n };\n };\n return {\n from: (address) => handle(async () => address),\n resolveSession: async (address) => (await agentIn(address))?.sessionId ?? null,\n attachSession: (id) =>\n handle(async () => (await generic.attachSession(id).inspect())?.conversationId ?? null, id),\n to: generic.to,\n };\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { SandboxEventKind, TurnPolicy, type ChannelDefinitionIface, type ChannelReceiveContextIface, type ConversationRefIface, type JsonValue, type RouteArgsIface, type RouteDecisionIface } from '@finalai/agent-provider';
|
|
2
|
-
import * as z from 'zod';
|
|
3
|
-
export declare const AGENT_EVENTS_SPECIFIER = "@finalai/final-agent-provider/channels/agent-events";
|
|
4
|
-
export declare const AGENT_EVENTS_TURN_POLICY = TurnPolicy.Steer;
|
|
5
|
-
export declare const WEBHOOK_SECRET_NAME = "webhook";
|
|
6
|
-
export declare const WEBHOOK_BODY_MAX_CHARS = 8000;
|
|
7
|
-
export declare enum AgentEventKind {
|
|
8
|
-
Webhook = "webhook",
|
|
9
|
-
LinkedConversation = "linked-conversation",
|
|
10
|
-
Sandbox = "sandbox"
|
|
11
|
-
}
|
|
12
|
-
export { SandboxEventKind } from '@finalai/agent-provider';
|
|
13
|
-
export declare const SYSTEM_EVENT_TEXT_MAX_CHARS = 4000;
|
|
14
|
-
export declare enum LinkedConversationEvent {
|
|
15
|
-
Replied = "replied",
|
|
16
|
-
WaitingForPerson = "waiting_for_person",
|
|
17
|
-
Failed = "failed"
|
|
18
|
-
}
|
|
19
|
-
export declare const LINKED_CONVERSATION_TEXT_MAX_CHARS = 4000;
|
|
20
|
-
declare const linkedConversationEventSchema: z.ZodObject<{
|
|
21
|
-
kind: z.ZodLiteral<AgentEventKind.LinkedConversation>;
|
|
22
|
-
conversationId: z.ZodString;
|
|
23
|
-
participantId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
24
|
-
linkId: z.ZodString;
|
|
25
|
-
linkedConversationId: z.ZodString;
|
|
26
|
-
linkedTitle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
27
|
-
event: z.ZodEnum<typeof LinkedConversationEvent>;
|
|
28
|
-
text: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
29
|
-
eventId: z.ZodString;
|
|
30
|
-
originTurnId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
31
|
-
}, z.core.$strip>;
|
|
32
|
-
declare const sandboxEventSchema: z.ZodObject<{
|
|
33
|
-
kind: z.ZodLiteral<AgentEventKind.Sandbox>;
|
|
34
|
-
conversationId: z.ZodString;
|
|
35
|
-
participantId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
36
|
-
bindingId: z.ZodString;
|
|
37
|
-
sandboxName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
38
|
-
event: z.ZodEnum<typeof SandboxEventKind>;
|
|
39
|
-
processId: z.ZodString;
|
|
40
|
-
command: z.ZodString;
|
|
41
|
-
exitCode: z.ZodNullable<z.ZodNumber>;
|
|
42
|
-
stdout: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
43
|
-
stderr: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
44
|
-
eventId: z.ZodString;
|
|
45
|
-
}, z.core.$strip>;
|
|
46
|
-
export declare const agentEventInboundSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
47
|
-
kind: z.ZodLiteral<AgentEventKind.Webhook>;
|
|
48
|
-
body: z.ZodString;
|
|
49
|
-
contentType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
50
|
-
event: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
51
|
-
deliveryId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
52
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
53
|
-
kind: z.ZodLiteral<AgentEventKind.LinkedConversation>;
|
|
54
|
-
conversationId: z.ZodString;
|
|
55
|
-
participantId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
56
|
-
linkId: z.ZodString;
|
|
57
|
-
linkedConversationId: z.ZodString;
|
|
58
|
-
linkedTitle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
59
|
-
event: z.ZodEnum<typeof LinkedConversationEvent>;
|
|
60
|
-
text: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
61
|
-
eventId: z.ZodString;
|
|
62
|
-
originTurnId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
63
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
64
|
-
kind: z.ZodLiteral<AgentEventKind.Sandbox>;
|
|
65
|
-
conversationId: z.ZodString;
|
|
66
|
-
participantId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
67
|
-
bindingId: z.ZodString;
|
|
68
|
-
sandboxName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
69
|
-
event: z.ZodEnum<typeof SandboxEventKind>;
|
|
70
|
-
processId: z.ZodString;
|
|
71
|
-
command: z.ZodString;
|
|
72
|
-
exitCode: z.ZodNullable<z.ZodNumber>;
|
|
73
|
-
stdout: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
74
|
-
stderr: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
75
|
-
eventId: z.ZodString;
|
|
76
|
-
}, z.core.$strip>], "kind">;
|
|
77
|
-
export type SandboxEventInboundIface = z.infer<typeof sandboxEventSchema>;
|
|
78
|
-
export type AgentEventInboundIface = z.infer<typeof agentEventInboundSchema>;
|
|
79
|
-
export declare enum ReceiveTargetKind {
|
|
80
|
-
BoundConversation = "bound-conversation",
|
|
81
|
-
OwnerDirect = "owner-direct"
|
|
82
|
-
}
|
|
83
|
-
export declare const targetedInboundSchema: z.ZodObject<{
|
|
84
|
-
target: z.ZodObject<{
|
|
85
|
-
kind: z.ZodEnum<typeof ReceiveTargetKind>;
|
|
86
|
-
}, z.core.$strip>;
|
|
87
|
-
content: z.ZodArray<z.ZodType<import("@finalai/agent-provider").JsonObject, unknown, z.core.$ZodTypeInternals<import("@finalai/agent-provider").JsonObject, unknown>>>;
|
|
88
|
-
deliveryId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
89
|
-
}, z.core.$strip>;
|
|
90
|
-
export type TargetedInboundIface = z.infer<typeof targetedInboundSchema>;
|
|
91
|
-
export type ChannelReceiveIface = (input: JsonValue, ctx: ChannelReceiveContextIface) => Promise<ConversationRefIface>;
|
|
92
|
-
export declare const createTargetedInputReceive: (turnPolicy?: TurnPolicy) => ChannelReceiveIface;
|
|
93
|
-
export declare const renderLinkedConversationEvent: (event: Pick<z.infer<typeof linkedConversationEventSchema>, "linkedTitle" | "event" | "text">) => string;
|
|
94
|
-
export declare const renderSandboxEvent: (event: Pick<SandboxEventInboundIface, "processId" | "command" | "exitCode" | "stdout" | "stderr">) => string;
|
|
95
|
-
export declare const routeToOwner: (participantId: string) => (args: RouteArgsIface) => RouteDecisionIface[];
|
|
96
|
-
export declare const receiveAgentEvent: ChannelReceiveIface;
|
|
97
|
-
export declare const hmacSha256Hex: (secret: string, body: string) => Promise<string>;
|
|
98
|
-
export declare const verifyWebhookSignature: (args: {
|
|
99
|
-
secret: string;
|
|
100
|
-
body: string;
|
|
101
|
-
headers: Headers;
|
|
102
|
-
}) => Promise<boolean>;
|
|
103
|
-
export declare const createAgentEventsChannel: () => ChannelDefinitionIface<JsonValue, JsonValue>;
|