@agent-native/core 0.7.51 → 0.7.53
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/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +109 -5
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +11 -0
- package/dist/a2a/server.js.map +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +1 -0
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js +54 -13
- package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
- package/dist/deploy/workspace-deploy.js +32 -3
- package/dist/deploy/workspace-deploy.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +2 -1
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +10 -0
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/onboarding/plugin.d.ts.map +1 -1
- package/dist/onboarding/plugin.js +2 -1
- package/dist/onboarding/plugin.js.map +1 -1
- package/dist/org/plugin.d.ts.map +1 -1
- package/dist/org/plugin.js +2 -1
- package/dist/org/plugin.js.map +1 -1
- package/dist/scripts/call-agent.js +2 -2
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +5 -11
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +2 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth-plugin.d.ts.map +1 -1
- package/dist/server/auth-plugin.js +2 -1
- package/dist/server/auth-plugin.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +7 -12
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +9 -29
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/cors-origins.d.ts +10 -0
- package/dist/server/cors-origins.d.ts.map +1 -0
- package/dist/server/cors-origins.js +34 -0
- package/dist/server/cors-origins.js.map +1 -0
- package/dist/server/create-server.d.ts.map +1 -1
- package/dist/server/create-server.js +10 -29
- package/dist/server/create-server.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts +11 -0
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +24 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/resources-plugin.d.ts.map +1 -1
- package/dist/server/resources-plugin.js +2 -1
- package/dist/server/resources-plugin.js.map +1 -1
- package/dist/terminal/terminal-plugin.d.ts.map +1 -1
- package/dist/terminal/terminal-plugin.js +2 -1
- package/dist/terminal/terminal-plugin.js.map +1 -1
- package/docs/content/a2a-protocol.md +93 -14
- package/docs/content/agent-mentions.md +2 -2
- package/docs/content/agent-teams.md +2 -2
- package/docs/content/client.md +1 -1
- package/docs/content/cloneable-saas.md +13 -13
- package/docs/content/creating-templates.md +253 -211
- package/docs/content/dispatch.md +94 -0
- package/docs/content/faq.md +2 -2
- package/docs/content/frames.md +1 -1
- package/docs/content/getting-started.md +9 -1
- package/docs/content/key-concepts.md +17 -1
- package/docs/content/messaging.md +56 -19
- package/docs/content/multi-app-workspace.md +10 -2
- package/docs/content/notifications.md +1 -1
- package/docs/content/observability.md +184 -0
- package/docs/content/onboarding.md +7 -2
- package/docs/content/server.md +117 -133
- package/docs/content/skills-guide.md +3 -3
- package/docs/content/template-analytics.md +8 -6
- package/docs/content/template-design.md +25 -27
- package/docs/content/template-dispatch.md +3 -1
- package/docs/content/template-forms.md +26 -21
- package/docs/content/template-mail.md +4 -0
- package/docs/content/template-video.md +4 -4
- package/docs/content/tools.md +95 -1
- package/docs/content/tracking.md +1 -1
- package/docs/content/what-is-agent-native.md +4 -2
- package/docs/content/workspace-management.md +5 -5
- package/docs/content/workspace.md +39 -30
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-plugin.js","sourceRoot":"","sources":["../../src/terminal/terminal-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { getH3App } from \"../server/framework-request-handler.js\";\nimport { isNodeRuntime } from \"../shared/runtime.js\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { createRequire } from \"node:module\";\n/**\n * Nitro Plugin — Agent Terminal\n *\n * Starts a PTY WebSocket server alongside the app so the <AgentTerminal />\n * component can connect to a real CLI. Mounts a discovery endpoint at\n * /_agent-native/agent-terminal-info for the client component.\n *\n * Skips activation when running inside a frame (FRAME_PORT is set).\n */\n\nimport { defineEventHandler } from \"h3\";\n\n// ─── module-load self-heal: chmod node-pty's spawn-helper ─────────────────\n// pnpm can extract node-pty's prebuilds tarball without running the\n// post-install that chmods spawn-helper, leaving it as `-rw-r--r--` instead\n// of `-rwxr-xr-x`. Every PTY spawn then fails with `posix_spawnp failed`.\n// Run the fix synchronously at module load (static imports, sync fs calls)\n// so by the time ANY plugin worker starts spawning PTYs, the helper is\n// already executable.\n(function fixSpawnHelperPermissions() {\n if (!isNodeRuntime()) return;\n try {\n const req = createRequire(import.meta.url);\n const ptyPkg = req.resolve(\"node-pty/package.json\");\n const ptyDir = path.dirname(ptyPkg);\n const helper = path.join(\n ptyDir,\n \"prebuilds\",\n `${process.platform}-${process.arch}`,\n \"spawn-helper\",\n );\n if (fs.existsSync(helper)) {\n const mode = fs.statSync(helper).mode;\n if (!(mode & 0o100)) {\n fs.chmodSync(helper, 0o755);\n console.log(\n `[terminal] Fixed non-executable node-pty spawn-helper at ${helper}`,\n );\n }\n }\n } catch (err) {\n // node-pty not installed → stay silent here; createTerminalPlugin emits\n // the \"install node-pty\" message when the PTY server actually fails to\n // start. Logging twice for the same root cause just adds noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"MODULE_NOT_FOUND\" || code === \"ERR_MODULE_NOT_FOUND\") return;\n console.warn(\n \"[terminal] Could not verify node-pty spawn-helper permissions:\",\n (err as Error).message,\n );\n }\n})();\n\nexport interface TerminalPluginOptions {\n /** CLI command to run. Defaults to AGENT_CLI_COMMAND env or 'builder' */\n command?: string;\n /** Port for the WebSocket server. Defaults to AGENT_TERMINAL_PORT env or auto-assigned */\n port?: number;\n /** Enable in production. Defaults to AGENT_TERMINAL_ENABLED env or false in prod */\n enabledInProduction?: boolean;\n /** Auth check for WebSocket connections in production */\n authCheck?: (req: any) => boolean | Promise<boolean>;\n}\n\n// Vite's dev server can initialize Nitro plugins more than once during boot.\n// Module-scope flags ensure the \"node-pty not installed\" / \"Disabled in\n// production\" / \"Frame detected\" notices each fire at most once per process.\nlet _ptyMissingLogged = false;\nlet _disabledLogged = false;\nlet _frameDetectedLogged = false;\n\nexport function createTerminalPlugin(options: TerminalPluginOptions = {}) {\n return async (nitroApp: any) => {\n // Terminal requires Node.js (PTY, child_process) — skip on edge runtimes\n if (!isNodeRuntime()) return;\n\n // Always mount /_agent-native/available-clis so the client doesn't get 404s\n getH3App(nitroApp).use(\n \"/_agent-native/available-clis\",\n defineEventHandler(async () => {\n try {\n const { CLI_REGISTRY, commandExists } =\n await import(\"./cli-registry.js\");\n const results = [];\n for (const [cmd, entry] of Object.entries(CLI_REGISTRY)) {\n results.push({\n command: cmd,\n label: entry.label,\n available: await commandExists(cmd),\n });\n }\n return results;\n } catch {\n return [];\n }\n }),\n );\n\n // Skip if running inside a frame\n if (process.env.FRAME_PORT) {\n if (!_frameDetectedLogged) {\n console.log(\"[terminal] Frame detected, skipping embedded terminal\");\n _frameDetectedLogged = true;\n }\n return;\n }\n\n const isProd = process.env.NODE_ENV === \"production\";\n const enabled =\n options.enabledInProduction ??\n (process.env.AGENT_TERMINAL_ENABLED === \"true\" || !isProd);\n\n if (!enabled) {\n if (!_disabledLogged) {\n console.log(\n \"[terminal] Disabled in production (set AGENT_TERMINAL_ENABLED=true to enable)\",\n );\n _disabledLogged = true;\n }\n // Mount a disabled info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({ available: false })),\n );\n return;\n }\n\n // Require authCheck in production to prevent unauthenticated shell access\n if (isProd && !options.authCheck) {\n console.error(\n \"[terminal] FATAL: authCheck is required when enabling the terminal in production. \" +\n \"Pass an authCheck function to createTerminalPlugin().\",\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: \"Terminal requires authCheck in production\",\n })),\n );\n return;\n }\n\n // Skip if a PTY server is already running (prevents leak on HMR rebuild)\n if (process.env.__AGENT_TERMINAL_RUNNING === \"true\") {\n const existingPort = process.env.AGENT_TERMINAL_PORT;\n console.log(\n `[terminal] PTY server already running on port ${existingPort}, skipping`,\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: existingPort ? parseInt(existingPort, 10) : 0,\n command:\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\",\n })),\n );\n return;\n }\n\n const command =\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\";\n const port =\n options.port ??\n (process.env.AGENT_TERMINAL_PORT\n ? parseInt(process.env.AGENT_TERMINAL_PORT, 10)\n : 0);\n\n // Mark as running BEFORE the async server start. The previous code only\n // set this AFTER `await createPtyWebSocketServer(...)`, which left a\n // TOCTOU window where two concurrent plugin invocations would both pass\n // the running-check, both spawn a server, and end up fighting for the\n // CLI's PTY pool — leading to `posix_spawnp failed` floods.\n process.env.__AGENT_TERMINAL_RUNNING = \"true\"; // guard:allow-env-mutation — process-wide running flag set once at boot, before any HTTP request handling, to coordinate concurrent plugin invocations\n\n try {\n const { createPtyWebSocketServer } = await import(\"./pty-server.js\");\n\n const result = await createPtyWebSocketServer({\n appDir: process.cwd(),\n command,\n port,\n authCheck: isProd ? options.authCheck : undefined,\n logPrefix: \"[terminal]\",\n });\n\n // Store port for other consumers\n process.env.AGENT_TERMINAL_PORT = String(result.port); // guard:allow-env-mutation — terminal subprocess port published once at boot, not per-request\n\n // Mount discovery endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: result.port,\n command,\n })),\n );\n\n // Cleanup on shutdown (use once to avoid listener leak on hot-reload)\n const cleanup = () => result.close();\n process.once(\"SIGTERM\", cleanup);\n process.once(\"SIGINT\", cleanup);\n process.once(\"exit\", cleanup);\n\n if (process.env.DEBUG)\n console.log(\n `[terminal] Agent terminal ready (command: ${command}, port: ${result.port})`,\n );\n } catch (err) {\n // Clear the running flag so a retry can spawn a fresh server\n delete process.env.__AGENT_TERMINAL_RUNNING; // guard:allow-env-mutation — terminal subprocess boot failed, clearing boot-time sentinel so a later plugin retry can start cleanly\n\n // Distinguish \"node-pty not installed\" (expected when the user opts\n // out of the terminal feature) from real failures (port conflict,\n // native binding mismatch). Native deps are optional — log as info\n // so the dev console isn't filled with red noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n const missingPty =\n code === \"ERR_MODULE_NOT_FOUND\" || code === \"MODULE_NOT_FOUND\";\n if (missingPty) {\n if (!_ptyMissingLogged) {\n console.log(\n \"[terminal] node-pty not installed — embedded terminal disabled. \" +\n \"Install with `pnpm add node-pty` to enable.\",\n );\n _ptyMissingLogged = true;\n }\n } else {\n console.error(\"[terminal] Failed to start PTY server:\", err);\n console.error(\n \"[terminal] If node-pty is installed but PTY fails to spawn, \" +\n \"try `pnpm rebuild node-pty` (common after switching Node \" +\n \"versions via fnm/nvm).\",\n );\n }\n\n // Mount a fallback info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: missingPty ? \"node-pty not installed\" : \"PTY server failed\",\n })),\n );\n }\n };\n}\n\n/** Pre-configured terminal plugin with defaults */\nexport const defaultTerminalPlugin = createTerminalPlugin();\n"]}
|
|
1
|
+
{"version":3,"file":"terminal-plugin.js","sourceRoot":"","sources":["../../src/terminal/terminal-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getH3App,\n markDefaultPluginProvided,\n} from \"../server/framework-request-handler.js\";\nimport { isNodeRuntime } from \"../shared/runtime.js\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { createRequire } from \"node:module\";\n/**\n * Nitro Plugin — Agent Terminal\n *\n * Starts a PTY WebSocket server alongside the app so the <AgentTerminal />\n * component can connect to a real CLI. Mounts a discovery endpoint at\n * /_agent-native/agent-terminal-info for the client component.\n *\n * Skips activation when running inside a frame (FRAME_PORT is set).\n */\n\nimport { defineEventHandler } from \"h3\";\n\n// ─── module-load self-heal: chmod node-pty's spawn-helper ─────────────────\n// pnpm can extract node-pty's prebuilds tarball without running the\n// post-install that chmods spawn-helper, leaving it as `-rw-r--r--` instead\n// of `-rwxr-xr-x`. Every PTY spawn then fails with `posix_spawnp failed`.\n// Run the fix synchronously at module load (static imports, sync fs calls)\n// so by the time ANY plugin worker starts spawning PTYs, the helper is\n// already executable.\n(function fixSpawnHelperPermissions() {\n if (!isNodeRuntime()) return;\n try {\n const req = createRequire(import.meta.url);\n const ptyPkg = req.resolve(\"node-pty/package.json\");\n const ptyDir = path.dirname(ptyPkg);\n const helper = path.join(\n ptyDir,\n \"prebuilds\",\n `${process.platform}-${process.arch}`,\n \"spawn-helper\",\n );\n if (fs.existsSync(helper)) {\n const mode = fs.statSync(helper).mode;\n if (!(mode & 0o100)) {\n fs.chmodSync(helper, 0o755);\n console.log(\n `[terminal] Fixed non-executable node-pty spawn-helper at ${helper}`,\n );\n }\n }\n } catch (err) {\n // node-pty not installed → stay silent here; createTerminalPlugin emits\n // the \"install node-pty\" message when the PTY server actually fails to\n // start. Logging twice for the same root cause just adds noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"MODULE_NOT_FOUND\" || code === \"ERR_MODULE_NOT_FOUND\") return;\n console.warn(\n \"[terminal] Could not verify node-pty spawn-helper permissions:\",\n (err as Error).message,\n );\n }\n})();\n\nexport interface TerminalPluginOptions {\n /** CLI command to run. Defaults to AGENT_CLI_COMMAND env or 'builder' */\n command?: string;\n /** Port for the WebSocket server. Defaults to AGENT_TERMINAL_PORT env or auto-assigned */\n port?: number;\n /** Enable in production. Defaults to AGENT_TERMINAL_ENABLED env or false in prod */\n enabledInProduction?: boolean;\n /** Auth check for WebSocket connections in production */\n authCheck?: (req: any) => boolean | Promise<boolean>;\n}\n\n// Vite's dev server can initialize Nitro plugins more than once during boot.\n// Module-scope flags ensure the \"node-pty not installed\" / \"Disabled in\n// production\" / \"Frame detected\" notices each fire at most once per process.\nlet _ptyMissingLogged = false;\nlet _disabledLogged = false;\nlet _frameDetectedLogged = false;\n\nexport function createTerminalPlugin(options: TerminalPluginOptions = {}) {\n return async (nitroApp: any) => {\n markDefaultPluginProvided(nitroApp, \"terminal\");\n // Terminal requires Node.js (PTY, child_process) — skip on edge runtimes\n if (!isNodeRuntime()) return;\n\n // Always mount /_agent-native/available-clis so the client doesn't get 404s\n getH3App(nitroApp).use(\n \"/_agent-native/available-clis\",\n defineEventHandler(async () => {\n try {\n const { CLI_REGISTRY, commandExists } =\n await import(\"./cli-registry.js\");\n const results = [];\n for (const [cmd, entry] of Object.entries(CLI_REGISTRY)) {\n results.push({\n command: cmd,\n label: entry.label,\n available: await commandExists(cmd),\n });\n }\n return results;\n } catch {\n return [];\n }\n }),\n );\n\n // Skip if running inside a frame\n if (process.env.FRAME_PORT) {\n if (!_frameDetectedLogged) {\n console.log(\"[terminal] Frame detected, skipping embedded terminal\");\n _frameDetectedLogged = true;\n }\n return;\n }\n\n const isProd = process.env.NODE_ENV === \"production\";\n const enabled =\n options.enabledInProduction ??\n (process.env.AGENT_TERMINAL_ENABLED === \"true\" || !isProd);\n\n if (!enabled) {\n if (!_disabledLogged) {\n console.log(\n \"[terminal] Disabled in production (set AGENT_TERMINAL_ENABLED=true to enable)\",\n );\n _disabledLogged = true;\n }\n // Mount a disabled info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({ available: false })),\n );\n return;\n }\n\n // Require authCheck in production to prevent unauthenticated shell access\n if (isProd && !options.authCheck) {\n console.error(\n \"[terminal] FATAL: authCheck is required when enabling the terminal in production. \" +\n \"Pass an authCheck function to createTerminalPlugin().\",\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: \"Terminal requires authCheck in production\",\n })),\n );\n return;\n }\n\n // Skip if a PTY server is already running (prevents leak on HMR rebuild)\n if (process.env.__AGENT_TERMINAL_RUNNING === \"true\") {\n const existingPort = process.env.AGENT_TERMINAL_PORT;\n console.log(\n `[terminal] PTY server already running on port ${existingPort}, skipping`,\n );\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: existingPort ? parseInt(existingPort, 10) : 0,\n command:\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\",\n })),\n );\n return;\n }\n\n const command =\n options.command || process.env.AGENT_CLI_COMMAND || \"builder\";\n const port =\n options.port ??\n (process.env.AGENT_TERMINAL_PORT\n ? parseInt(process.env.AGENT_TERMINAL_PORT, 10)\n : 0);\n\n // Mark as running BEFORE the async server start. The previous code only\n // set this AFTER `await createPtyWebSocketServer(...)`, which left a\n // TOCTOU window where two concurrent plugin invocations would both pass\n // the running-check, both spawn a server, and end up fighting for the\n // CLI's PTY pool — leading to `posix_spawnp failed` floods.\n process.env.__AGENT_TERMINAL_RUNNING = \"true\"; // guard:allow-env-mutation — process-wide running flag set once at boot, before any HTTP request handling, to coordinate concurrent plugin invocations\n\n try {\n const { createPtyWebSocketServer } = await import(\"./pty-server.js\");\n\n const result = await createPtyWebSocketServer({\n appDir: process.cwd(),\n command,\n port,\n authCheck: isProd ? options.authCheck : undefined,\n logPrefix: \"[terminal]\",\n });\n\n // Store port for other consumers\n process.env.AGENT_TERMINAL_PORT = String(result.port); // guard:allow-env-mutation — terminal subprocess port published once at boot, not per-request\n\n // Mount discovery endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: true,\n wsPort: result.port,\n command,\n })),\n );\n\n // Cleanup on shutdown (use once to avoid listener leak on hot-reload)\n const cleanup = () => result.close();\n process.once(\"SIGTERM\", cleanup);\n process.once(\"SIGINT\", cleanup);\n process.once(\"exit\", cleanup);\n\n if (process.env.DEBUG)\n console.log(\n `[terminal] Agent terminal ready (command: ${command}, port: ${result.port})`,\n );\n } catch (err) {\n // Clear the running flag so a retry can spawn a fresh server\n delete process.env.__AGENT_TERMINAL_RUNNING; // guard:allow-env-mutation — terminal subprocess boot failed, clearing boot-time sentinel so a later plugin retry can start cleanly\n\n // Distinguish \"node-pty not installed\" (expected when the user opts\n // out of the terminal feature) from real failures (port conflict,\n // native binding mismatch). Native deps are optional — log as info\n // so the dev console isn't filled with red noise.\n const code = (err as NodeJS.ErrnoException)?.code;\n const missingPty =\n code === \"ERR_MODULE_NOT_FOUND\" || code === \"MODULE_NOT_FOUND\";\n if (missingPty) {\n if (!_ptyMissingLogged) {\n console.log(\n \"[terminal] node-pty not installed — embedded terminal disabled. \" +\n \"Install with `pnpm add node-pty` to enable.\",\n );\n _ptyMissingLogged = true;\n }\n } else {\n console.error(\"[terminal] Failed to start PTY server:\", err);\n console.error(\n \"[terminal] If node-pty is installed but PTY fails to spawn, \" +\n \"try `pnpm rebuild node-pty` (common after switching Node \" +\n \"versions via fnm/nvm).\",\n );\n }\n\n // Mount a fallback info endpoint\n getH3App(nitroApp).use(\n \"/_agent-native/agent-terminal-info\",\n defineEventHandler(() => ({\n available: false,\n error: missingPty ? \"node-pty not installed\" : \"PTY server failed\",\n })),\n );\n }\n };\n}\n\n/** Pre-configured terminal plugin with defaults */\nexport const defaultTerminalPlugin = createTerminalPlugin();\n"]}
|
|
@@ -11,16 +11,18 @@ Agent-to-agent communication over HTTP. Agents discover each other, send message
|
|
|
11
11
|
|
|
12
12
|
A2A (agent-to-agent) is a JSON-RPC protocol for inter-agent communication. A mail agent can ask an analytics agent to run a query. A calendar agent can search issues in a project management agent. Each agent exposes its capabilities via an agent card and accepts work via a standard JSON-RPC endpoint.
|
|
13
13
|
|
|
14
|
+
A2A is the substrate for cross-app delegation in this framework — most prominently for [Dispatch](/docs/dispatch), which routes a single inbound message (Slack, email, etc.) to whichever app in the workspace is best suited to handle it.
|
|
15
|
+
|
|
14
16
|
Key concepts:
|
|
15
17
|
|
|
16
18
|
- **Agent card** — public metadata at `/.well-known/agent-card.json` describing skills and capabilities
|
|
17
|
-
- **JSON-RPC** —
|
|
19
|
+
- **JSON-RPC** — agent-native apps use `POST /_agent-native/a2a`; external/legacy peers may use `POST /a2a`
|
|
18
20
|
- **Tasks** — each message creates a task with a lifecycle (submitted, working, completed, failed, canceled)
|
|
19
|
-
- **
|
|
21
|
+
- **JWT bearer auth** — production A2A requires `A2A_SECRET` or an explicit legacy `apiKeyEnv`
|
|
20
22
|
|
|
21
23
|
## Server setup {#server-setup}
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
Most templates get A2A through the framework agent chat plugin. If you are mounting it yourself, call `mountA2A()` in a server plugin:
|
|
24
26
|
|
|
25
27
|
```ts
|
|
26
28
|
// server/plugins/a2a.ts
|
|
@@ -39,18 +41,30 @@ export default defineNitroPlugin((nitro) => {
|
|
|
39
41
|
examples: ["Show me signups by source this month"],
|
|
40
42
|
},
|
|
41
43
|
],
|
|
42
|
-
|
|
44
|
+
// Optional legacy external-peer bearer key. Prefer A2A_SECRET for
|
|
45
|
+
// agent-native workspace calls and production deployments.
|
|
46
|
+
apiKeyEnv: "A2A_API_KEY",
|
|
43
47
|
streaming: true, // enable message/stream
|
|
44
48
|
});
|
|
45
49
|
});
|
|
46
50
|
```
|
|
47
51
|
|
|
48
|
-
This mounts
|
|
52
|
+
This mounts:
|
|
53
|
+
|
|
54
|
+
- `GET /.well-known/agent-card.json` — public discovery metadata.
|
|
55
|
+
- `POST /_agent-native/a2a` — primary agent-native JSON-RPC endpoint.
|
|
56
|
+
- `POST /_agent-native/a2a/_process-task` — internal async processor route, signed with `A2A_SECRET`.
|
|
57
|
+
|
|
58
|
+
The client also falls back to `/a2a` for external agents that expose the legacy/simple path. Production agent-native deployments should set `A2A_SECRET`; without it, hosted runtimes fail closed instead of accepting unauthenticated remote work.
|
|
49
59
|
|
|
50
60
|
## Agent card {#agent-card}
|
|
51
61
|
|
|
52
62
|
The agent card is auto-generated from your config and served at `/.well-known/agent-card.json`. Other agents fetch it to discover your agent's skills.
|
|
53
63
|
|
|
64
|
+
### Per-tenant skill filtering {#agent-card-filtering}
|
|
65
|
+
|
|
66
|
+
The card endpoint is public, so the framework redacts skills whose IDs reveal per-user or per-org integrations before serving it. Any skill whose id starts with `mcp__user_<emailhash>_…` or `mcp__org_<orgid>_…` is dropped from the published card. Operator-controlled stdio MCP tools (loaded from `mcp.config.json`) and template-defined skills stay visible. This prevents an unauthenticated caller from fingerprinting which tenants exist or which integrations they have connected. See `packages/core/src/a2a/server.ts`.
|
|
67
|
+
|
|
54
68
|
```json
|
|
55
69
|
{
|
|
56
70
|
"name": "Analytics Agent",
|
|
@@ -81,14 +95,16 @@ The agent card is auto-generated from your config and served at `/.well-known/ag
|
|
|
81
95
|
|
|
82
96
|
## JSON-RPC methods {#json-rpc-methods}
|
|
83
97
|
|
|
84
|
-
All methods are called via `POST /a2a` with JSON-RPC 2.0 format:
|
|
98
|
+
All methods are called via `POST /_agent-native/a2a` with JSON-RPC 2.0 format:
|
|
99
|
+
|
|
100
|
+
| Method | Description | Key params |
|
|
101
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
|
|
102
|
+
| `message/send` | Send a message and wait for the completed task. Pass `async: true` to return immediately in `working` state and poll. | `message, contextId?, async?` |
|
|
103
|
+
| `message/stream` | Send a message, receive SSE task updates | `message, contextId?` |
|
|
104
|
+
| `tasks/get` | Fetch a task by ID — used to poll an async task to completion | `id` |
|
|
105
|
+
| `tasks/cancel` | Cancel a running task | `id` |
|
|
85
106
|
|
|
86
|
-
|
|
87
|
-
| ---------------- | ----------------------------------------- | --------------------- |
|
|
88
|
-
| `message/send` | Send a message, get a completed task back | `message, contextId?` |
|
|
89
|
-
| `message/stream` | Send a message, receive SSE task updates | `message, contextId?` |
|
|
90
|
-
| `tasks/get` | Fetch a task by ID | `id` |
|
|
91
|
-
| `tasks/cancel` | Cancel a running task | `id` |
|
|
107
|
+
When `message/send` is called with `async: true`, the JSON-RPC handler enqueues the task and self-fires a POST to an internal `/_agent-native/a2a/_process-task` route so the handler runs in a fresh function execution with its own full timeout. This route is authenticated with an HMAC token bound to the task ID (5-minute lifetime, signed with `A2A_SECRET`). It is mounted before the `/_agent-native/a2a` JSON-RPC route so h3's prefix matching does not swallow it.
|
|
92
108
|
|
|
93
109
|
Messages contain typed parts:
|
|
94
110
|
|
|
@@ -171,7 +187,9 @@ Tasks persist in the `a2a_tasks` SQL table and can be retrieved later via `tasks
|
|
|
171
187
|
|
|
172
188
|
## Security {#security}
|
|
173
189
|
|
|
174
|
-
Set `
|
|
190
|
+
Set `A2A_SECRET` on every production app that calls or receives A2A traffic. Agent-native callers sign JWT bearer tokens with this secret so receivers can verify the caller identity before the agent loop starts.
|
|
191
|
+
|
|
192
|
+
For external peers that still use a shared static token, set `apiKeyEnv` in your config to the name of an environment variable containing the expected bearer token:
|
|
175
193
|
|
|
176
194
|
```ts
|
|
177
195
|
// Config
|
|
@@ -184,7 +202,68 @@ mountA2A(app, {
|
|
|
184
202
|
const client = new A2AClient(url, process.env.A2A_API_KEY);
|
|
185
203
|
```
|
|
186
204
|
|
|
187
|
-
The agent card endpoint is always public (no auth) so other agents can discover capabilities. The `/a2a` JSON-RPC endpoint
|
|
205
|
+
The agent card endpoint is always public (no auth) so other agents can discover capabilities. The `/_agent-native/a2a` JSON-RPC endpoint accepts JWT bearer tokens signed by `A2A_SECRET`, and also accepts the legacy `apiKeyEnv` token when configured. In local development, auth can be omitted; in hosted production runtimes, missing A2A auth returns 503 instead of running unauthenticated.
|
|
206
|
+
|
|
207
|
+
### Auth policy boundary {#auth-policy}
|
|
208
|
+
|
|
209
|
+
Bearer validation runs at the request boundary — in the JSON-RPC handler — before the agent loop ever sees the message. The shared helpers in `packages/core/src/a2a/auth-policy.ts` decide what the deployment requires:
|
|
210
|
+
|
|
211
|
+
- `isA2AProductionRuntime()` returns `true` on Netlify, AWS Lambda, Cloudflare Pages/Workers, Vercel, Render, Fly, and Cloud Run — even when `NODE_ENV` isn't `"production"`. Some serverless providers don't set `NODE_ENV` consistently, so the policy reads provider-specific flags too.
|
|
212
|
+
- `hasConfiguredA2ASecret()` returns `true` when `A2A_SECRET` is set.
|
|
213
|
+
- `shouldAdvertiseJwtA2AAuth()` is what the agent card uses to decide whether to publish a `jwtBearer` security scheme.
|
|
214
|
+
|
|
215
|
+
The production policy is strict: in any production runtime, the async `_process-task` route refuses to dispatch unless `A2A_SECRET` is configured (returns 503), and the JSON-RPC endpoint refuses unauthenticated calls. The dev fallback (warn once, allow) only fires when no production flag is set.
|
|
216
|
+
|
|
217
|
+
This boundary matters because the agent loop accepts free-form input from a remote caller. Putting the bearer check inside the loop, or relying on a tool to enforce it, would let prompt-injection or a buggy handler bypass auth. Keeping it at the HTTP boundary means a token failure short-circuits before any LLM call.
|
|
218
|
+
|
|
219
|
+
JWT verification (`verifyA2AToken` in `server.ts`) accepts tokens signed with either the global `A2A_SECRET` or an org-scoped secret looked up from SQL via the token's `org_domain` claim, and enforces the token's own `aud`/`iss` claims when present.
|
|
220
|
+
|
|
221
|
+
## Continuations {#continuations}
|
|
222
|
+
|
|
223
|
+
When an agent calls a remote A2A peer that doesn't return immediately, the framework polls `tasks/get` until the task settles. This is wired through `A2AClient.sendAndWait`, which is the default mode used by the `callAgent()` helper.
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// Default: async + poll (safe on serverless hosts)
|
|
227
|
+
const reply = await callAgent(url, "Generate the quarterly report", {
|
|
228
|
+
userEmail: session.user.email,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Single-shot blocking POST (avoid on Netlify/Vercel for slow handlers)
|
|
232
|
+
const reply2 = await callAgent(url, "Quick lookup", { async: false });
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
For inbound continuations triggered by a messaging integration (Slack, email), the framework persists the continuation in SQL and processes it out-of-band:
|
|
236
|
+
|
|
237
|
+
- A row is written to the `a2a_continuations` table when the integration handler hands off to a remote agent.
|
|
238
|
+
- A self-fired `POST /_agent-native/integrations/process-a2a-continuation` claims the row, calls `tasks/get` on the remote agent, and either delivers the reply to the integration adapter or reschedules.
|
|
239
|
+
- If the remote task is still working, the row is rescheduled and re-dispatched. The poll budget is **bounded by ~10 minutes of remote work** (`MAX_REMOTE_WORK_MS`) and **6 dispatch attempts** (`MAX_ATTEMPTS`); after either limit, the continuation is failed with a clear error and the user gets a "the agent didn't respond in time" reply.
|
|
240
|
+
- A recurring sweeper (`claimDueA2AContinuations`) re-claims any continuation rows that were left in flight when the previous function execution died. Even if the calling app crashes mid-poll, the next sweep tick resumes the work.
|
|
241
|
+
|
|
242
|
+
Defined in `packages/core/src/integrations/a2a-continuation-processor.ts`. The same retry job pattern is used for integration webhook tasks (`pending-tasks-retry-job.ts`, capped at 3 attempts).
|
|
243
|
+
|
|
244
|
+
## Workspace A2A {#workspace-a2a}
|
|
245
|
+
|
|
246
|
+
In a multi-app workspace deployed to a single Netlify site (see [multi-app workspace](/docs/multi-app-workspace)), every app under `apps/<id>/` is auto-registered as an A2A peer:
|
|
247
|
+
|
|
248
|
+
- A shared `A2A_SECRET` is mounted into every app's environment at build time.
|
|
249
|
+
- Cross-app calls are same-origin — `https://workspace.example.com/apps/analytics` calls `https://workspace.example.com/apps/mail` — so there is no DNS, CORS, or per-pair JWT setup.
|
|
250
|
+
- Outbound calls signed with the shared secret carry the caller's email as `sub` and (when present) the org domain. The receiver's JWT verifier accepts either the shared secret or the org-scoped secret from SQL, in that order.
|
|
251
|
+
- Agent discovery walks the workspace registry rather than relying on the operator to wire each peer by hand. See `discoverAgents` in `packages/core/src/server/agent-discovery.ts` and the org refresh path in `packages/core/src/org/handlers.ts`.
|
|
252
|
+
|
|
253
|
+
External A2A — calls to agents outside your workspace — still uses the bearer-token model (`apiKeyEnv` + `A2AClient(url, apiKey)`). Workspace A2A is layered on top; nothing about external peers changes.
|
|
254
|
+
|
|
255
|
+
## Serverless gotchas {#serverless}
|
|
256
|
+
|
|
257
|
+
**Never rely on a fire-and-forget `Promise` outliving the response.** Serverless functions (Netlify, Vercel, AWS Lambda, Cloud Run) freeze the moment the response body is flushed — sometimes before the TCP handshake of an unawaited `fetch(...)` even completes. Patterns that work locally on Node will silently drop work in production.
|
|
258
|
+
|
|
259
|
+
The framework's pattern, used by both A2A async dispatch and the [integration webhook queue](/docs/messaging), is:
|
|
260
|
+
|
|
261
|
+
1. Accept the request, persist what needs to happen to SQL, return 200 immediately.
|
|
262
|
+
2. Self-fire a `POST` to a separate framework route (`/_agent-native/a2a/_process-task` or `/_agent-native/integrations/process-task`) so the actual work runs in a **fresh function execution** with its own full timeout.
|
|
263
|
+
3. Authenticate the self-fire with an HMAC token bound to the row id, signed with `A2A_SECRET`.
|
|
264
|
+
4. A recurring retry job sweeps any rows that were claimed but not finished, so a crashed function doesn't strand the work.
|
|
265
|
+
|
|
266
|
+
When you write your own A2A handler or integration adapter, follow the same shape. Don't attach work to a detached promise after `return`. If you must self-fire from a serverless handler, start the fetch before returning and give it a tiny head start (the framework uses a short timeout) so Lambda-style runtimes do not freeze before the outbound request leaves the process. The `integration-webhooks` skill is the canonical reference.
|
|
188
267
|
|
|
189
268
|
## Agent mentions {#agent-mentions}
|
|
190
269
|
|
|
@@ -60,7 +60,7 @@ Agents become available for mentioning through several mechanisms:
|
|
|
60
60
|
|
|
61
61
|
- **Custom workspace agents** — create agent profiles in the Workspace tab as `agents/*.md`
|
|
62
62
|
- **Auto-discovery** — the framework automatically discovers connected agents running on known ports or configured URLs
|
|
63
|
-
- **Remote manifests** — add connected-agent manifests as `agents/*.json`
|
|
63
|
+
- **Remote manifests** — add connected-agent manifests as `remote-agents/*.json`
|
|
64
64
|
|
|
65
65
|
### Custom workspace agents
|
|
66
66
|
|
|
@@ -91,7 +91,7 @@ You can create them from the Workspace tab using:
|
|
|
91
91
|
Remote A2A agents still use JSON manifests:
|
|
92
92
|
|
|
93
93
|
```json
|
|
94
|
-
// agents/analytics.json
|
|
94
|
+
// remote-agents/analytics.json
|
|
95
95
|
{
|
|
96
96
|
"name": "Analytics Agent",
|
|
97
97
|
"url": "https://analytics.example.com",
|
|
@@ -52,12 +52,12 @@ import { spawnTask } from "@agent-native/core/server";
|
|
|
52
52
|
|
|
53
53
|
const task = await spawnTask({
|
|
54
54
|
description: "Draft an outreach email to this lead",
|
|
55
|
-
instructions: "Match Steve's voice from
|
|
55
|
+
instructions: "Match Steve's voice from memory/MEMORY.md.",
|
|
56
56
|
ownerEmail: user.email,
|
|
57
57
|
systemPrompt: mailAgentSystemPrompt,
|
|
58
58
|
actions: mailActions,
|
|
59
59
|
apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
60
|
-
parentSend: emit, //
|
|
60
|
+
parentSend: emit, // streaming sender for the parent chat response
|
|
61
61
|
});
|
|
62
62
|
```
|
|
63
63
|
|
package/docs/content/client.md
CHANGED
|
@@ -158,7 +158,7 @@ function App() {
|
|
|
158
158
|
| `queryClient` | `QueryClient?` | React-query client for cache invalidation |
|
|
159
159
|
| `queryKeys` | `string[]?` | Query key prefixes to invalidate. Default: `["file", "fileTree"]` |
|
|
160
160
|
| `pollUrl` | `string?` | Poll endpoint URL. Default: `"/_agent-native/poll"` |
|
|
161
|
-
| `onEvent` | `(data) => void` | Optional callback
|
|
161
|
+
| `onEvent` | `(data) => void` | Optional callback when a poll detects a newer sync version |
|
|
162
162
|
|
|
163
163
|
## cn(...inputs) {#cn}
|
|
164
164
|
|
|
@@ -15,19 +15,19 @@ We call them **cloneable SaaS**, not templates. You're not starting from scratch
|
|
|
15
15
|
|
|
16
16
|
Each one is a real app you could use today, and the launching pad for your own version of it.
|
|
17
17
|
|
|
18
|
-
| Template | What it is
|
|
19
|
-
| ------------- |
|
|
20
|
-
| **Mail** | An agent-native Superhuman. Inbox, labels, AI triage, keyboard-first, drafts and sends through the agent.
|
|
21
|
-
| **Calendar** | An agent-native Google Calendar. Events, sync, public booking links, agent-driven scheduling.
|
|
22
|
-
| **Content** | An agent-native Notion / Google Docs. Markdown + Tiptap editor, Notion sync, real-time multi-user collab.
|
|
23
|
-
| **Slides** | An agent-native Google Slides. React-based decks the agent generates and edits directly.
|
|
24
|
-
| **Video** | An agent-native video editor on Remotion. Prompt for a cut, the agent assembles it.
|
|
25
|
-
| **Analytics** | An agent-native Amplitude/Mixpanel. Connect data sources, prompt for charts, pin to dashboards.
|
|
26
|
-
| **Clips** | An agent-native Loom. Async screen + camera recording with transcription, chapters, AI summaries.
|
|
27
|
-
| **Design** |
|
|
28
|
-
| **Forms** | An agent-native Typeform. Build, share, and
|
|
29
|
-
| **Dispatch** | The workspace control plane: shared secrets, cross-app integrations, Slack/Telegram, scheduled jobs.
|
|
30
|
-
| **Starter** | The minimal scaffold. Agent chat plus the architecture, nothing else. Build something new.
|
|
18
|
+
| Template | What it is |
|
|
19
|
+
| ------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
20
|
+
| **Mail** | An agent-native Superhuman. Inbox, labels, AI triage, keyboard-first, drafts and sends through the agent. |
|
|
21
|
+
| **Calendar** | An agent-native Google Calendar. Events, sync, public booking links, agent-driven scheduling. |
|
|
22
|
+
| **Content** | An agent-native Notion / Google Docs. Markdown + Tiptap editor, Notion sync, real-time multi-user collab. |
|
|
23
|
+
| **Slides** | An agent-native Google Slides. React-based decks the agent generates and edits directly. |
|
|
24
|
+
| **Video** | An agent-native video editor on Remotion. Prompt for a cut, the agent assembles it. |
|
|
25
|
+
| **Analytics** | An agent-native Amplitude/Mixpanel. Connect data sources, prompt for charts, pin to dashboards. |
|
|
26
|
+
| **Clips** | An agent-native Loom. Async screen + camera recording with transcription, chapters, AI summaries. |
|
|
27
|
+
| **Design** | Agent-native HTML prototyping studio for interactive Alpine/Tailwind designs. |
|
|
28
|
+
| **Forms** | An agent-native Typeform. Build, share, collect, and route submissions to Slack, Sheets, webhooks, or Discord. |
|
|
29
|
+
| **Dispatch** | The workspace control plane: shared secrets, cross-app integrations, Slack/Telegram, scheduled jobs. |
|
|
30
|
+
| **Starter** | The minimal scaffold. Agent chat plus the architecture, nothing else. Build something new. |
|
|
31
31
|
|
|
32
32
|
See the full catalog under [Templates](/templates), or jump straight to one — for example, [Dispatch](/docs/template-dispatch) is a great place to start if you want a workspace-style app.
|
|
33
33
|
|