@agent-native/core 0.131.6 → 0.131.9

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.
Files changed (113) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +31 -0
  3. package/corpus/core/docs/content/deployment.mdx +12 -10
  4. package/corpus/core/docs/content/security.mdx +2 -2
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/a2a/invoke.ts +4 -2
  7. package/corpus/core/src/agent/action-continuation-guidance.ts +2 -1
  8. package/corpus/core/src/agent/engine/registry.ts +61 -9
  9. package/corpus/core/src/application-state/store.ts +18 -31
  10. package/corpus/core/src/cli/create.ts +115 -16
  11. package/corpus/core/src/client/AssistantChat.tsx +10 -2
  12. package/corpus/core/src/client/frame-protocol.ts +5 -1
  13. package/corpus/core/src/guards/no-env-credentials.ts +2 -0
  14. package/corpus/core/src/scripts/call-agent.ts +4 -2
  15. package/corpus/core/src/secrets/crypto.ts +44 -15
  16. package/corpus/core/src/secrets/storage.ts +6 -4
  17. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +2 -0
  18. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +14 -9
  19. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +14 -9
  20. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -9
  21. package/corpus/core/src/workspace-files/tool.ts +18 -11
  22. package/corpus/templates/analytics/AGENTS.md +1 -0
  23. package/corpus/templates/analytics/changelog/2026-07-30-delegated-analytics-questions-now-return-a-useful-current-me.md +6 -0
  24. package/corpus/templates/analytics/server/lib/real-data-actions.ts +10 -0
  25. package/corpus/templates/clips/actions/generate-workflow.ts +6 -4
  26. package/corpus/templates/clips/actions/reconcile-workflow-generation.ts +257 -0
  27. package/corpus/templates/clips/app/hooks/use-auto-title.ts +166 -4
  28. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
  29. package/corpus/templates/clips/changelog/2026-07-27-stopped-agent-runs-no-longer-leave-generated-workflow-cards-.md +6 -0
  30. package/corpus/templates/clips/changelog/2026-07-30-workflow-generation-now-stops-retrying-after-repeated-failur.md +6 -0
  31. package/corpus/templates/clips/shared/workflow.ts +5 -0
  32. package/corpus/templates/plan/actions/get-visual-plan.ts +10 -6
  33. package/corpus/templates/plan/actions/patch-visual-plan-source.ts +117 -1
  34. package/corpus/templates/plan/actions/update-visual-plan.ts +56 -14
  35. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
  36. package/corpus/templates/plan/changelog/2026-07-30-plan-agents-recover-with-targeted-writes.md +6 -0
  37. package/corpus/templates/plan/shared/plan-content.ts +35 -0
  38. package/corpus/templates/slides/actions/create-deck.ts +1 -1
  39. package/corpus/templates/slides/changelog/2026-07-30-new-decks-now-start-with-an-empty-slide-list-when-no-slides-.md +6 -0
  40. package/dist/a2a/invoke.d.ts.map +1 -1
  41. package/dist/a2a/invoke.js +4 -2
  42. package/dist/a2a/invoke.js.map +1 -1
  43. package/dist/agent/action-continuation-guidance.d.ts.map +1 -1
  44. package/dist/agent/action-continuation-guidance.js +2 -1
  45. package/dist/agent/action-continuation-guidance.js.map +1 -1
  46. package/dist/agent/engine/registry.d.ts.map +1 -1
  47. package/dist/agent/engine/registry.js +59 -12
  48. package/dist/agent/engine/registry.js.map +1 -1
  49. package/dist/application-state/store.d.ts.map +1 -1
  50. package/dist/application-state/store.js +20 -36
  51. package/dist/application-state/store.js.map +1 -1
  52. package/dist/cli/create.d.ts +8 -1
  53. package/dist/cli/create.d.ts.map +1 -1
  54. package/dist/cli/create.js +98 -16
  55. package/dist/cli/create.js.map +1 -1
  56. package/dist/client/AssistantChat.d.ts.map +1 -1
  57. package/dist/client/AssistantChat.js +10 -2
  58. package/dist/client/AssistantChat.js.map +1 -1
  59. package/dist/client/frame-protocol.d.ts +1 -0
  60. package/dist/client/frame-protocol.d.ts.map +1 -1
  61. package/dist/client/frame-protocol.js.map +1 -1
  62. package/dist/collab/routes.d.ts +1 -1
  63. package/dist/collab/struct-routes.d.ts +1 -1
  64. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  65. package/dist/guards/no-env-credentials.d.ts.map +1 -1
  66. package/dist/guards/no-env-credentials.js +2 -0
  67. package/dist/guards/no-env-credentials.js.map +1 -1
  68. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  69. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  70. package/dist/notifications/routes.d.ts +6 -6
  71. package/dist/observability/routes.d.ts +3 -3
  72. package/dist/scripts/call-agent.d.ts.map +1 -1
  73. package/dist/scripts/call-agent.js +4 -2
  74. package/dist/scripts/call-agent.js.map +1 -1
  75. package/dist/secrets/crypto.d.ts +14 -9
  76. package/dist/secrets/crypto.d.ts.map +1 -1
  77. package/dist/secrets/crypto.js +42 -16
  78. package/dist/secrets/crypto.js.map +1 -1
  79. package/dist/secrets/storage.d.ts +6 -4
  80. package/dist/secrets/storage.d.ts.map +1 -1
  81. package/dist/secrets/storage.js +6 -4
  82. package/dist/secrets/storage.js.map +1 -1
  83. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  84. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  85. package/dist/server/agent-chat/action-filters-a2a.js +2 -0
  86. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  87. package/dist/server/realtime-token.d.ts +1 -1
  88. package/dist/server/transcribe-voice.d.ts +1 -1
  89. package/dist/templates/default/.agents/skills/secrets/SKILL.md +14 -9
  90. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +14 -9
  91. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -9
  92. package/dist/workspace-files/tool.d.ts.map +1 -1
  93. package/dist/workspace-files/tool.js +18 -11
  94. package/dist/workspace-files/tool.js.map +1 -1
  95. package/docs/content/deployment.mdx +12 -10
  96. package/docs/content/security.mdx +2 -2
  97. package/package.json +1 -1
  98. package/src/a2a/invoke.ts +4 -2
  99. package/src/agent/action-continuation-guidance.ts +2 -1
  100. package/src/agent/engine/registry.ts +61 -9
  101. package/src/application-state/store.ts +18 -31
  102. package/src/cli/create.ts +115 -16
  103. package/src/client/AssistantChat.tsx +10 -2
  104. package/src/client/frame-protocol.ts +5 -1
  105. package/src/guards/no-env-credentials.ts +2 -0
  106. package/src/scripts/call-agent.ts +4 -2
  107. package/src/secrets/crypto.ts +44 -15
  108. package/src/secrets/storage.ts +6 -4
  109. package/src/server/agent-chat/action-filters-a2a.ts +2 -0
  110. package/src/templates/default/.agents/skills/secrets/SKILL.md +14 -9
  111. package/src/templates/headless/.agents/skills/secrets/SKILL.md +14 -9
  112. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -9
  113. package/src/workspace-files/tool.ts +18 -11
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/secrets/crypto.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared AES-256-GCM encryption for secret values at rest.\n *\n * Used by the framework secrets vault, per-user/per-org credentials\n * (`resolveCredential` / `saveCredential`, stored in `settings`), and other\n * column-level encrypted values. The `app_secrets` storage layer uses the\n * shared-key variant below because workspace-scoped vault rows are readable by\n * sibling apps in the same workspace. When a deployment has not been given\n * shared key material yet, that variant falls back to the app-scoped key so\n * existing single-app deployments can keep reading and writing secrets while\n * they migrate to the shared key.\n *\n * The generic encryption key is derived from\n * `<APP_NAME>_SECRETS_ENCRYPTION_KEY` when set, then\n * `SECRETS_ENCRYPTION_KEY`, then `BETTER_AUTH_SECRET`. Workspace-shared vault\n * rows use a different precedence: `SECRETS_ENCRYPTION_KEY`, then material\n * derived from the workspace-wide `A2A_SECRET`, then the app-local auth/key\n * fallbacks retained for backward-compatible reads. This keeps sibling apps\n * on one key even when each app correctly has a different auth secret.\n *\n * In production we refuse to start without configured key material — a\n * CWD-derived fallback would be effectively static (e.g. `/var/task` on\n * Lambda), so anyone with read access to the DB could decrypt every secret.\n *\n * Encrypted values are tagged `v1:<iv-hex>:<ct-hex>:<tag-hex>`. The `v1:` prefix\n * lets readers distinguish ciphertext from legacy plaintext during migration.\n */\n\nimport {\n deriveServerSecret,\n getWorkspaceA2ADerivedSecret,\n} from \"../server/derived-secret.js\";\n\ntype NodeCryptoModule = typeof import(\"node:crypto\");\n\nfunction getNodeCrypto(): NodeCryptoModule | undefined {\n if (\n typeof window !== \"undefined\" ||\n typeof process === \"undefined\" ||\n !process.versions?.node ||\n typeof process.getBuiltinModule !== \"function\"\n ) {\n return undefined;\n }\n return process.getBuiltinModule(\"node:crypto\") as\n | NodeCryptoModule\n | undefined;\n}\n\nconst nodeCrypto = getNodeCrypto();\n\nlet _warnedFallback = false;\n\nfunction requireNodeCrypto(): NonNullable<typeof nodeCrypto> {\n if (!nodeCrypto) {\n throw new Error(\n \"[agent-native/secrets] Secret encryption is only available in server/runtime code.\",\n );\n }\n return nodeCrypto;\n}\n\nfunction processNodeEnv(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env.NODE_ENV;\n}\n\nfunction processCwd(): string {\n if (typeof process === \"undefined\") return \".\";\n return process.cwd();\n}\n\nfunction appScopedEncryptionKey(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n const appName = process.env.APP_NAME?.trim() // guard:allow-env-credential — deploy-level app configuration selects the scoped encryption key.\n .toUpperCase()\n .replace(/[^A-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n return appName\n ? process.env[`${appName}_SECRETS_ENCRYPTION_KEY`] // guard:allow-env-credential — deploy-level app encryption material, never a user credential.\n : undefined;\n}\n\n/**\n * Preserve the generic/app-local key precedence. Generic encrypted values are\n * not a cross-app boundary, and changing their preferred key would strand\n * existing OAuth tokens and credentials.\n */\nfunction genericEncryptionKeyMaterial(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return (\n process.env.SECRETS_ENCRYPTION_KEY ||\n process.env.BETTER_AUTH_SECRET ||\n getWorkspaceA2ADerivedSecret(\"secrets-encryption\")\n );\n}\n\n/**\n * Vault sharing follows configured A2A trust even on independently deployed\n * sibling apps that are not launched by the workspace wrapper. The wrapper's\n * `AGENT_NATIVE_WORKSPACE` flag remains required for auth/OAuth-derived\n * secrets, but it must not be a hidden prerequisite for decrypting vault rows\n * when every app already has the same explicit `A2A_SECRET`.\n */\nfunction a2aSharedEncryptionKeyMaterial(): string | undefined {\n const workspaceDerived = getWorkspaceA2ADerivedSecret(\"secrets-encryption\");\n if (workspaceDerived) return workspaceDerived;\n if (typeof process === \"undefined\") return undefined;\n const rootSecret = process.env.A2A_SECRET?.trim();\n return rootSecret\n ? deriveServerSecret(rootSecret, \"secrets-encryption\")\n : undefined;\n}\n\n/**\n * Stable materials that may be used for workspace-shared vault rows, ordered\n * from current preference to legacy compatibility fallbacks.\n *\n * `BETTER_AUTH_SECRET` deliberately comes after the A2A-derived material:\n * sibling apps normally have different auth secrets but share A2A trust.\n */\nfunction sharedEncryptionKeyMaterials(): string[] {\n if (typeof process === \"undefined\") return [];\n const candidates = [\n process.env.SECRETS_ENCRYPTION_KEY,\n a2aSharedEncryptionKeyMaterial(),\n process.env.BETTER_AUTH_SECRET,\n appScopedEncryptionKey(),\n ].filter((value): value is string => Boolean(value));\n return [...new Set(candidates)];\n}\n\nfunction preferredSharedEncryptionKeyMaterial(): string | undefined {\n return sharedEncryptionKeyMaterials()[0];\n}\n\nfunction hashSecretEncryptionKey(material: string): Buffer {\n const { createHash } = requireNodeCrypto();\n return createHash(\"sha256\").update(material).digest();\n}\n\nfunction deriveSecretEncryptionKey(\n explicit: string | undefined,\n errorMessage: string,\n warningMessage: string,\n): Buffer {\n if (!explicit) {\n if (processNodeEnv() === \"production\") {\n throw new Error(errorMessage);\n }\n if (!_warnedFallback) {\n _warnedFallback = true;\n // eslint-disable-next-line no-console\n console.warn(warningMessage);\n }\n }\n\n const material = explicit || `agent-native-secrets:${processCwd()}`;\n return hashSecretEncryptionKey(material);\n}\n\n/**\n * Derive the key used by generic encrypted values such as credentials and\n * OAuth tokens. App-specific key material is allowed for these app-local\n * values.\n */\nexport function getSecretEncryptionKey(): Buffer {\n const appName =\n typeof process === \"undefined\"\n ? undefined\n : process.env.APP_NAME?.trim() // guard:allow-env-credential — deploy-level app configuration selects the scoped encryption key.\n .toUpperCase()\n .replace(/[^A-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n return deriveSecretEncryptionKey(\n appScopedEncryptionKey() || genericEncryptionKeyMaterial(),\n \"[agent-native/secrets] Refusing to start in production without an encryption key. \" +\n `Set ${appName ? `${appName}_SECRETS_ENCRYPTION_KEY, ` : \"\"}SECRETS_ENCRYPTION_KEY, or BETTER_AUTH_SECRET in the deploy environment. ` +\n \"The previous CWD-derived fallback was effectively static (e.g. `/var/task` on Lambda), \" +\n \"which means anyone with read access to the DB could decrypt every secret.\",\n \"[agent-native/secrets] SECRETS_ENCRYPTION_KEY not set — using a machine-local fallback. \" +\n \"Set an app-scoped *_SECRETS_ENCRYPTION_KEY, SECRETS_ENCRYPTION_KEY, or BETTER_AUTH_SECRET for production. \" +\n \"Production deploys without one of these env vars now hard-fail.\",\n );\n}\n\n/**\n * Derive the preferred workspace-shared key used by `app_secrets` rows.\n * Unlike generic column-level encryption, workspace vault data must decrypt\n * in sibling apps. An explicit `SECRETS_ENCRYPTION_KEY` wins; hosted\n * workspaces otherwise derive stable material from their shared `A2A_SECRET`\n * before considering app-local `BETTER_AUTH_SECRET` or app-scoped key\n * fallbacks. Reads try every configured legacy candidate and report when the\n * ciphertext should be refreshed under the preferred key.\n */\nexport function getSharedSecretEncryptionKey(): Buffer {\n return deriveSecretEncryptionKey(\n preferredSharedEncryptionKeyMaterial(),\n \"[agent-native/secrets] Refusing to start in production without encryption key material for workspace secrets. \" +\n \"Set SECRETS_ENCRYPTION_KEY, ensure a hosted workspace has A2A_SECRET, or set BETTER_AUTH_SECRET / an app-scoped \" +\n \"*_SECRETS_ENCRYPTION_KEY compatibility fallback in the deploy environment.\",\n \"[agent-native/secrets] SECRETS_ENCRYPTION_KEY not set — using app-scoped or machine-local fallback for workspace secrets. \" +\n \"Set SECRETS_ENCRYPTION_KEY or rely on A2A_SECRET-derived material on hosted workspace deploys so sibling apps share vault rows.\",\n );\n}\n\n/** Whether this deployment has stable workspace-shared key material. */\nexport function hasSharedSecretEncryptionKeyMaterial(): boolean {\n if (typeof process === \"undefined\") return false;\n return Boolean(\n process.env.SECRETS_ENCRYPTION_KEY ||\n a2aSharedEncryptionKeyMaterial() ||\n process.env.BETTER_AUTH_SECRET,\n );\n}\n\nfunction encryptWithKey(plaintext: string, key: Buffer): string {\n const { createCipheriv, randomBytes } = requireNodeCrypto();\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const ct = Buffer.concat([cipher.update(plaintext, \"utf8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n return `v1:${iv.toString(\"hex\")}:${ct.toString(\"hex\")}:${tag.toString(\"hex\")}`;\n}\n\nfunction decryptWithKey(encrypted: string, key: Buffer): string {\n const { createDecipheriv } = requireNodeCrypto();\n if (!encrypted.startsWith(\"v1:\")) {\n throw new Error(\"Unrecognised secret encoding\");\n }\n const [, ivHex, ctHex, tagHex] = encrypted.split(\":\");\n if (!ivHex || !ctHex || !tagHex) {\n throw new Error(\"Corrupt secret payload\");\n }\n const decipher = createDecipheriv(\n \"aes-256-gcm\",\n key,\n Buffer.from(ivHex, \"hex\"),\n );\n decipher.setAuthTag(Buffer.from(tagHex, \"hex\"));\n const pt = Buffer.concat([\n decipher.update(Buffer.from(ctHex, \"hex\")),\n decipher.final(),\n ]);\n return pt.toString(\"utf8\");\n}\n\n/** Encrypt a plain-text value with the generic app-local key. */\nexport function encryptSecretValue(plaintext: string): string {\n return encryptWithKey(plaintext, getSecretEncryptionKey());\n}\n\n/** Decrypt a value produced by `encryptSecretValue`. Throws on tampering. */\nexport function decryptSecretValue(encrypted: string): string {\n return decryptWithKey(encrypted, getSecretEncryptionKey());\n}\n\n/** Encrypt a workspace-shared `app_secrets` value. */\nexport function encryptSharedSecretValue(plaintext: string): string {\n return encryptWithKey(plaintext, getSharedSecretEncryptionKey());\n}\n\n/** Decrypt a workspace-shared `app_secrets` value. */\nexport function decryptSharedSecretValue(encrypted: string): string {\n return decryptSharedSecretValueDetailed(encrypted).value;\n}\n\nexport interface DecryptedSharedSecretValue {\n value: string;\n /**\n * True when a legacy app-local candidate decrypted the value. Callers that\n * own the row should opportunistically re-encrypt it with the preferred\n * workspace key.\n */\n needsReencrypt: boolean;\n}\n\n/**\n * Decrypt workspace ciphertext with the preferred key first, then configured\n * legacy candidates. The result never exposes which secret material matched.\n */\nexport function decryptSharedSecretValueDetailed(\n encrypted: string,\n): DecryptedSharedSecretValue {\n const preferredKey = getSharedSecretEncryptionKey();\n const candidateKeys = [preferredKey];\n for (const material of sharedEncryptionKeyMaterials()) {\n const candidate = hashSecretEncryptionKey(material);\n if (!candidateKeys.some((existing) => existing.equals(candidate))) {\n candidateKeys.push(candidate);\n }\n }\n\n let lastError: unknown;\n for (const candidate of candidateKeys) {\n try {\n return {\n value: decryptWithKey(encrypted, candidate),\n needsReencrypt: !candidate.equals(preferredKey),\n };\n } catch (error) {\n lastError = error;\n }\n }\n throw lastError instanceof Error\n ? lastError\n : new Error(\"Unable to decrypt workspace secret\");\n}\n\n/**\n * Strict check for a value produced by `encryptSecretValue`: `v1:` followed by\n * three hex segments. Intentionally strict so a legacy plaintext credential\n * that merely happens to start with `v1:` is treated as plaintext (and read via\n * the legacy fallback) rather than mis-decrypted.\n */\nconst ENCRYPTED_VALUE_RE = /^v1:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$/;\n\nexport function isEncryptedSecretValue(value: unknown): value is string {\n return typeof value === \"string\" && ENCRYPTED_VALUE_RE.test(value);\n}\n"]}
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/secrets/crypto.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared AES-256-GCM encryption for secret values at rest.\n *\n * Used by the framework secrets vault, per-user/per-org credentials\n * (`resolveCredential` / `saveCredential`, stored in `settings`), and other\n * column-level encrypted values. The `app_secrets` storage layer uses the\n * shared-key variant below because workspace-scoped vault rows are readable by\n * sibling apps in the same workspace. When a deployment has not been given\n * shared key material yet, that variant falls back to the app-scoped key so\n * existing single-app deployments can keep reading and writing secrets while\n * they migrate to the shared key.\n *\n * The generic encryption key is derived from\n * `<APP_NAME>_SECRETS_ENCRYPTION_KEY` when set, then\n * `SECRETS_ENCRYPTION_KEY`, then `BETTER_AUTH_SECRET`. Workspace-shared vault\n * rows use a different precedence: `WORKSPACE_SECRETS_ENCRYPTION_KEY`, then\n * the legacy shared `SECRETS_ENCRYPTION_KEY`, then material derived from the\n * workspace-wide `A2A_SECRET`, then the app-local auth/key fallbacks retained\n * for backward-compatible reads. A previous workspace key can be supplied\n * during rotation with `WORKSPACE_SECRETS_ENCRYPTION_KEY_PREVIOUS`. This keeps\n * sibling apps on one stable key even when each app correctly has a different\n * auth secret, and prevents A2A trust rotation from stranding vault data.\n *\n * In production we refuse to start without configured key material — a\n * CWD-derived fallback would be effectively static (e.g. `/var/task` on\n * Lambda), so anyone with read access to the DB could decrypt every secret.\n *\n * Encrypted values are tagged `v1:<iv-hex>:<ct-hex>:<tag-hex>`. The `v1:` prefix\n * lets readers distinguish ciphertext from legacy plaintext during migration.\n */\n\nimport {\n deriveServerSecret,\n getWorkspaceA2ADerivedSecret,\n} from \"../server/derived-secret.js\";\n\ntype NodeCryptoModule = typeof import(\"node:crypto\");\n\nfunction getNodeCrypto(): NodeCryptoModule | undefined {\n if (\n typeof window !== \"undefined\" ||\n typeof process === \"undefined\" ||\n !process.versions?.node ||\n typeof process.getBuiltinModule !== \"function\"\n ) {\n return undefined;\n }\n return process.getBuiltinModule(\"node:crypto\") as\n | NodeCryptoModule\n | undefined;\n}\n\nconst nodeCrypto = getNodeCrypto();\n\nlet _warnedFallback = false;\n\nfunction requireNodeCrypto(): NonNullable<typeof nodeCrypto> {\n if (!nodeCrypto) {\n throw new Error(\n \"[agent-native/secrets] Secret encryption is only available in server/runtime code.\",\n );\n }\n return nodeCrypto;\n}\n\nfunction processNodeEnv(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env.NODE_ENV;\n}\n\nfunction processCwd(): string {\n if (typeof process === \"undefined\") return \".\";\n return process.cwd();\n}\n\nfunction appScopedEncryptionKey(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n const appName = process.env.APP_NAME?.trim() // guard:allow-env-credential — deploy-level app configuration selects the scoped encryption key.\n .toUpperCase()\n .replace(/[^A-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n return appName\n ? process.env[`${appName}_SECRETS_ENCRYPTION_KEY`] // guard:allow-env-credential — deploy-level app encryption material, never a user credential.\n : undefined;\n}\n\n/**\n * Preserve the generic/app-local key precedence. Generic encrypted values are\n * not a cross-app boundary, and changing their preferred key would strand\n * existing OAuth tokens and credentials.\n */\nfunction genericEncryptionKeyMaterial(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return (\n process.env.SECRETS_ENCRYPTION_KEY ||\n process.env.BETTER_AUTH_SECRET ||\n getWorkspaceA2ADerivedSecret(\"secrets-encryption\")\n );\n}\n\nfunction workspaceSharedEncryptionKeyMaterial(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env.WORKSPACE_SECRETS_ENCRYPTION_KEY?.trim() || undefined;\n}\n\nfunction previousWorkspaceSharedEncryptionKeyMaterial(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return (\n process.env.WORKSPACE_SECRETS_ENCRYPTION_KEY_PREVIOUS?.trim() || undefined\n );\n}\n\n/**\n * Vault sharing follows configured A2A trust even on independently deployed\n * sibling apps that are not launched by the workspace wrapper. The wrapper's\n * `AGENT_NATIVE_WORKSPACE` flag remains required for auth/OAuth-derived\n * secrets, but it must not be a hidden prerequisite for decrypting vault rows\n * when every app already has the same explicit `A2A_SECRET`.\n */\nfunction a2aSharedEncryptionKeyMaterial(): string | undefined {\n const workspaceDerived = getWorkspaceA2ADerivedSecret(\"secrets-encryption\");\n if (workspaceDerived) return workspaceDerived;\n if (typeof process === \"undefined\") return undefined;\n const rootSecret = process.env.A2A_SECRET?.trim();\n return rootSecret\n ? deriveServerSecret(rootSecret, \"secrets-encryption\")\n : undefined;\n}\n\n/**\n * Stable materials that may be used for workspace-shared vault rows, ordered\n * from current preference to legacy compatibility fallbacks.\n *\n * `BETTER_AUTH_SECRET` deliberately comes after the workspace and A2A-derived\n * materials: sibling apps normally have different auth secrets but share\n * workspace trust.\n */\nfunction sharedEncryptionKeyMaterials(): string[] {\n if (typeof process === \"undefined\") return [];\n const candidates = [\n workspaceSharedEncryptionKeyMaterial(),\n process.env.SECRETS_ENCRYPTION_KEY,\n a2aSharedEncryptionKeyMaterial(),\n previousWorkspaceSharedEncryptionKeyMaterial(),\n process.env.BETTER_AUTH_SECRET,\n appScopedEncryptionKey(),\n ].filter((value): value is string => Boolean(value));\n return [...new Set(candidates)];\n}\n\nfunction preferredSharedEncryptionKeyMaterial(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return (\n workspaceSharedEncryptionKeyMaterial() ||\n process.env.SECRETS_ENCRYPTION_KEY ||\n a2aSharedEncryptionKeyMaterial() ||\n process.env.BETTER_AUTH_SECRET ||\n appScopedEncryptionKey()\n );\n}\n\nfunction hashSecretEncryptionKey(material: string): Buffer {\n const { createHash } = requireNodeCrypto();\n return createHash(\"sha256\").update(material).digest();\n}\n\nfunction deriveSecretEncryptionKey(\n explicit: string | undefined,\n errorMessage: string,\n warningMessage: string,\n): Buffer {\n if (!explicit) {\n if (processNodeEnv() === \"production\") {\n throw new Error(errorMessage);\n }\n if (!_warnedFallback) {\n _warnedFallback = true;\n // eslint-disable-next-line no-console\n console.warn(warningMessage);\n }\n }\n\n const material = explicit || `agent-native-secrets:${processCwd()}`;\n return hashSecretEncryptionKey(material);\n}\n\n/**\n * Derive the key used by generic encrypted values such as credentials and\n * OAuth tokens. App-specific key material is allowed for these app-local\n * values.\n */\nexport function getSecretEncryptionKey(): Buffer {\n const appName =\n typeof process === \"undefined\"\n ? undefined\n : process.env.APP_NAME?.trim() // guard:allow-env-credential — deploy-level app configuration selects the scoped encryption key.\n .toUpperCase()\n .replace(/[^A-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n return deriveSecretEncryptionKey(\n appScopedEncryptionKey() || genericEncryptionKeyMaterial(),\n \"[agent-native/secrets] Refusing to start in production without an encryption key. \" +\n `Set ${appName ? `${appName}_SECRETS_ENCRYPTION_KEY, ` : \"\"}SECRETS_ENCRYPTION_KEY, or BETTER_AUTH_SECRET in the deploy environment. ` +\n \"The previous CWD-derived fallback was effectively static (e.g. `/var/task` on Lambda), \" +\n \"which means anyone with read access to the DB could decrypt every secret.\",\n \"[agent-native/secrets] SECRETS_ENCRYPTION_KEY not set — using a machine-local fallback. \" +\n \"Set an app-scoped *_SECRETS_ENCRYPTION_KEY, SECRETS_ENCRYPTION_KEY, or BETTER_AUTH_SECRET for production. \" +\n \"Production deploys without one of these env vars now hard-fail.\",\n );\n}\n\n/**\n * Derive the preferred workspace-shared key used by `app_secrets` rows.\n * Unlike generic column-level encryption, workspace vault data must decrypt\n * in sibling apps. An explicit `WORKSPACE_SECRETS_ENCRYPTION_KEY` wins without\n * changing the key for app-local OAuth and credential ciphertext. The legacy\n * shared `SECRETS_ENCRYPTION_KEY` remains supported; hosted workspaces\n * otherwise derive material from their shared `A2A_SECRET` before considering\n * app-local `BETTER_AUTH_SECRET` or app-scoped key fallbacks. Reads try every\n * configured legacy/previous candidate and report when the ciphertext should\n * be refreshed under the preferred key.\n */\nexport function getSharedSecretEncryptionKey(): Buffer {\n return deriveSecretEncryptionKey(\n preferredSharedEncryptionKeyMaterial(),\n \"[agent-native/secrets] Refusing to start in production without encryption key material for workspace secrets. \" +\n \"Set WORKSPACE_SECRETS_ENCRYPTION_KEY (preferred), SECRETS_ENCRYPTION_KEY, ensure a hosted workspace has A2A_SECRET, \" +\n \"or set BETTER_AUTH_SECRET / an app-scoped \" +\n \"*_SECRETS_ENCRYPTION_KEY compatibility fallback in the deploy environment.\",\n \"[agent-native/secrets] Workspace encryption key not set — using app-scoped or machine-local fallback for workspace secrets. \" +\n \"Set WORKSPACE_SECRETS_ENCRYPTION_KEY or rely on A2A_SECRET-derived material on hosted workspace deploys so sibling apps share vault rows.\",\n );\n}\n\n/** Whether this deployment has stable workspace-shared key material. */\nexport function hasSharedSecretEncryptionKeyMaterial(): boolean {\n if (typeof process === \"undefined\") return false;\n return Boolean(\n workspaceSharedEncryptionKeyMaterial() ||\n process.env.SECRETS_ENCRYPTION_KEY ||\n a2aSharedEncryptionKeyMaterial() ||\n process.env.BETTER_AUTH_SECRET,\n );\n}\n\nfunction encryptWithKey(plaintext: string, key: Buffer): string {\n const { createCipheriv, randomBytes } = requireNodeCrypto();\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const ct = Buffer.concat([cipher.update(plaintext, \"utf8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n return `v1:${iv.toString(\"hex\")}:${ct.toString(\"hex\")}:${tag.toString(\"hex\")}`;\n}\n\nfunction decryptWithKey(encrypted: string, key: Buffer): string {\n const { createDecipheriv } = requireNodeCrypto();\n if (!encrypted.startsWith(\"v1:\")) {\n throw new Error(\"Unrecognised secret encoding\");\n }\n const [, ivHex, ctHex, tagHex] = encrypted.split(\":\");\n if (!ivHex || !ctHex || !tagHex) {\n throw new Error(\"Corrupt secret payload\");\n }\n const decipher = createDecipheriv(\n \"aes-256-gcm\",\n key,\n Buffer.from(ivHex, \"hex\"),\n );\n decipher.setAuthTag(Buffer.from(tagHex, \"hex\"));\n const pt = Buffer.concat([\n decipher.update(Buffer.from(ctHex, \"hex\")),\n decipher.final(),\n ]);\n return pt.toString(\"utf8\");\n}\n\n/** Encrypt a plain-text value with the generic app-local key. */\nexport function encryptSecretValue(plaintext: string): string {\n return encryptWithKey(plaintext, getSecretEncryptionKey());\n}\n\n/** Decrypt a value produced by `encryptSecretValue`. Throws on tampering. */\nexport function decryptSecretValue(encrypted: string): string {\n return decryptWithKey(encrypted, getSecretEncryptionKey());\n}\n\n/** Encrypt a workspace-shared `app_secrets` value. */\nexport function encryptSharedSecretValue(plaintext: string): string {\n return encryptWithKey(plaintext, getSharedSecretEncryptionKey());\n}\n\n/** Decrypt a workspace-shared `app_secrets` value. */\nexport function decryptSharedSecretValue(encrypted: string): string {\n return decryptSharedSecretValueDetailed(encrypted).value;\n}\n\nexport interface DecryptedSharedSecretValue {\n value: string;\n /**\n * True when a legacy app-local candidate decrypted the value. Callers that\n * own the row should opportunistically re-encrypt it with the preferred\n * workspace key.\n */\n needsReencrypt: boolean;\n}\n\n/**\n * Decrypt workspace ciphertext with the preferred key first, then configured\n * legacy candidates. The result never exposes which secret material matched.\n */\nexport function decryptSharedSecretValueDetailed(\n encrypted: string,\n): DecryptedSharedSecretValue {\n const preferredKey = getSharedSecretEncryptionKey();\n const candidateKeys = [preferredKey];\n for (const material of sharedEncryptionKeyMaterials()) {\n const candidate = hashSecretEncryptionKey(material);\n if (!candidateKeys.some((existing) => existing.equals(candidate))) {\n candidateKeys.push(candidate);\n }\n }\n\n let lastError: unknown;\n for (const candidate of candidateKeys) {\n try {\n return {\n value: decryptWithKey(encrypted, candidate),\n needsReencrypt: !candidate.equals(preferredKey),\n };\n } catch (error) {\n lastError = error;\n }\n }\n throw lastError instanceof Error\n ? lastError\n : new Error(\"Unable to decrypt workspace secret\");\n}\n\n/**\n * Strict check for a value produced by `encryptSecretValue`: `v1:` followed by\n * three hex segments. Intentionally strict so a legacy plaintext credential\n * that merely happens to start with `v1:` is treated as plaintext (and read via\n * the legacy fallback) rather than mis-decrypted.\n */\nconst ENCRYPTED_VALUE_RE = /^v1:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$/;\n\nexport function isEncryptedSecretValue(value: unknown): value is string {\n return typeof value === \"string\" && ENCRYPTED_VALUE_RE.test(value);\n}\n"]}
@@ -2,10 +2,12 @@
2
2
  * Storage layer for the framework secrets registry.
3
3
  *
4
4
  * Values are encrypted at rest with AES-256-GCM. The workspace-shared
5
- * encryption key is derived from `SECRETS_ENCRYPTION_KEY` (preferred) or the
6
- * workspace-wide `A2A_SECRET`. `BETTER_AUTH_SECRET` and app-scoped keys remain
7
- * read fallbacks for rows written before sibling apps converged on the shared
8
- * key. Successful fallback reads race-safely refresh the shared ciphertext.
5
+ * encryption key prefers `WORKSPACE_SECRETS_ENCRYPTION_KEY`, then the legacy
6
+ * combined `SECRETS_ENCRYPTION_KEY`, then the workspace-wide `A2A_SECRET`.
7
+ * A configured previous workspace key, `BETTER_AUTH_SECRET`, and app-scoped
8
+ * keys remain read fallbacks for rows written before sibling apps converged on
9
+ * the shared key. Successful fallback reads race-safely refresh the shared
10
+ * ciphertext.
9
11
  *
10
12
  * Secret values are NEVER logged and NEVER returned from any route handler.
11
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/secrets/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAaH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA+FjD;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3C;AAMD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAqF3E;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAmID;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA8BlC;AAED,wEAAwE;AACxE,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAoCzC;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,SAAS,GACb,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAItD;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAsC5B;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,EAAE,CAAC,CAuCvB;AAeD,wBAAsB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAStE"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/secrets/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA+FjD;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3C;AAMD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAqF3E;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAmID;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA8BlC;AAED,wEAAwE;AACxE,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAoCzC;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,SAAS,GACb,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAItD;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAsC5B;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,EAAE,CAAC,CAuCvB;AAeD,wBAAsB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAStE"}
@@ -2,10 +2,12 @@
2
2
  * Storage layer for the framework secrets registry.
3
3
  *
4
4
  * Values are encrypted at rest with AES-256-GCM. The workspace-shared
5
- * encryption key is derived from `SECRETS_ENCRYPTION_KEY` (preferred) or the
6
- * workspace-wide `A2A_SECRET`. `BETTER_AUTH_SECRET` and app-scoped keys remain
7
- * read fallbacks for rows written before sibling apps converged on the shared
8
- * key. Successful fallback reads race-safely refresh the shared ciphertext.
5
+ * encryption key prefers `WORKSPACE_SECRETS_ENCRYPTION_KEY`, then the legacy
6
+ * combined `SECRETS_ENCRYPTION_KEY`, then the workspace-wide `A2A_SECRET`.
7
+ * A configured previous workspace key, `BETTER_AUTH_SECRET`, and app-scoped
8
+ * keys remain read fallbacks for rows written before sibling apps converged on
9
+ * the shared key. Successful fallback reads race-safely refresh the shared
10
+ * ciphertext.
9
11
  *
10
12
  * Secret values are NEVER logged and NEVER returned from any route handler.
11
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/secrets/storage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Storage layer for the framework secrets registry.\n *\n * Values are encrypted at rest with AES-256-GCM. The workspace-shared\n * encryption key is derived from `SECRETS_ENCRYPTION_KEY` (preferred) or the\n * workspace-wide `A2A_SECRET`. `BETTER_AUTH_SECRET` and app-scoped keys remain\n * read fallbacks for rows written before sibling apps converged on the shared\n * key. Successful fallback reads race-safely refresh the shared ciphertext.\n *\n * Secret values are NEVER logged and NEVER returned from any route handler.\n */\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { getDbExec, isPostgres } from \"../db/client.js\";\nimport { ensureColumnExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport {\n encryptSecretValue as encryptLegacyValue,\n encryptSharedSecretValue as encryptValue,\n decryptSharedSecretValueDetailed as decryptValue,\n decryptSecretValue as decryptLegacyValue,\n hasSharedSecretEncryptionKeyMaterial,\n} from \"./crypto.js\";\nimport type { SecretScope } from \"./register.js\";\nimport { APP_SECRETS_CREATE_SQL } from \"./schema.js\";\n\n// ---------------------------------------------------------------------------\n// Table bootstrap\n// ---------------------------------------------------------------------------\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n // Postgres version of the CREATE TABLE — the generic `INTEGER` maps to\n // BIGINT on Postgres, which we need for millisecond timestamps.\n const createSql = isPostgres()\n ? APP_SECRETS_CREATE_SQL.replace(/\\bINTEGER\\b/g, \"BIGINT\")\n : APP_SECRETS_CREATE_SQL;\n\n if (isPostgres()) {\n // Hot path: in production the table and both additive columns are\n // virtually always already present. Issuing `CREATE`/`ALTER` would\n // still take an ACCESS EXCLUSIVE lock — which, in a fresh background\n // worker process behind a concurrent connection on the shared Neon DB,\n // can block ~indefinitely. `ensureTableExists` / `ensureColumnExists`\n // check `information_schema` first (a plain read, no lock) and run DDL\n // ONLY for what is actually missing, wrapping any DDL that must run in a\n // transaction-scoped `lock_timeout` so a contended lock fails fast. They\n // also re-probe after a swallowed lock-timeout and THROW if the schema\n // is still missing, so a timed-out DDL never poisons this init memo.\n await ensureTableExists(\"app_secrets\", createSql);\n await ensureColumnExists(\n \"app_secrets\",\n \"description\",\n `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS description TEXT`,\n );\n await ensureColumnExists(\n \"app_secrets\",\n \"url_allowlist\",\n `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS url_allowlist TEXT`,\n );\n await ensureColumnExists(\n \"app_secrets\",\n \"shared_encrypted_value\",\n `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS shared_encrypted_value TEXT`,\n );\n return;\n }\n\n // SQLite (local dev): no ACCESS EXCLUSIVE lock problem, keep the original\n // create-then-additive-alter behaviour. SQLite has no\n // `ADD COLUMN IF NOT EXISTS`, so the ALTERs stay wrapped in try/catch.\n await client.execute(createSql);\n\n // Additive migration: description column (for ad-hoc keys)\n try {\n await client.execute(\n `ALTER TABLE app_secrets ADD COLUMN description TEXT`,\n );\n } catch {\n // Column already exists — expected\n }\n\n // Additive migration: url_allowlist column\n try {\n await client.execute(\n `ALTER TABLE app_secrets ADD COLUMN url_allowlist TEXT`,\n );\n } catch {\n // Column already exists — expected\n }\n\n // Additive migration: workspace-shared ciphertext. Keep the legacy\n // encrypted_value column so older app versions remain readable.\n try {\n await client.execute(\n `ALTER TABLE app_secrets ADD COLUMN shared_encrypted_value TEXT`,\n );\n } catch {\n // Column already exists — expected\n }\n })().catch((err) => {\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\n// ---------------------------------------------------------------------------\n// Encryption — see ./crypto.ts. Keep encrypted_value on the legacy app-key\n// format for mixed-version deployments, and add shared_encrypted_value when a\n// stable workspace key is configured so sibling apps can read the same row.\n// ---------------------------------------------------------------------------\n\n/**\n * Return the last 4 characters of a secret, with any leading characters\n * masked. Used to show a preview without leaking the value.\n */\nexport function last4(value: string): string {\n if (!value) return \"\";\n if (value.length <= 4) return \"••••\";\n return \"••••\" + value.slice(-4);\n}\n\n// ---------------------------------------------------------------------------\n// CRUD\n// ---------------------------------------------------------------------------\n\nexport interface SecretRef {\n key: string;\n scope: SecretScope;\n scopeId: string;\n}\n\nexport interface WriteSecretArgs extends SecretRef {\n value: string;\n /** Optional human-readable description (used for ad-hoc keys). */\n description?: string;\n /** Optional JSON-stringified array of allowed URL origins. */\n urlAllowlist?: string;\n}\n\n/**\n * Write (insert or update) a secret. The value is encrypted before being\n * stored — the caller's plaintext is never persisted. Returns the new\n * record's id.\n */\nexport async function writeAppSecret(args: WriteSecretArgs): Promise<string> {\n await ensureTable();\n const { key, value, scope, scopeId, description, urlAllowlist } = args;\n if (!key || !value || !scope || !scopeId) {\n throw new Error(\n \"writeAppSecret: key, value, scope, and scopeId are all required\",\n );\n }\n const client = getDbExec();\n const now = Date.now();\n // Dual-write during rollout: old readers continue using encrypted_value,\n // while new readers prefer the nullable shared ciphertext. An app-only\n // deployment leaves the shared column null; on an update, a writer without\n // shared key material clears any existing shared ciphertext rather than\n // preserving it (see the upsert SQL below for why).\n const encrypted = encryptLegacyValue(value);\n const sharedEncrypted = hasSharedSecretEncryptionKeyMaterial()\n ? encryptValue(value)\n : null;\n const id = randomUUID();\n\n // Atomic upsert by (scope, scope_id, key). Previously this was a\n // SELECT-then-branch (UPDATE if found, else INSERT): under concurrent\n // writers for the same key both could see \"no row\" and both attempt\n // INSERT, and the loser threw a raw UNIQUE(scope, scope_id, key)\n // constraint violation (a user-facing 500) instead of updating. A single\n // `INSERT ... ON CONFLICT DO UPDATE` closes that window — it's one\n // statement, so there's no gap between \"check\" and \"act\". `id` is\n // deliberately left out of the `DO UPDATE SET` list so an existing row\n // keeps its original id (any stored references stay stable); only a\n // genuinely new row gets the freshly generated `id`. This syntax is\n // portable across SQLite (UPSERT since 3.24) and Postgres.\n //\n // shared_encrypted_value is overwritten with `excluded.shared_encrypted_value`\n // (NULL when this writer lacks shared key material) rather than preserved\n // via COALESCE. Preserving an existing shared ciphertext across a value\n // update would let a sibling app silently decrypt a STALE value after the\n // owner rotates it — a material-less writer has no way to produce the new\n // shared ciphertext, so it must clear the old one instead of leaving it\n // pointing at data that's no longer current. Siblings then get an honest\n // cache miss (falling back to the legacy column or reporting missing) until\n // the owning app's next read repopulates shared_encrypted_value via\n // `populateSharedAppSecret`, which fills a NULL column or compare-and-swap\n // replaces the exact legacy ciphertext it just decrypted. A temporary miss\n // is safer than serving rotated-away plaintext.\n const upsertSql = `INSERT INTO app_secrets (id, scope, scope_id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (scope, scope_id, key) DO UPDATE SET\n encrypted_value = excluded.encrypted_value,\n shared_encrypted_value = excluded.shared_encrypted_value,\n description = excluded.description,\n url_allowlist = excluded.url_allowlist,\n updated_at = excluded.updated_at`;\n const upsertArgs = [\n id,\n scope,\n scopeId,\n key,\n encrypted,\n sharedEncrypted,\n description ?? null,\n urlAllowlist ?? null,\n now,\n now,\n ];\n\n if (isPostgres()) {\n const { rows } = await client.execute({\n sql: `${upsertSql} RETURNING id`,\n args: upsertArgs,\n });\n return String(rows[0]?.id ?? id);\n }\n\n // SQLite: RETURNING support varies across better-sqlite3/libsql builds, so\n // (matching the convention elsewhere in this codebase, e.g.\n // integrations/pending-tasks-store.ts) re-read the id afterward instead of\n // relying on it. The row is guaranteed to exist at this point, so this is\n // a plain lookup rather than a TOCTOU-prone gate on the write itself.\n await client.execute({ sql: upsertSql, args: upsertArgs });\n const { rows } = await client.execute({\n sql: `SELECT id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,\n args: [scope, scopeId, key],\n });\n return String(rows[0]?.id ?? id);\n}\n\nexport interface ReadSecretResult {\n value: string;\n last4: string;\n updatedAt: number;\n}\n\n/**\n * Read the shared-key format and retain compatibility with rows written before\n * app_secrets moved to its workspace-shared encryption boundary. The legacy\n * fallback is only useful when the current app owns the old row; sibling apps\n * will receive shared-key ciphertext after the next vault sync or update.\n */\ninterface DecryptedAppSecretValue {\n value: string;\n /** True when the app-scoped fallback decrypted encrypted_value. */\n usedLegacyKey: boolean;\n /** True when shared_encrypted_value needs to be created or refreshed. */\n needsSharedCiphertext: boolean;\n /**\n * Existing ciphertext that must still match before a refresh. Null means the\n * migration may only fill an empty shared column.\n */\n sharedCiphertextToReplace?: string | null;\n}\n\nfunction decryptAppSecretValue(\n encrypted: string,\n sharedEncrypted?: string | null,\n): DecryptedAppSecretValue {\n if (sharedEncrypted) {\n try {\n const decrypted = decryptValue(sharedEncrypted);\n return {\n value: decrypted.value,\n usedLegacyKey: false,\n needsSharedCiphertext: decrypted.needsReencrypt,\n sharedCiphertextToReplace: decrypted.needsReencrypt\n ? sharedEncrypted\n : undefined,\n };\n } catch {\n // Fall through to the legacy column. A partially migrated row may have\n // a stale shared ciphertext while the old app-key value is valid.\n }\n }\n try {\n const decrypted = decryptValue(encrypted);\n return {\n value: decrypted.value,\n usedLegacyKey: false,\n needsSharedCiphertext: true,\n sharedCiphertextToReplace: sharedEncrypted ?? null,\n };\n } catch {\n return {\n value: decryptLegacyValue(encrypted),\n usedLegacyKey: true,\n needsSharedCiphertext: true,\n sharedCiphertextToReplace: sharedEncrypted ?? null,\n };\n }\n}\n\n/**\n * Create or refresh the shared column without touching encrypted_value. This\n * is intentionally best-effort: a read must still succeed if a deployment's\n * DB role cannot update the row. The compare-and-swap predicate prevents a\n * concurrent writer from being overwritten, and leaving updated_at untouched\n * preserves the row's user-visible ordering/metadata.\n */\nasync function populateSharedAppSecret(\n id: unknown,\n value: string,\n sharedCiphertextToReplace: string | null,\n): Promise<void> {\n if (\n id === undefined ||\n id === null ||\n !hasSharedSecretEncryptionKeyMaterial()\n ) {\n return;\n }\n try {\n const encrypted = encryptValue(value);\n if (sharedCiphertextToReplace === null) {\n await getDbExec().execute({\n sql: `UPDATE app_secrets SET shared_encrypted_value = ? WHERE id = ? AND shared_encrypted_value IS NULL`,\n args: [encrypted, id],\n });\n } else {\n await getDbExec().execute({\n sql: `UPDATE app_secrets SET shared_encrypted_value = ? WHERE id = ? AND shared_encrypted_value = ?`,\n args: [encrypted, id, sharedCiphertextToReplace],\n });\n }\n } catch {\n // Migration is opportunistic. Preserve the successful read if the update\n // is unavailable due to a read-only role, transient DB failure, or race.\n }\n}\n\ntype AppSecretsReadQuery = { sql: string; args: unknown[] };\n\n/**\n * True only when the database says the app_secrets table itself is missing.\n * Other query failures must propagate unchanged: attempting schema bootstrap\n * for connectivity, permission, or syntax errors both hides the real failure\n * and can introduce DDL onto a latency-sensitive read path.\n */\nfunction isMissingAppSecretsTableError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n const code = String((error as Error & { code?: unknown }).code ?? \"\");\n const message = error.message.toLowerCase();\n const namesAppSecrets = /(?:app_secrets|\"app_secrets\")/.test(message);\n\n if (code === \"42P01\") return namesAppSecrets;\n return (\n namesAppSecrets &&\n (message.includes(\"no such table\") ||\n (message.includes(\"relation\") && message.includes(\"does not exist\")))\n );\n}\n\n/** Execute a read without schema probes on the normal path. */\nasync function executeAppSecretsRead(query: AppSecretsReadQuery) {\n const client = getDbExec();\n try {\n return await client.execute(query);\n } catch (error) {\n if (!isMissingAppSecretsTableError(error)) throw error;\n await ensureTable();\n return client.execute(query);\n }\n}\n\n/**\n * Read a secret's plaintext value. Returns null when not found. The caller\n * is responsible for never logging the returned value.\n */\nexport async function readAppSecret(\n ref: SecretRef,\n): Promise<ReadSecretResult | null> {\n const { key, scope, scopeId } = ref;\n const { rows } = await executeAppSecretsRead({\n sql: `SELECT encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,\n args: [scope, scopeId, key],\n });\n if (rows.length === 0) return null;\n try {\n const encrypted = rows[0].encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n rows[0].shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n rows[0].id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n return {\n value: decrypted.value,\n last4: last4(decrypted.value),\n updatedAt: Number(rows[0].updated_at ?? 0),\n };\n } catch {\n // Decryption failure — key rotated, tampered row, etc. Don't throw up the\n // stack in a way that could leak the ciphertext; just report missing.\n return null;\n }\n}\n\n/** Read several keys from one scope in a single database round trip. */\nexport async function readAppSecrets(args: {\n keys: readonly string[];\n scope: SecretScope;\n scopeId: string;\n}): Promise<Map<string, ReadSecretResult>> {\n const keys = [...new Set(args.keys.filter(Boolean))];\n if (keys.length === 0) return new Map();\n\n const placeholders = keys.map(() => \"?\").join(\", \");\n const { rows } = await executeAppSecretsRead({\n sql: `SELECT key, encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key IN (${placeholders})`,\n args: [args.scope, args.scopeId, ...keys],\n });\n const results = new Map<string, ReadSecretResult>();\n for (const row of rows) {\n const key = String(row.key ?? \"\");\n if (!key) continue;\n try {\n const encrypted = row.encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n row.shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n row.id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n results.set(key, {\n value: decrypted.value,\n last4: last4(decrypted.value),\n updatedAt: Number(row.updated_at ?? 0),\n });\n } catch {\n // Match readAppSecret: corrupted or stale ciphertext behaves as missing.\n }\n }\n return results;\n}\n\n/**\n * Return just the metadata for a secret (no value). Used by the list route so\n * the UI can show the \"Set\" pill and last-4 without the decrypted value going\n * over the wire.\n */\nexport async function getAppSecretMeta(\n ref: SecretRef,\n): Promise<{ last4: string; updatedAt: number } | null> {\n const result = await readAppSecret(ref);\n if (!result) return null;\n return { last4: result.last4, updatedAt: result.updatedAt };\n}\n\nexport interface SecretMeta {\n key: string;\n scope: SecretScope;\n scopeId: string;\n last4: string;\n description: string | null;\n urlAllowlist: string[] | null;\n createdAt: number;\n updatedAt: number;\n}\n\n/**\n * Read a secret's metadata, including ad-hoc fields (description, allowlist),\n * without ever decrypting or returning the plaintext value. Used by the\n * ad-hoc list route and any UI that wants to render a key tile.\n */\nexport async function readAppSecretMeta(\n ref: SecretRef,\n): Promise<SecretMeta | null> {\n await ensureTable();\n const { key, scope, scopeId } = ref;\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,\n args: [scope, scopeId, key],\n });\n if (rows.length === 0) return null;\n const row = rows[0];\n let last4Value = \"\";\n try {\n const encrypted = row.encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n row.shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n row.id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n last4Value = last4(decrypted.value);\n } catch {\n last4Value = \"\";\n }\n return {\n key,\n scope,\n scopeId,\n last4: last4Value,\n description: (row.description as string | null) ?? null,\n urlAllowlist: parseAllowlist(row.url_allowlist as string | null),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\n/**\n * List all secrets for a given scope. Returns metadata only — values are\n * never decrypted or returned. Used by the ad-hoc list route to surface\n * user-created keys.\n */\nexport async function listAppSecretsForScope(\n scope: SecretScope,\n scopeId: string,\n): Promise<SecretMeta[]> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? ORDER BY updated_at DESC`,\n args: [scope, scopeId],\n });\n const results: SecretMeta[] = [];\n for (const row of rows) {\n let last4Value = \"\";\n try {\n const encrypted = row.encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n row.shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n row.id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n last4Value = last4(decrypted.value);\n } catch {\n last4Value = \"\";\n }\n results.push({\n key: row.key as string,\n scope,\n scopeId,\n last4: last4Value,\n description: (row.description as string | null) ?? null,\n urlAllowlist: parseAllowlist(row.url_allowlist as string | null),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n });\n }\n return results;\n}\n\nfunction parseAllowlist(raw: string | null): string[] | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((v) => typeof v === \"string\")) {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport async function deleteAppSecret(ref: SecretRef): Promise<boolean> {\n await ensureTable();\n const { key, scope, scopeId } = ref;\n const client = getDbExec();\n const { rowsAffected } = await client.execute({\n sql: `DELETE FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ?`,\n args: [scope, scopeId, key],\n });\n return rowsAffected > 0;\n}\n"]}
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/secrets/storage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Storage layer for the framework secrets registry.\n *\n * Values are encrypted at rest with AES-256-GCM. The workspace-shared\n * encryption key prefers `WORKSPACE_SECRETS_ENCRYPTION_KEY`, then the legacy\n * combined `SECRETS_ENCRYPTION_KEY`, then the workspace-wide `A2A_SECRET`.\n * A configured previous workspace key, `BETTER_AUTH_SECRET`, and app-scoped\n * keys remain read fallbacks for rows written before sibling apps converged on\n * the shared key. Successful fallback reads race-safely refresh the shared\n * ciphertext.\n *\n * Secret values are NEVER logged and NEVER returned from any route handler.\n */\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { getDbExec, isPostgres } from \"../db/client.js\";\nimport { ensureColumnExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport {\n encryptSecretValue as encryptLegacyValue,\n encryptSharedSecretValue as encryptValue,\n decryptSharedSecretValueDetailed as decryptValue,\n decryptSecretValue as decryptLegacyValue,\n hasSharedSecretEncryptionKeyMaterial,\n} from \"./crypto.js\";\nimport type { SecretScope } from \"./register.js\";\nimport { APP_SECRETS_CREATE_SQL } from \"./schema.js\";\n\n// ---------------------------------------------------------------------------\n// Table bootstrap\n// ---------------------------------------------------------------------------\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n // Postgres version of the CREATE TABLE — the generic `INTEGER` maps to\n // BIGINT on Postgres, which we need for millisecond timestamps.\n const createSql = isPostgres()\n ? APP_SECRETS_CREATE_SQL.replace(/\\bINTEGER\\b/g, \"BIGINT\")\n : APP_SECRETS_CREATE_SQL;\n\n if (isPostgres()) {\n // Hot path: in production the table and both additive columns are\n // virtually always already present. Issuing `CREATE`/`ALTER` would\n // still take an ACCESS EXCLUSIVE lock — which, in a fresh background\n // worker process behind a concurrent connection on the shared Neon DB,\n // can block ~indefinitely. `ensureTableExists` / `ensureColumnExists`\n // check `information_schema` first (a plain read, no lock) and run DDL\n // ONLY for what is actually missing, wrapping any DDL that must run in a\n // transaction-scoped `lock_timeout` so a contended lock fails fast. They\n // also re-probe after a swallowed lock-timeout and THROW if the schema\n // is still missing, so a timed-out DDL never poisons this init memo.\n await ensureTableExists(\"app_secrets\", createSql);\n await ensureColumnExists(\n \"app_secrets\",\n \"description\",\n `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS description TEXT`,\n );\n await ensureColumnExists(\n \"app_secrets\",\n \"url_allowlist\",\n `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS url_allowlist TEXT`,\n );\n await ensureColumnExists(\n \"app_secrets\",\n \"shared_encrypted_value\",\n `ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS shared_encrypted_value TEXT`,\n );\n return;\n }\n\n // SQLite (local dev): no ACCESS EXCLUSIVE lock problem, keep the original\n // create-then-additive-alter behaviour. SQLite has no\n // `ADD COLUMN IF NOT EXISTS`, so the ALTERs stay wrapped in try/catch.\n await client.execute(createSql);\n\n // Additive migration: description column (for ad-hoc keys)\n try {\n await client.execute(\n `ALTER TABLE app_secrets ADD COLUMN description TEXT`,\n );\n } catch {\n // Column already exists — expected\n }\n\n // Additive migration: url_allowlist column\n try {\n await client.execute(\n `ALTER TABLE app_secrets ADD COLUMN url_allowlist TEXT`,\n );\n } catch {\n // Column already exists — expected\n }\n\n // Additive migration: workspace-shared ciphertext. Keep the legacy\n // encrypted_value column so older app versions remain readable.\n try {\n await client.execute(\n `ALTER TABLE app_secrets ADD COLUMN shared_encrypted_value TEXT`,\n );\n } catch {\n // Column already exists — expected\n }\n })().catch((err) => {\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\n// ---------------------------------------------------------------------------\n// Encryption — see ./crypto.ts. Keep encrypted_value on the legacy app-key\n// format for mixed-version deployments, and add shared_encrypted_value when a\n// stable workspace key is configured so sibling apps can read the same row.\n// ---------------------------------------------------------------------------\n\n/**\n * Return the last 4 characters of a secret, with any leading characters\n * masked. Used to show a preview without leaking the value.\n */\nexport function last4(value: string): string {\n if (!value) return \"\";\n if (value.length <= 4) return \"••••\";\n return \"••••\" + value.slice(-4);\n}\n\n// ---------------------------------------------------------------------------\n// CRUD\n// ---------------------------------------------------------------------------\n\nexport interface SecretRef {\n key: string;\n scope: SecretScope;\n scopeId: string;\n}\n\nexport interface WriteSecretArgs extends SecretRef {\n value: string;\n /** Optional human-readable description (used for ad-hoc keys). */\n description?: string;\n /** Optional JSON-stringified array of allowed URL origins. */\n urlAllowlist?: string;\n}\n\n/**\n * Write (insert or update) a secret. The value is encrypted before being\n * stored — the caller's plaintext is never persisted. Returns the new\n * record's id.\n */\nexport async function writeAppSecret(args: WriteSecretArgs): Promise<string> {\n await ensureTable();\n const { key, value, scope, scopeId, description, urlAllowlist } = args;\n if (!key || !value || !scope || !scopeId) {\n throw new Error(\n \"writeAppSecret: key, value, scope, and scopeId are all required\",\n );\n }\n const client = getDbExec();\n const now = Date.now();\n // Dual-write during rollout: old readers continue using encrypted_value,\n // while new readers prefer the nullable shared ciphertext. An app-only\n // deployment leaves the shared column null; on an update, a writer without\n // shared key material clears any existing shared ciphertext rather than\n // preserving it (see the upsert SQL below for why).\n const encrypted = encryptLegacyValue(value);\n const sharedEncrypted = hasSharedSecretEncryptionKeyMaterial()\n ? encryptValue(value)\n : null;\n const id = randomUUID();\n\n // Atomic upsert by (scope, scope_id, key). Previously this was a\n // SELECT-then-branch (UPDATE if found, else INSERT): under concurrent\n // writers for the same key both could see \"no row\" and both attempt\n // INSERT, and the loser threw a raw UNIQUE(scope, scope_id, key)\n // constraint violation (a user-facing 500) instead of updating. A single\n // `INSERT ... ON CONFLICT DO UPDATE` closes that window — it's one\n // statement, so there's no gap between \"check\" and \"act\". `id` is\n // deliberately left out of the `DO UPDATE SET` list so an existing row\n // keeps its original id (any stored references stay stable); only a\n // genuinely new row gets the freshly generated `id`. This syntax is\n // portable across SQLite (UPSERT since 3.24) and Postgres.\n //\n // shared_encrypted_value is overwritten with `excluded.shared_encrypted_value`\n // (NULL when this writer lacks shared key material) rather than preserved\n // via COALESCE. Preserving an existing shared ciphertext across a value\n // update would let a sibling app silently decrypt a STALE value after the\n // owner rotates it — a material-less writer has no way to produce the new\n // shared ciphertext, so it must clear the old one instead of leaving it\n // pointing at data that's no longer current. Siblings then get an honest\n // cache miss (falling back to the legacy column or reporting missing) until\n // the owning app's next read repopulates shared_encrypted_value via\n // `populateSharedAppSecret`, which fills a NULL column or compare-and-swap\n // replaces the exact legacy ciphertext it just decrypted. A temporary miss\n // is safer than serving rotated-away plaintext.\n const upsertSql = `INSERT INTO app_secrets (id, scope, scope_id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (scope, scope_id, key) DO UPDATE SET\n encrypted_value = excluded.encrypted_value,\n shared_encrypted_value = excluded.shared_encrypted_value,\n description = excluded.description,\n url_allowlist = excluded.url_allowlist,\n updated_at = excluded.updated_at`;\n const upsertArgs = [\n id,\n scope,\n scopeId,\n key,\n encrypted,\n sharedEncrypted,\n description ?? null,\n urlAllowlist ?? null,\n now,\n now,\n ];\n\n if (isPostgres()) {\n const { rows } = await client.execute({\n sql: `${upsertSql} RETURNING id`,\n args: upsertArgs,\n });\n return String(rows[0]?.id ?? id);\n }\n\n // SQLite: RETURNING support varies across better-sqlite3/libsql builds, so\n // (matching the convention elsewhere in this codebase, e.g.\n // integrations/pending-tasks-store.ts) re-read the id afterward instead of\n // relying on it. The row is guaranteed to exist at this point, so this is\n // a plain lookup rather than a TOCTOU-prone gate on the write itself.\n await client.execute({ sql: upsertSql, args: upsertArgs });\n const { rows } = await client.execute({\n sql: `SELECT id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,\n args: [scope, scopeId, key],\n });\n return String(rows[0]?.id ?? id);\n}\n\nexport interface ReadSecretResult {\n value: string;\n last4: string;\n updatedAt: number;\n}\n\n/**\n * Read the shared-key format and retain compatibility with rows written before\n * app_secrets moved to its workspace-shared encryption boundary. The legacy\n * fallback is only useful when the current app owns the old row; sibling apps\n * will receive shared-key ciphertext after the next vault sync or update.\n */\ninterface DecryptedAppSecretValue {\n value: string;\n /** True when the app-scoped fallback decrypted encrypted_value. */\n usedLegacyKey: boolean;\n /** True when shared_encrypted_value needs to be created or refreshed. */\n needsSharedCiphertext: boolean;\n /**\n * Existing ciphertext that must still match before a refresh. Null means the\n * migration may only fill an empty shared column.\n */\n sharedCiphertextToReplace?: string | null;\n}\n\nfunction decryptAppSecretValue(\n encrypted: string,\n sharedEncrypted?: string | null,\n): DecryptedAppSecretValue {\n if (sharedEncrypted) {\n try {\n const decrypted = decryptValue(sharedEncrypted);\n return {\n value: decrypted.value,\n usedLegacyKey: false,\n needsSharedCiphertext: decrypted.needsReencrypt,\n sharedCiphertextToReplace: decrypted.needsReencrypt\n ? sharedEncrypted\n : undefined,\n };\n } catch {\n // Fall through to the legacy column. A partially migrated row may have\n // a stale shared ciphertext while the old app-key value is valid.\n }\n }\n try {\n const decrypted = decryptValue(encrypted);\n return {\n value: decrypted.value,\n usedLegacyKey: false,\n needsSharedCiphertext: true,\n sharedCiphertextToReplace: sharedEncrypted ?? null,\n };\n } catch {\n return {\n value: decryptLegacyValue(encrypted),\n usedLegacyKey: true,\n needsSharedCiphertext: true,\n sharedCiphertextToReplace: sharedEncrypted ?? null,\n };\n }\n}\n\n/**\n * Create or refresh the shared column without touching encrypted_value. This\n * is intentionally best-effort: a read must still succeed if a deployment's\n * DB role cannot update the row. The compare-and-swap predicate prevents a\n * concurrent writer from being overwritten, and leaving updated_at untouched\n * preserves the row's user-visible ordering/metadata.\n */\nasync function populateSharedAppSecret(\n id: unknown,\n value: string,\n sharedCiphertextToReplace: string | null,\n): Promise<void> {\n if (\n id === undefined ||\n id === null ||\n !hasSharedSecretEncryptionKeyMaterial()\n ) {\n return;\n }\n try {\n const encrypted = encryptValue(value);\n if (sharedCiphertextToReplace === null) {\n await getDbExec().execute({\n sql: `UPDATE app_secrets SET shared_encrypted_value = ? WHERE id = ? AND shared_encrypted_value IS NULL`,\n args: [encrypted, id],\n });\n } else {\n await getDbExec().execute({\n sql: `UPDATE app_secrets SET shared_encrypted_value = ? WHERE id = ? AND shared_encrypted_value = ?`,\n args: [encrypted, id, sharedCiphertextToReplace],\n });\n }\n } catch {\n // Migration is opportunistic. Preserve the successful read if the update\n // is unavailable due to a read-only role, transient DB failure, or race.\n }\n}\n\ntype AppSecretsReadQuery = { sql: string; args: unknown[] };\n\n/**\n * True only when the database says the app_secrets table itself is missing.\n * Other query failures must propagate unchanged: attempting schema bootstrap\n * for connectivity, permission, or syntax errors both hides the real failure\n * and can introduce DDL onto a latency-sensitive read path.\n */\nfunction isMissingAppSecretsTableError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n const code = String((error as Error & { code?: unknown }).code ?? \"\");\n const message = error.message.toLowerCase();\n const namesAppSecrets = /(?:app_secrets|\"app_secrets\")/.test(message);\n\n if (code === \"42P01\") return namesAppSecrets;\n return (\n namesAppSecrets &&\n (message.includes(\"no such table\") ||\n (message.includes(\"relation\") && message.includes(\"does not exist\")))\n );\n}\n\n/** Execute a read without schema probes on the normal path. */\nasync function executeAppSecretsRead(query: AppSecretsReadQuery) {\n const client = getDbExec();\n try {\n return await client.execute(query);\n } catch (error) {\n if (!isMissingAppSecretsTableError(error)) throw error;\n await ensureTable();\n return client.execute(query);\n }\n}\n\n/**\n * Read a secret's plaintext value. Returns null when not found. The caller\n * is responsible for never logging the returned value.\n */\nexport async function readAppSecret(\n ref: SecretRef,\n): Promise<ReadSecretResult | null> {\n const { key, scope, scopeId } = ref;\n const { rows } = await executeAppSecretsRead({\n sql: `SELECT encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,\n args: [scope, scopeId, key],\n });\n if (rows.length === 0) return null;\n try {\n const encrypted = rows[0].encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n rows[0].shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n rows[0].id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n return {\n value: decrypted.value,\n last4: last4(decrypted.value),\n updatedAt: Number(rows[0].updated_at ?? 0),\n };\n } catch {\n // Decryption failure — key rotated, tampered row, etc. Don't throw up the\n // stack in a way that could leak the ciphertext; just report missing.\n return null;\n }\n}\n\n/** Read several keys from one scope in a single database round trip. */\nexport async function readAppSecrets(args: {\n keys: readonly string[];\n scope: SecretScope;\n scopeId: string;\n}): Promise<Map<string, ReadSecretResult>> {\n const keys = [...new Set(args.keys.filter(Boolean))];\n if (keys.length === 0) return new Map();\n\n const placeholders = keys.map(() => \"?\").join(\", \");\n const { rows } = await executeAppSecretsRead({\n sql: `SELECT key, encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key IN (${placeholders})`,\n args: [args.scope, args.scopeId, ...keys],\n });\n const results = new Map<string, ReadSecretResult>();\n for (const row of rows) {\n const key = String(row.key ?? \"\");\n if (!key) continue;\n try {\n const encrypted = row.encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n row.shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n row.id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n results.set(key, {\n value: decrypted.value,\n last4: last4(decrypted.value),\n updatedAt: Number(row.updated_at ?? 0),\n });\n } catch {\n // Match readAppSecret: corrupted or stale ciphertext behaves as missing.\n }\n }\n return results;\n}\n\n/**\n * Return just the metadata for a secret (no value). Used by the list route so\n * the UI can show the \"Set\" pill and last-4 without the decrypted value going\n * over the wire.\n */\nexport async function getAppSecretMeta(\n ref: SecretRef,\n): Promise<{ last4: string; updatedAt: number } | null> {\n const result = await readAppSecret(ref);\n if (!result) return null;\n return { last4: result.last4, updatedAt: result.updatedAt };\n}\n\nexport interface SecretMeta {\n key: string;\n scope: SecretScope;\n scopeId: string;\n last4: string;\n description: string | null;\n urlAllowlist: string[] | null;\n createdAt: number;\n updatedAt: number;\n}\n\n/**\n * Read a secret's metadata, including ad-hoc fields (description, allowlist),\n * without ever decrypting or returning the plaintext value. Used by the\n * ad-hoc list route and any UI that wants to render a key tile.\n */\nexport async function readAppSecretMeta(\n ref: SecretRef,\n): Promise<SecretMeta | null> {\n await ensureTable();\n const { key, scope, scopeId } = ref;\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,\n args: [scope, scopeId, key],\n });\n if (rows.length === 0) return null;\n const row = rows[0];\n let last4Value = \"\";\n try {\n const encrypted = row.encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n row.shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n row.id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n last4Value = last4(decrypted.value);\n } catch {\n last4Value = \"\";\n }\n return {\n key,\n scope,\n scopeId,\n last4: last4Value,\n description: (row.description as string | null) ?? null,\n urlAllowlist: parseAllowlist(row.url_allowlist as string | null),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\n/**\n * List all secrets for a given scope. Returns metadata only — values are\n * never decrypted or returned. Used by the ad-hoc list route to surface\n * user-created keys.\n */\nexport async function listAppSecretsForScope(\n scope: SecretScope,\n scopeId: string,\n): Promise<SecretMeta[]> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? ORDER BY updated_at DESC`,\n args: [scope, scopeId],\n });\n const results: SecretMeta[] = [];\n for (const row of rows) {\n let last4Value = \"\";\n try {\n const encrypted = row.encrypted_value as string;\n const decrypted = decryptAppSecretValue(\n encrypted,\n row.shared_encrypted_value as string | null,\n );\n if (decrypted.needsSharedCiphertext) {\n await populateSharedAppSecret(\n row.id,\n decrypted.value,\n decrypted.sharedCiphertextToReplace ?? null,\n );\n }\n last4Value = last4(decrypted.value);\n } catch {\n last4Value = \"\";\n }\n results.push({\n key: row.key as string,\n scope,\n scopeId,\n last4: last4Value,\n description: (row.description as string | null) ?? null,\n urlAllowlist: parseAllowlist(row.url_allowlist as string | null),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n });\n }\n return results;\n}\n\nfunction parseAllowlist(raw: string | null): string[] | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((v) => typeof v === \"string\")) {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport async function deleteAppSecret(ref: SecretRef): Promise<boolean> {\n await ensureTable();\n const { key, scope, scopeId } = ref;\n const client = getDbExec();\n const { rowsAffected } = await client.execute({\n sql: `DELETE FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ?`,\n args: [scope, scopeId, key],\n });\n return rowsAffected > 0;\n}\n"]}
@@ -75,7 +75,7 @@ type A2AAgentLoopRunner = typeof runAgentLoopDirectWithSoftTimeout;
75
75
  export declare const DEFAULT_DELEGATED_MAX_ITERATIONS = 80;
76
76
  export declare const DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS = 750000;
77
77
  export declare const DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS = 20000;
78
- export declare const DELEGATED_AGENT_EXECUTION_CONTRACT = "\n<delegated-agent-contract>\nThis request was delegated by another app. You are the specialist owner of the work.\n- Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.\n- Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.\n- Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.\n</delegated-agent-contract>";
78
+ export declare const DELEGATED_AGENT_EXECUTION_CONTRACT = "\n<delegated-agent-contract>\nThis request was delegated by another app. You are the specialist owner of the work.\n- Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.\n- Finish the objective autonomously in this delegated turn whenever a safe, reasonable default exists. Do not bounce the work back with UI-navigation requests, implementation questions, or intermediate status. Ask for input only when authorization, missing credentials, or a consequential user choice truly blocks progress.\n- When evidence is incomplete, return the best grounded partial answer with explicit coverage gaps instead of refusing or asking the caller to choose your source, filter, dashboard, or workflow.\n- Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.\n- Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.\n</delegated-agent-contract>";
79
79
  export interface DelegatedAgentLoopTelemetry {
80
80
  runId: string;
81
81
  threadId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"action-filters-a2a.d.ts","sourceRoot":"","sources":["../../../src/server/agent-chat/action-filters-a2a.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action-filters-a2a.d.ts","sourceRoot":"","sources":["../../../src/server/agent-chat/action-filters-a2a.ts"],"names":[],"mappings":"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"}
@@ -259,6 +259,8 @@ export const DELEGATED_AGENT_EXECUTION_CONTRACT = `
259
259
  <delegated-agent-contract>
260
260
  This request was delegated by another app. You are the specialist owner of the work.
261
261
  - Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.
262
+ - Finish the objective autonomously in this delegated turn whenever a safe, reasonable default exists. Do not bounce the work back with UI-navigation requests, implementation questions, or intermediate status. Ask for input only when authorization, missing credentials, or a consequential user choice truly blocks progress.
263
+ - When evidence is incomplete, return the best grounded partial answer with explicit coverage gaps instead of refusing or asking the caller to choose your source, filter, dashboard, or workflow.
262
264
  - Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.
263
265
  - Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.
264
266
  </delegated-agent-contract>`;
@@ -1 +1 @@
1
- {"version":3,"file":"action-filters-a2a.js","sourceRoot":"","sources":["../../../src/server/agent-chat/action-filters-a2a.ts"],"names":[],"mappings":"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","sourcesContent":["import { getHeader } from \"h3\";\n\nimport {\n appendA2AArtifactLinks,\n type A2AArtifactResponseOptions,\n type A2AToolResultSummary,\n} from \"../../a2a/artifact-response.js\";\nimport { collectFinalResponseTextFromAgentEvents } from \"../../a2a/response-text.js\";\nimport { resolveMainChatMaxOutputTokens } from \"../../agent/engine/output-tokens.js\";\nimport type { EngineTool } from \"../../agent/engine/types.js\";\nimport {\n filterInitialEngineTools,\n resolveAgentRequestReasoningEffort,\n type ActionEntry,\n type AgentLoopOutcome,\n} from \"../../agent/production-agent.js\";\nimport { runAgentLoopDirectWithSoftTimeout } from \"../../agent/run-loop-with-resume.js\";\nimport type { AgentChatEvent } from \"../../agent/types.js\";\nimport {\n isAuthenticatedReadAction,\n isAutoReadExcludedActionName,\n} from \"../../mcp/build-server.js\";\nimport { withConfiguredAppBasePath } from \"../app-base-path.js\";\nimport type { AgentChatPluginOptions } from \"./plugin-options.js\";\n\n// ---------------------------------------------------------------------------\n// Action-visibility filters (read-only / agent-exposed / public-agent-safe)\n// and the A2A (agent-to-agent) final-response assembly + delegated-run\n// helpers that share those filters.\n// ---------------------------------------------------------------------------\n\nexport function filterReadOnlyActions(\n actions: Record<string, ActionEntry>,\n): Record<string, ActionEntry> {\n return Object.fromEntries(\n Object.entries(actions).filter(([, entry]) => entry.readOnly === true),\n );\n}\n\n/** Drop actions that opted out of agent exposure via `agentTool: false`. They\n * remain callable from the frontend / HTTP (mounted separately from this\n * agent tool surface — see `httpActions`) but never appear in any agent tool\n * list (in-app assistant, MCP, A2A, job/trigger runners) or actions prompt.\n * Default-allow: only an explicit `false` is excluded. */\nexport function filterAgentTools(\n actions: Record<string, ActionEntry>,\n): Record<string, ActionEntry> {\n return Object.fromEntries(\n Object.entries(actions).filter(([, entry]) => entry.agentTool !== false),\n );\n}\n\nexport function filterPublicAgentActions(\n actions: Record<string, ActionEntry>,\n): Record<string, ActionEntry> {\n return Object.fromEntries(\n Object.entries(actions).filter(([, entry]) => {\n const config = entry.publicAgent;\n return (\n config?.expose === true &&\n config.readOnly === true &&\n config.requiresAuth !== true &&\n config.isConsequential !== true\n );\n }),\n );\n}\n\n/**\n * Input fields that unambiguously carry a program the receiver executes.\n *\n * Deliberately excludes `query`: across the templates that field is nearly\n * always natural-language search text (Brain's `search-everything`,\n * `search-knowledge`), and blocking it would break exactly the ask-don't-instruct\n * calls this rule exists to encourage.\n */\nconst RAW_QUERY_INPUT_FIELDS = new Set([\"sql\", \"code\", \"script\", \"expression\"]);\n\n/**\n * True when an action takes a free-form query or program as input — raw SQL, a\n * code body, an arbitrary expression.\n *\n * Such an action must not be sibling-invocable over A2A. The app that owns the\n * data owns its schema, data dictionary, skills, and reference queries; a\n * calling app has none of that, so letting it pass SQL means every caller\n * reimplements the owner's schema knowledge badly and silently rots when the\n * owner's shape changes. Callers ask the owning app a question; the owner\n * forms the query. Set `publicAgent.allowRawQueryInput` to opt a specific\n * action out of this rule.\n */\nexport function hasRawQueryInput(entry: ActionEntry): boolean {\n const parameters = entry.tool?.parameters as\n | { properties?: Record<string, { type?: unknown }> }\n | undefined;\n const properties = parameters?.properties;\n if (!properties || typeof properties !== \"object\") return false;\n return Object.entries(properties).some(([field, schema]) => {\n const type = schema?.type;\n const acceptsString =\n type === \"string\" ||\n type === undefined ||\n (Array.isArray(type) && type.includes(\"string\"));\n return RAW_QUERY_INPUT_FIELDS.has(field.toLowerCase()) && acceptsString;\n });\n}\n\n/**\n * Direct A2A action calls share the authenticated external-agent policy with\n * MCP, but remain stricter: only explicitly exposed, authenticated read-only\n * actions can skip the receiver's model loop, and never one that takes a raw\n * query the caller wrote.\n */\nexport function filterDirectA2AActions(\n actions: Record<string, ActionEntry>,\n options: Pick<AgentChatPluginOptions, \"connectorCatalog\" | \"externalAgents\">,\n): Record<string, ActionEntry> {\n const catalog = new Set(options.connectorCatalog ?? []);\n const denied = new Set(options.externalAgents?.denyActions ?? []);\n const autoReads = options.externalAgents?.authenticatedReads === \"auto\";\n\n return Object.fromEntries(\n Object.entries(actions).filter(([name, entry]) => {\n const exposure = entry.publicAgent;\n const selected =\n catalog.has(name) ||\n (autoReads &&\n isAuthenticatedReadAction(entry) &&\n !isAutoReadExcludedActionName(name));\n const rawQueryAllowed =\n !hasRawQueryInput(entry) || exposure?.allowRawQueryInput === true;\n return (\n selected &&\n rawQueryAllowed &&\n !denied.has(name) &&\n entry.agentTool !== false &&\n entry.readOnly === true &&\n exposure?.expose === true &&\n exposure.readOnly === true &&\n exposure.requiresAuth === true &&\n (entry.needsApproval === undefined || entry.needsApproval === false) &&\n exposure.isConsequential !== true\n );\n }),\n );\n}\n\nexport function buildPublicAgentA2ASkills(\n actions: Record<string, ActionEntry>,\n): Array<{\n id: string;\n name: string;\n description: string;\n publicAgent: ActionEntry[\"publicAgent\"];\n inputSchema?: Record<string, unknown>;\n}> {\n return Object.entries(filterPublicAgentActions(actions)).map(\n ([name, entry]) => ({\n id: name,\n name,\n description: entry.tool.description,\n publicAgent: entry.publicAgent,\n ...(entry.tool.parameters\n ? {\n inputSchema: entry.tool.parameters as unknown as Record<\n string,\n unknown\n >,\n }\n : {}),\n }),\n );\n}\n\n/**\n * Skills for a caller with a verified A2A identity: exactly what\n * `filterDirectA2AActions` will execute. Kept separate from\n * `buildPublicAgentA2ASkills` because the public card may only name actions\n * with `requiresAuth !== true` while direct invocation requires\n * `requiresAuth === true` — advertising the public set alone tells siblings\n * an app has nothing callable when it does.\n */\nexport function buildAuthenticatedAgentA2ASkills(\n actions: Record<string, ActionEntry>,\n options: Pick<AgentChatPluginOptions, \"connectorCatalog\" | \"externalAgents\">,\n): Array<{\n id: string;\n name: string;\n description: string;\n publicAgent: ActionEntry[\"publicAgent\"];\n inputSchema?: Record<string, unknown>;\n}> {\n return Object.entries(filterDirectA2AActions(actions, options)).map(\n ([name, entry]) => ({\n id: name,\n name,\n description: entry.tool.description,\n publicAgent: entry.publicAgent,\n // Every action in this set is read-only by construction. Omitting the\n // flag made discovery label all of them \"(mutating)\", which pushes a\n // caller away from invoking them and back into open-ended delegation.\n readOnly: true,\n // Naming an action without its parameters is what makes a caller invoke\n // it with `{}` and fail on a required field.\n ...(entry.tool.parameters\n ? {\n inputSchema: entry.tool.parameters as unknown as Record<\n string,\n unknown\n >,\n }\n : {}),\n }),\n );\n}\n\nexport function resolveArtifactBaseUrl(\n event: any | undefined,\n): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(String(fromEnv));\n\n try {\n const proto = getHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getHeader(event, \"host\");\n if (host) return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {}\n\n return undefined;\n}\n\nexport function assembleA2AFinalResponse(\n events: readonly AgentChatEvent[],\n toolResults: readonly A2AToolResultSummary[],\n options: A2AArtifactResponseOptions & {\n event?: any;\n outcome?: AgentLoopOutcome;\n } = {},\n): { responseText: string; finalText: string } {\n const terminalError = options.outcome\n ? terminalErrorFromOutcome(options.outcome)\n : getA2ATerminalErrorEvent(events);\n const responseText = collectFinalResponseTextFromAgentEvents(events, {\n fallbackToPreToolText: !terminalError,\n });\n const finalText = appendA2AArtifactLinks(responseText, [...toolResults], {\n baseUrl: options.baseUrl ?? resolveArtifactBaseUrl(options.event),\n includeReferencedArtifacts: true,\n includePersistedArtifactMarker: true,\n });\n if (terminalError) {\n const partialResult = finalText.trim()\n ? `\\n\\nPartial verified results before the failure:\\n${finalText.trim()}`\n : \"\";\n throw new Error(formatA2ATerminalError(terminalError) + partialResult);\n }\n if (!finalText.trim()) {\n throw new Error(\n \"Agent completed without a response or verified artifact.\\ncode: empty_agent_response\",\n );\n }\n return { responseText, finalText };\n}\n\nfunction terminalErrorFromOutcome(\n outcome: AgentLoopOutcome,\n): Extract<AgentChatEvent, { type: \"error\" }> | null {\n if (outcome.state === \"completed\") return null;\n if (outcome.state === \"failed\") {\n return {\n type: \"error\",\n error: outcome.message,\n errorCode: outcome.code,\n recoverable: outcome.retryable,\n };\n }\n if (outcome.state === \"input_required\") {\n return {\n type: \"error\",\n error: outcome.message,\n errorCode: outcome.code,\n recoverable: true,\n };\n }\n return {\n type: \"error\",\n error: outcome.message ?? \"Agent run was canceled.\",\n errorCode: \"canceled\",\n recoverable: false,\n };\n}\n\nfunction getA2ATerminalErrorEvent(\n events: readonly AgentChatEvent[],\n): Extract<AgentChatEvent, { type: \"error\" }> | null {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.type === \"clear\") continue;\n if (event.type === \"done\") return null;\n if (event.type === \"error\") return event;\n if (event.type === \"tripwire\") {\n return {\n type: \"error\",\n error: event.reason || \"Agent stopped at a delegated-run guardrail.\",\n errorCode: event.processor ? `tripwire:${event.processor}` : \"tripwire\",\n recoverable: true,\n };\n }\n if (event.type === \"loop_limit\") {\n return {\n type: \"error\",\n error:\n \"Agent stopped before finishing at the delegated-run step limit.\",\n errorCode: \"loop_limit\",\n recoverable: true,\n };\n }\n if (event.type === \"auto_continue\") {\n return {\n type: \"error\",\n error: `Agent stopped before finishing (${event.reason}).`,\n errorCode: event.reason,\n recoverable: true,\n };\n }\n }\n return null;\n}\n\nfunction formatA2ATerminalError(\n event: Extract<AgentChatEvent, { type: \"error\" }>,\n): string {\n const parts = [\n event.error || \"Agent failed before producing a final response.\",\n event.errorCode ? `code: ${event.errorCode}` : \"\",\n event.details ? `details: ${event.details}` : \"\",\n ].filter(Boolean);\n return parts.join(\"\\n\");\n}\n\ntype A2AAgentLoopRunner = typeof runAgentLoopDirectWithSoftTimeout;\n\n/**\n * Delegated turns should do specialist work with the receiver's own tools,\n * but must return a bounded caller-ready result. Interactive defaults allow\n * extremely deep work (400 iterations / 20M cumulative input tokens), which\n * made healthy Slides -> Analytics calls take 4-13 minutes and consume up to\n * millions of input tokens as tool results accumulated. These defaults leave\n * ample room for multi-source analysis while failing before a delegated turn\n * can silently become an unbounded research session.\n */\nexport const DEFAULT_DELEGATED_MAX_ITERATIONS = 80;\nexport const DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS = 750_000;\nexport const DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS = 20_000;\n\nexport const DELEGATED_AGENT_EXECUTION_CONTRACT = `\n<delegated-agent-contract>\nThis request was delegated by another app. You are the specialist owner of the work.\n- Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.\n- Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.\n- Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.\n</delegated-agent-contract>`;\n\nexport interface DelegatedAgentLoopTelemetry {\n runId: string;\n threadId: string | null;\n userId: string | null;\n delegation: {\n protocol: \"a2a\" | \"mcp\";\n callerApp?: string;\n taskId?: string;\n parentRunId?: string;\n parentTurnId?: string;\n };\n}\n\ninterface DelegatedAgentLoopOptions {\n runner?: A2AAgentLoopRunner;\n telemetry?: DelegatedAgentLoopTelemetry;\n}\n\nasync function runDelegatedAgentLoop(\n runOptions: Parameters<A2AAgentLoopRunner>[0],\n pluginOptions: Pick<\n AgentChatPluginOptions,\n \"delegatedRunPolicy\" | \"finalResponseGuard\" | \"runSoftTimeoutMs\"\n >,\n timeoutOptions: Parameters<A2AAgentLoopRunner>[2],\n options: DelegatedAgentLoopOptions,\n) {\n const runner = options.runner ?? runAgentLoopDirectWithSoftTimeout;\n const policy = pluginOptions.delegatedRunPolicy;\n const configuredHardToolResultCap = runOptions.toolLimits?.hardMaxResultChars;\n const delegatedHardToolResultCap =\n policy?.maxToolResultChars ?? DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS;\n const resolvedRunOptions = {\n ...runOptions,\n systemPrompt: runOptions.systemPrompt + DELEGATED_AGENT_EXECUTION_CONTRACT,\n // Delegated runs resolve their own model and do not pass through the\n // interactive request handler's output-token setup. Use the same\n // model-aware headroom here so reasoning models (notably GPT-5.x) do\n // not spend the small internal default entirely on reasoning before\n // emitting a tool call or answer. Preserve explicit test/caller values.\n maxOutputTokens:\n runOptions.maxOutputTokens ??\n resolveMainChatMaxOutputTokens(runOptions.model),\n reasoningEffort:\n runOptions.reasoningEffort ??\n resolveAgentRequestReasoningEffort({ model: runOptions.model }),\n maxIterations:\n runOptions.maxIterations ??\n policy?.maxIterations ??\n DEFAULT_DELEGATED_MAX_ITERATIONS,\n maxRunInputTokens:\n runOptions.maxRunInputTokens ??\n policy?.maxRunInputTokens ??\n DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS,\n toolLimits: {\n ...(runOptions.toolLimits ?? {}),\n hardMaxResultChars:\n typeof configuredHardToolResultCap === \"number\"\n ? Math.min(configuredHardToolResultCap, delegatedHardToolResultCap)\n : delegatedHardToolResultCap,\n },\n finalResponseGuard: pluginOptions.finalResponseGuard,\n };\n const execute = (loopOptions = resolvedRunOptions) =>\n runner(loopOptions, pluginOptions.runSoftTimeoutMs, timeoutOptions);\n\n if (!options.telemetry) return execute();\n\n let instrumented = false;\n try {\n const { getObservabilityConfig, instrumentAgentLoop } =\n await import(\"../../observability/traces.js\");\n const config = await getObservabilityConfig();\n if (config.enabled) {\n instrumented = true;\n return await instrumentAgentLoop({\n runAgentLoop: (loopOptions) =>\n execute(\n loopOptions as Parameters<A2AAgentLoopRunner>[0] &\n typeof resolvedRunOptions,\n ),\n loopOpts: resolvedRunOptions,\n runId: options.telemetry.runId,\n threadId: options.telemetry.threadId,\n userId: options.telemetry.userId,\n config,\n delegation: options.telemetry.delegation,\n });\n }\n } catch (error) {\n // Match interactive chat: setup failures fall through, but a failure from\n // inside an instrumented agent loop is the real run failure and rethrows.\n if (instrumented) throw error;\n }\n return execute();\n}\n\n/**\n * Run an A2A-delegated agent turn with the same final-response guard used by\n * the app's interactive chat surface.\n *\n * Keeping this in one helper prevents delegated calls from silently bypassing\n * template guarantees such as Analytics' requirement to query real data\n * before presenting metrics or exhaustive provider conclusions.\n */\nexport function runA2AAgentLoop(\n runOptions: Parameters<A2AAgentLoopRunner>[0],\n pluginOptions: Pick<\n AgentChatPluginOptions,\n \"delegatedRunPolicy\" | \"finalResponseGuard\" | \"runSoftTimeoutMs\"\n >,\n timeoutOptions: Parameters<A2AAgentLoopRunner>[2],\n options: DelegatedAgentLoopOptions = {},\n) {\n return runDelegatedAgentLoop(\n runOptions,\n pluginOptions,\n timeoutOptions,\n options,\n );\n}\n\n/**\n * Run the MCP-local ask_app turn with the same app-level response guard as\n * A2A. Keeping this seam shared prevents hosted MCP callers from bypassing\n * template guarantees when the request cannot use the self-A2A route.\n */\nexport function runMCPAgentLoop(\n runOptions: Parameters<A2AAgentLoopRunner>[0],\n pluginOptions: Pick<\n AgentChatPluginOptions,\n \"delegatedRunPolicy\" | \"finalResponseGuard\" | \"runSoftTimeoutMs\"\n >,\n timeoutOptions: Parameters<A2AAgentLoopRunner>[2],\n options: DelegatedAgentLoopOptions = {},\n) {\n return runDelegatedAgentLoop(\n runOptions,\n pluginOptions,\n timeoutOptions,\n options,\n );\n}\n\n/**\n * Keep delegated A2A turns on the same compact initial tool surface as\n * interactive chat. `tool-search` remains in the initial set, while the\n * complete registry is supplied separately so the run loop can load a matched\n * schema after a tool-search result.\n */\nexport function createA2AEngineToolSurface(\n availableTools: EngineTool[],\n initialToolNames?: string[],\n): { tools: EngineTool[]; availableTools: EngineTool[] } {\n return {\n tools: filterInitialEngineTools(availableTools, initialToolNames),\n availableTools,\n };\n}\n\nexport function resolveInitialToolNames(\n templateActions: Record<string, ActionEntry>,\n configured?: string[],\n): string[] {\n return configured ?? Object.keys(templateActions);\n}\n"]}
1
+ {"version":3,"file":"action-filters-a2a.js","sourceRoot":"","sources":["../../../src/server/agent-chat/action-filters-a2a.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,EACL,sBAAsB,GAGvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,uCAAuC,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,OAAO,EACL,wBAAwB,EACxB,kCAAkC,GAGnC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,iCAAiC,EAAE,MAAM,qCAAqC,CAAC;AAExF,OAAO,EACL,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AACvE,oCAAoC;AACpC,8EAA8E;AAE9E,MAAM,UAAU,qBAAqB,CACnC,OAAoC;IAEpC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,CACvE,CAAC;AACJ,CAAC;AAED;;;;2DAI2D;AAC3D,MAAM,UAAU,gBAAgB,CAC9B,OAAoC;IAEpC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,CACzE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,OAAoC;IAEpC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;QACjC,OAAO,CACL,MAAM,EAAE,MAAM,KAAK,IAAI;YACvB,MAAM,CAAC,QAAQ,KAAK,IAAI;YACxB,MAAM,CAAC,YAAY,KAAK,IAAI;YAC5B,MAAM,CAAC,eAAe,KAAK,IAAI,CAChC,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;AAEhF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,UAElB,CAAC;IACd,MAAM,UAAU,GAAG,UAAU,EAAE,UAAU,CAAC;IAC1C,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAChE,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE;QACzD,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,CAAC;QAC1B,MAAM,aAAa,GACjB,IAAI,KAAK,QAAQ;YACjB,IAAI,KAAK,SAAS;YAClB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACnD,OAAO,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,aAAa,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAoC,EACpC,OAA4E;IAE5E,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,kBAAkB,KAAK,MAAM,CAAC;IAExE,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC;QACnC,MAAM,QAAQ,GACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YACjB,CAAC,SAAS;gBACR,yBAAyB,CAAC,KAAK,CAAC;gBAChC,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,MAAM,eAAe,GACnB,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;QACpE,OAAO,CACL,QAAQ;YACR,eAAe;YACf,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;YACjB,KAAK,CAAC,SAAS,KAAK,KAAK;YACzB,KAAK,CAAC,QAAQ,KAAK,IAAI;YACvB,QAAQ,EAAE,MAAM,KAAK,IAAI;YACzB,QAAQ,CAAC,QAAQ,KAAK,IAAI;YAC1B,QAAQ,CAAC,YAAY,KAAK,IAAI;YAC9B,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,IAAI,KAAK,CAAC,aAAa,KAAK,KAAK,CAAC;YACpE,QAAQ,CAAC,eAAe,KAAK,IAAI,CAClC,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,OAAoC;IAQpC,OAAO,MAAM,CAAC,OAAO,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAC1D,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QAClB,EAAE,EAAE,IAAI;QACR,IAAI;QACJ,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW;QACnC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU;YACvB,CAAC,CAAC;gBACE,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,UAGvB;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gCAAgC,CAC9C,OAAoC,EACpC,OAA4E;IAQ5E,OAAO,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CACjE,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QAClB,EAAE,EAAE,IAAI;QACR,IAAI;QACJ,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW;QACnC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,sEAAsE;QACtE,qEAAqE;QACrE,sEAAsE;QACtE,QAAQ,EAAE,IAAI;QACd,wEAAwE;QACxE,6CAA6C;QAC7C,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU;YACvB,CAAC,CAAC;gBACE,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,UAGvB;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAsB;IAEtB,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,OAAO;QACnB,OAAO,CAAC,GAAG,CAAC,GAAG;QACf,OAAO,CAAC,GAAG,CAAC,UAAU;QACtB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC9B,IAAI,OAAO;QAAE,OAAO,yBAAyB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAE/D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,mBAAmB,CAAC,IAAI,OAAO,CAAC;QAC/D,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACtC,IAAI,IAAI;YAAE,OAAO,yBAAyB,CAAC,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,MAAiC,EACjC,WAA4C,EAC5C,OAAO,GAGH,EAAE;IAEN,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO;QACnC,CAAC,CAAC,wBAAwB,CAAC,OAAO,CAAC,OAAO,CAAC;QAC3C,CAAC,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,YAAY,GAAG,uCAAuC,CAAC,MAAM,EAAE;QACnE,qBAAqB,EAAE,CAAC,aAAa;KACtC,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,sBAAsB,CAAC,YAAY,EAAE,CAAC,GAAG,WAAW,CAAC,EAAE;QACvE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,sBAAsB,CAAC,OAAO,CAAC,KAAK,CAAC;QACjE,0BAA0B,EAAE,IAAI;QAChC,8BAA8B,EAAE,IAAI;KACrC,CAAC,CAAC;IACH,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,EAAE;YACpC,CAAC,CAAC,qDAAqD,SAAS,CAAC,IAAI,EAAE,EAAE;YACzE,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,aAAa,CAAC,GAAG,aAAa,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,wBAAwB,CAC/B,OAAyB;IAEzB,IAAI,OAAO,CAAC,KAAK,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO;YACL,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,OAAO,CAAC,OAAO;YACtB,SAAS,EAAE,OAAO,CAAC,IAAI;YACvB,WAAW,EAAE,OAAO,CAAC,SAAS;SAC/B,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,gBAAgB,EAAE,CAAC;QACvC,OAAO;YACL,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,OAAO,CAAC,OAAO;YACtB,SAAS,EAAE,OAAO,CAAC,IAAI;YACvB,WAAW,EAAE,IAAI;SAClB,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO,CAAC,OAAO,IAAI,yBAAyB;QACnD,SAAS,EAAE,UAAU;QACrB,WAAW,EAAE,KAAK;KACnB,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAC/B,MAAiC;IAEjC,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,SAAS;QACrC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QACvC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,KAAK,CAAC;QACzC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,KAAK,CAAC,MAAM,IAAI,6CAA6C;gBACpE,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,UAAU;gBACvE,WAAW,EAAE,IAAI;aAClB,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChC,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,KAAK,EACH,iEAAiE;gBACnE,SAAS,EAAE,YAAY;gBACvB,WAAW,EAAE,IAAI;aAClB,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACnC,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,mCAAmC,KAAK,CAAC,MAAM,IAAI;gBAC1D,SAAS,EAAE,KAAK,CAAC,MAAM;gBACvB,WAAW,EAAE,IAAI;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAiD;IAEjD,MAAM,KAAK,GAAG;QACZ,KAAK,CAAC,KAAK,IAAI,iDAAiD;QAChE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE;QACjD,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE;KACjD,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAID;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,EAAE,CAAC;AACnD,MAAM,CAAC,MAAM,sCAAsC,GAAG,OAAO,CAAC;AAC9D,MAAM,CAAC,MAAM,uCAAuC,GAAG,MAAM,CAAC;AAE9D,MAAM,CAAC,MAAM,kCAAkC,GAAG;;;;;;;;4BAQtB,CAAC;AAoB7B,KAAK,UAAU,qBAAqB,CAClC,UAA6C,EAC7C,aAGC,EACD,cAAiD,EACjD,OAAkC;IAElC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,iCAAiC,CAAC;IACnE,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,CAAC;IAChD,MAAM,2BAA2B,GAAG,UAAU,CAAC,UAAU,EAAE,kBAAkB,CAAC;IAC9E,MAAM,0BAA0B,GAC9B,MAAM,EAAE,kBAAkB,IAAI,uCAAuC,CAAC;IACxE,MAAM,kBAAkB,GAAG;QACzB,GAAG,UAAU;QACb,YAAY,EAAE,UAAU,CAAC,YAAY,GAAG,kCAAkC;QAC1E,qEAAqE;QACrE,iEAAiE;QACjE,qEAAqE;QACrE,oEAAoE;QACpE,wEAAwE;QACxE,eAAe,EACb,UAAU,CAAC,eAAe;YAC1B,8BAA8B,CAAC,UAAU,CAAC,KAAK,CAAC;QAClD,eAAe,EACb,UAAU,CAAC,eAAe;YAC1B,kCAAkC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;QACjE,aAAa,EACX,UAAU,CAAC,aAAa;YACxB,MAAM,EAAE,aAAa;YACrB,gCAAgC;QAClC,iBAAiB,EACf,UAAU,CAAC,iBAAiB;YAC5B,MAAM,EAAE,iBAAiB;YACzB,sCAAsC;QACxC,UAAU,EAAE;YACV,GAAG,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,CAAC;YAChC,kBAAkB,EAChB,OAAO,2BAA2B,KAAK,QAAQ;gBAC7C,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,2BAA2B,EAAE,0BAA0B,CAAC;gBACnE,CAAC,CAAC,0BAA0B;SACjC;QACD,kBAAkB,EAAE,aAAa,CAAC,kBAAkB;KACrD,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,WAAW,GAAG,kBAAkB,EAAE,EAAE,CACnD,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;IAEtE,IAAI,CAAC,OAAO,CAAC,SAAS;QAAE,OAAO,OAAO,EAAE,CAAC;IAEzC,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,GACnD,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,sBAAsB,EAAE,CAAC;QAC9C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,YAAY,GAAG,IAAI,CAAC;YACpB,OAAO,MAAM,mBAAmB,CAAC;gBAC/B,YAAY,EAAE,CAAC,WAAW,EAAE,EAAE,CAC5B,OAAO,CACL,WAC2B,CAC5B;gBACH,QAAQ,EAAE,kBAAkB;gBAC5B,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK;gBAC9B,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,QAAQ;gBACpC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM;gBAChC,MAAM;gBACN,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,UAAU;aACzC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,0EAA0E;QAC1E,IAAI,YAAY;YAAE,MAAM,KAAK,CAAC;IAChC,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,UAA6C,EAC7C,aAGC,EACD,cAAiD,EACjD,OAAO,GAA8B,EAAE;IAEvC,OAAO,qBAAqB,CAC1B,UAAU,EACV,aAAa,EACb,cAAc,EACd,OAAO,CACR,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,UAA6C,EAC7C,aAGC,EACD,cAAiD,EACjD,OAAO,GAA8B,EAAE;IAEvC,OAAO,qBAAqB,CAC1B,UAAU,EACV,aAAa,EACb,cAAc,EACd,OAAO,CACR,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CACxC,cAA4B,EAC5B,gBAA2B;IAE3B,OAAO;QACL,KAAK,EAAE,wBAAwB,CAAC,cAAc,EAAE,gBAAgB,CAAC;QACjE,cAAc;KACf,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,eAA4C,EAC5C,UAAqB;IAErB,OAAO,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AACpD,CAAC","sourcesContent":["import { getHeader } from \"h3\";\n\nimport {\n appendA2AArtifactLinks,\n type A2AArtifactResponseOptions,\n type A2AToolResultSummary,\n} from \"../../a2a/artifact-response.js\";\nimport { collectFinalResponseTextFromAgentEvents } from \"../../a2a/response-text.js\";\nimport { resolveMainChatMaxOutputTokens } from \"../../agent/engine/output-tokens.js\";\nimport type { EngineTool } from \"../../agent/engine/types.js\";\nimport {\n filterInitialEngineTools,\n resolveAgentRequestReasoningEffort,\n type ActionEntry,\n type AgentLoopOutcome,\n} from \"../../agent/production-agent.js\";\nimport { runAgentLoopDirectWithSoftTimeout } from \"../../agent/run-loop-with-resume.js\";\nimport type { AgentChatEvent } from \"../../agent/types.js\";\nimport {\n isAuthenticatedReadAction,\n isAutoReadExcludedActionName,\n} from \"../../mcp/build-server.js\";\nimport { withConfiguredAppBasePath } from \"../app-base-path.js\";\nimport type { AgentChatPluginOptions } from \"./plugin-options.js\";\n\n// ---------------------------------------------------------------------------\n// Action-visibility filters (read-only / agent-exposed / public-agent-safe)\n// and the A2A (agent-to-agent) final-response assembly + delegated-run\n// helpers that share those filters.\n// ---------------------------------------------------------------------------\n\nexport function filterReadOnlyActions(\n actions: Record<string, ActionEntry>,\n): Record<string, ActionEntry> {\n return Object.fromEntries(\n Object.entries(actions).filter(([, entry]) => entry.readOnly === true),\n );\n}\n\n/** Drop actions that opted out of agent exposure via `agentTool: false`. They\n * remain callable from the frontend / HTTP (mounted separately from this\n * agent tool surface — see `httpActions`) but never appear in any agent tool\n * list (in-app assistant, MCP, A2A, job/trigger runners) or actions prompt.\n * Default-allow: only an explicit `false` is excluded. */\nexport function filterAgentTools(\n actions: Record<string, ActionEntry>,\n): Record<string, ActionEntry> {\n return Object.fromEntries(\n Object.entries(actions).filter(([, entry]) => entry.agentTool !== false),\n );\n}\n\nexport function filterPublicAgentActions(\n actions: Record<string, ActionEntry>,\n): Record<string, ActionEntry> {\n return Object.fromEntries(\n Object.entries(actions).filter(([, entry]) => {\n const config = entry.publicAgent;\n return (\n config?.expose === true &&\n config.readOnly === true &&\n config.requiresAuth !== true &&\n config.isConsequential !== true\n );\n }),\n );\n}\n\n/**\n * Input fields that unambiguously carry a program the receiver executes.\n *\n * Deliberately excludes `query`: across the templates that field is nearly\n * always natural-language search text (Brain's `search-everything`,\n * `search-knowledge`), and blocking it would break exactly the ask-don't-instruct\n * calls this rule exists to encourage.\n */\nconst RAW_QUERY_INPUT_FIELDS = new Set([\"sql\", \"code\", \"script\", \"expression\"]);\n\n/**\n * True when an action takes a free-form query or program as input — raw SQL, a\n * code body, an arbitrary expression.\n *\n * Such an action must not be sibling-invocable over A2A. The app that owns the\n * data owns its schema, data dictionary, skills, and reference queries; a\n * calling app has none of that, so letting it pass SQL means every caller\n * reimplements the owner's schema knowledge badly and silently rots when the\n * owner's shape changes. Callers ask the owning app a question; the owner\n * forms the query. Set `publicAgent.allowRawQueryInput` to opt a specific\n * action out of this rule.\n */\nexport function hasRawQueryInput(entry: ActionEntry): boolean {\n const parameters = entry.tool?.parameters as\n | { properties?: Record<string, { type?: unknown }> }\n | undefined;\n const properties = parameters?.properties;\n if (!properties || typeof properties !== \"object\") return false;\n return Object.entries(properties).some(([field, schema]) => {\n const type = schema?.type;\n const acceptsString =\n type === \"string\" ||\n type === undefined ||\n (Array.isArray(type) && type.includes(\"string\"));\n return RAW_QUERY_INPUT_FIELDS.has(field.toLowerCase()) && acceptsString;\n });\n}\n\n/**\n * Direct A2A action calls share the authenticated external-agent policy with\n * MCP, but remain stricter: only explicitly exposed, authenticated read-only\n * actions can skip the receiver's model loop, and never one that takes a raw\n * query the caller wrote.\n */\nexport function filterDirectA2AActions(\n actions: Record<string, ActionEntry>,\n options: Pick<AgentChatPluginOptions, \"connectorCatalog\" | \"externalAgents\">,\n): Record<string, ActionEntry> {\n const catalog = new Set(options.connectorCatalog ?? []);\n const denied = new Set(options.externalAgents?.denyActions ?? []);\n const autoReads = options.externalAgents?.authenticatedReads === \"auto\";\n\n return Object.fromEntries(\n Object.entries(actions).filter(([name, entry]) => {\n const exposure = entry.publicAgent;\n const selected =\n catalog.has(name) ||\n (autoReads &&\n isAuthenticatedReadAction(entry) &&\n !isAutoReadExcludedActionName(name));\n const rawQueryAllowed =\n !hasRawQueryInput(entry) || exposure?.allowRawQueryInput === true;\n return (\n selected &&\n rawQueryAllowed &&\n !denied.has(name) &&\n entry.agentTool !== false &&\n entry.readOnly === true &&\n exposure?.expose === true &&\n exposure.readOnly === true &&\n exposure.requiresAuth === true &&\n (entry.needsApproval === undefined || entry.needsApproval === false) &&\n exposure.isConsequential !== true\n );\n }),\n );\n}\n\nexport function buildPublicAgentA2ASkills(\n actions: Record<string, ActionEntry>,\n): Array<{\n id: string;\n name: string;\n description: string;\n publicAgent: ActionEntry[\"publicAgent\"];\n inputSchema?: Record<string, unknown>;\n}> {\n return Object.entries(filterPublicAgentActions(actions)).map(\n ([name, entry]) => ({\n id: name,\n name,\n description: entry.tool.description,\n publicAgent: entry.publicAgent,\n ...(entry.tool.parameters\n ? {\n inputSchema: entry.tool.parameters as unknown as Record<\n string,\n unknown\n >,\n }\n : {}),\n }),\n );\n}\n\n/**\n * Skills for a caller with a verified A2A identity: exactly what\n * `filterDirectA2AActions` will execute. Kept separate from\n * `buildPublicAgentA2ASkills` because the public card may only name actions\n * with `requiresAuth !== true` while direct invocation requires\n * `requiresAuth === true` — advertising the public set alone tells siblings\n * an app has nothing callable when it does.\n */\nexport function buildAuthenticatedAgentA2ASkills(\n actions: Record<string, ActionEntry>,\n options: Pick<AgentChatPluginOptions, \"connectorCatalog\" | \"externalAgents\">,\n): Array<{\n id: string;\n name: string;\n description: string;\n publicAgent: ActionEntry[\"publicAgent\"];\n inputSchema?: Record<string, unknown>;\n}> {\n return Object.entries(filterDirectA2AActions(actions, options)).map(\n ([name, entry]) => ({\n id: name,\n name,\n description: entry.tool.description,\n publicAgent: entry.publicAgent,\n // Every action in this set is read-only by construction. Omitting the\n // flag made discovery label all of them \"(mutating)\", which pushes a\n // caller away from invoking them and back into open-ended delegation.\n readOnly: true,\n // Naming an action without its parameters is what makes a caller invoke\n // it with `{}` and fail on a required field.\n ...(entry.tool.parameters\n ? {\n inputSchema: entry.tool.parameters as unknown as Record<\n string,\n unknown\n >,\n }\n : {}),\n }),\n );\n}\n\nexport function resolveArtifactBaseUrl(\n event: any | undefined,\n): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(String(fromEnv));\n\n try {\n const proto = getHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getHeader(event, \"host\");\n if (host) return withConfiguredAppBasePath(`${proto}://${host}`);\n } catch {}\n\n return undefined;\n}\n\nexport function assembleA2AFinalResponse(\n events: readonly AgentChatEvent[],\n toolResults: readonly A2AToolResultSummary[],\n options: A2AArtifactResponseOptions & {\n event?: any;\n outcome?: AgentLoopOutcome;\n } = {},\n): { responseText: string; finalText: string } {\n const terminalError = options.outcome\n ? terminalErrorFromOutcome(options.outcome)\n : getA2ATerminalErrorEvent(events);\n const responseText = collectFinalResponseTextFromAgentEvents(events, {\n fallbackToPreToolText: !terminalError,\n });\n const finalText = appendA2AArtifactLinks(responseText, [...toolResults], {\n baseUrl: options.baseUrl ?? resolveArtifactBaseUrl(options.event),\n includeReferencedArtifacts: true,\n includePersistedArtifactMarker: true,\n });\n if (terminalError) {\n const partialResult = finalText.trim()\n ? `\\n\\nPartial verified results before the failure:\\n${finalText.trim()}`\n : \"\";\n throw new Error(formatA2ATerminalError(terminalError) + partialResult);\n }\n if (!finalText.trim()) {\n throw new Error(\n \"Agent completed without a response or verified artifact.\\ncode: empty_agent_response\",\n );\n }\n return { responseText, finalText };\n}\n\nfunction terminalErrorFromOutcome(\n outcome: AgentLoopOutcome,\n): Extract<AgentChatEvent, { type: \"error\" }> | null {\n if (outcome.state === \"completed\") return null;\n if (outcome.state === \"failed\") {\n return {\n type: \"error\",\n error: outcome.message,\n errorCode: outcome.code,\n recoverable: outcome.retryable,\n };\n }\n if (outcome.state === \"input_required\") {\n return {\n type: \"error\",\n error: outcome.message,\n errorCode: outcome.code,\n recoverable: true,\n };\n }\n return {\n type: \"error\",\n error: outcome.message ?? \"Agent run was canceled.\",\n errorCode: \"canceled\",\n recoverable: false,\n };\n}\n\nfunction getA2ATerminalErrorEvent(\n events: readonly AgentChatEvent[],\n): Extract<AgentChatEvent, { type: \"error\" }> | null {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.type === \"clear\") continue;\n if (event.type === \"done\") return null;\n if (event.type === \"error\") return event;\n if (event.type === \"tripwire\") {\n return {\n type: \"error\",\n error: event.reason || \"Agent stopped at a delegated-run guardrail.\",\n errorCode: event.processor ? `tripwire:${event.processor}` : \"tripwire\",\n recoverable: true,\n };\n }\n if (event.type === \"loop_limit\") {\n return {\n type: \"error\",\n error:\n \"Agent stopped before finishing at the delegated-run step limit.\",\n errorCode: \"loop_limit\",\n recoverable: true,\n };\n }\n if (event.type === \"auto_continue\") {\n return {\n type: \"error\",\n error: `Agent stopped before finishing (${event.reason}).`,\n errorCode: event.reason,\n recoverable: true,\n };\n }\n }\n return null;\n}\n\nfunction formatA2ATerminalError(\n event: Extract<AgentChatEvent, { type: \"error\" }>,\n): string {\n const parts = [\n event.error || \"Agent failed before producing a final response.\",\n event.errorCode ? `code: ${event.errorCode}` : \"\",\n event.details ? `details: ${event.details}` : \"\",\n ].filter(Boolean);\n return parts.join(\"\\n\");\n}\n\ntype A2AAgentLoopRunner = typeof runAgentLoopDirectWithSoftTimeout;\n\n/**\n * Delegated turns should do specialist work with the receiver's own tools,\n * but must return a bounded caller-ready result. Interactive defaults allow\n * extremely deep work (400 iterations / 20M cumulative input tokens), which\n * made healthy Slides -> Analytics calls take 4-13 minutes and consume up to\n * millions of input tokens as tool results accumulated. These defaults leave\n * ample room for multi-source analysis while failing before a delegated turn\n * can silently become an unbounded research session.\n */\nexport const DEFAULT_DELEGATED_MAX_ITERATIONS = 80;\nexport const DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS = 750_000;\nexport const DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS = 20_000;\n\nexport const DELEGATED_AGENT_EXECUTION_CONTRACT = `\n<delegated-agent-contract>\nThis request was delegated by another app. You are the specialist owner of the work.\n- Interpret the caller's natural-language objective using your own instructions, skills, data dictionary, credentials, and tools. Choose providers, schemas, queries, and joins here; never ask the caller to invent SQL or source-specific implementation details for you.\n- Finish the objective autonomously in this delegated turn whenever a safe, reasonable default exists. Do not bounce the work back with UI-navigation requests, implementation questions, or intermediate status. Ask for input only when authorization, missing credentials, or a consequential user choice truly blocks progress.\n- When evidence is incomplete, return the best grounded partial answer with explicit coverage gaps instead of refusing or asking the caller to choose your source, filter, dashboard, or workflow.\n- Minimize round trips. Filter, join, aggregate, paginate, stage, and reduce large datasets inside your own tools rather than returning raw records or transcripts.\n- Return a concise caller-ready result with the answer, source and coverage details, relevant counts or IDs, caveats/partial gaps, and exact artifact URLs. Do not return tool transcripts or large raw payloads.\n</delegated-agent-contract>`;\n\nexport interface DelegatedAgentLoopTelemetry {\n runId: string;\n threadId: string | null;\n userId: string | null;\n delegation: {\n protocol: \"a2a\" | \"mcp\";\n callerApp?: string;\n taskId?: string;\n parentRunId?: string;\n parentTurnId?: string;\n };\n}\n\ninterface DelegatedAgentLoopOptions {\n runner?: A2AAgentLoopRunner;\n telemetry?: DelegatedAgentLoopTelemetry;\n}\n\nasync function runDelegatedAgentLoop(\n runOptions: Parameters<A2AAgentLoopRunner>[0],\n pluginOptions: Pick<\n AgentChatPluginOptions,\n \"delegatedRunPolicy\" | \"finalResponseGuard\" | \"runSoftTimeoutMs\"\n >,\n timeoutOptions: Parameters<A2AAgentLoopRunner>[2],\n options: DelegatedAgentLoopOptions,\n) {\n const runner = options.runner ?? runAgentLoopDirectWithSoftTimeout;\n const policy = pluginOptions.delegatedRunPolicy;\n const configuredHardToolResultCap = runOptions.toolLimits?.hardMaxResultChars;\n const delegatedHardToolResultCap =\n policy?.maxToolResultChars ?? DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS;\n const resolvedRunOptions = {\n ...runOptions,\n systemPrompt: runOptions.systemPrompt + DELEGATED_AGENT_EXECUTION_CONTRACT,\n // Delegated runs resolve their own model and do not pass through the\n // interactive request handler's output-token setup. Use the same\n // model-aware headroom here so reasoning models (notably GPT-5.x) do\n // not spend the small internal default entirely on reasoning before\n // emitting a tool call or answer. Preserve explicit test/caller values.\n maxOutputTokens:\n runOptions.maxOutputTokens ??\n resolveMainChatMaxOutputTokens(runOptions.model),\n reasoningEffort:\n runOptions.reasoningEffort ??\n resolveAgentRequestReasoningEffort({ model: runOptions.model }),\n maxIterations:\n runOptions.maxIterations ??\n policy?.maxIterations ??\n DEFAULT_DELEGATED_MAX_ITERATIONS,\n maxRunInputTokens:\n runOptions.maxRunInputTokens ??\n policy?.maxRunInputTokens ??\n DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS,\n toolLimits: {\n ...(runOptions.toolLimits ?? {}),\n hardMaxResultChars:\n typeof configuredHardToolResultCap === \"number\"\n ? Math.min(configuredHardToolResultCap, delegatedHardToolResultCap)\n : delegatedHardToolResultCap,\n },\n finalResponseGuard: pluginOptions.finalResponseGuard,\n };\n const execute = (loopOptions = resolvedRunOptions) =>\n runner(loopOptions, pluginOptions.runSoftTimeoutMs, timeoutOptions);\n\n if (!options.telemetry) return execute();\n\n let instrumented = false;\n try {\n const { getObservabilityConfig, instrumentAgentLoop } =\n await import(\"../../observability/traces.js\");\n const config = await getObservabilityConfig();\n if (config.enabled) {\n instrumented = true;\n return await instrumentAgentLoop({\n runAgentLoop: (loopOptions) =>\n execute(\n loopOptions as Parameters<A2AAgentLoopRunner>[0] &\n typeof resolvedRunOptions,\n ),\n loopOpts: resolvedRunOptions,\n runId: options.telemetry.runId,\n threadId: options.telemetry.threadId,\n userId: options.telemetry.userId,\n config,\n delegation: options.telemetry.delegation,\n });\n }\n } catch (error) {\n // Match interactive chat: setup failures fall through, but a failure from\n // inside an instrumented agent loop is the real run failure and rethrows.\n if (instrumented) throw error;\n }\n return execute();\n}\n\n/**\n * Run an A2A-delegated agent turn with the same final-response guard used by\n * the app's interactive chat surface.\n *\n * Keeping this in one helper prevents delegated calls from silently bypassing\n * template guarantees such as Analytics' requirement to query real data\n * before presenting metrics or exhaustive provider conclusions.\n */\nexport function runA2AAgentLoop(\n runOptions: Parameters<A2AAgentLoopRunner>[0],\n pluginOptions: Pick<\n AgentChatPluginOptions,\n \"delegatedRunPolicy\" | \"finalResponseGuard\" | \"runSoftTimeoutMs\"\n >,\n timeoutOptions: Parameters<A2AAgentLoopRunner>[2],\n options: DelegatedAgentLoopOptions = {},\n) {\n return runDelegatedAgentLoop(\n runOptions,\n pluginOptions,\n timeoutOptions,\n options,\n );\n}\n\n/**\n * Run the MCP-local ask_app turn with the same app-level response guard as\n * A2A. Keeping this seam shared prevents hosted MCP callers from bypassing\n * template guarantees when the request cannot use the self-A2A route.\n */\nexport function runMCPAgentLoop(\n runOptions: Parameters<A2AAgentLoopRunner>[0],\n pluginOptions: Pick<\n AgentChatPluginOptions,\n \"delegatedRunPolicy\" | \"finalResponseGuard\" | \"runSoftTimeoutMs\"\n >,\n timeoutOptions: Parameters<A2AAgentLoopRunner>[2],\n options: DelegatedAgentLoopOptions = {},\n) {\n return runDelegatedAgentLoop(\n runOptions,\n pluginOptions,\n timeoutOptions,\n options,\n );\n}\n\n/**\n * Keep delegated A2A turns on the same compact initial tool surface as\n * interactive chat. `tool-search` remains in the initial set, while the\n * complete registry is supplied separately so the run loop can load a matched\n * schema after a tool-search result.\n */\nexport function createA2AEngineToolSurface(\n availableTools: EngineTool[],\n initialToolNames?: string[],\n): { tools: EngineTool[]; availableTools: EngineTool[] } {\n return {\n tools: filterInitialEngineTools(availableTools, initialToolNames),\n availableTools,\n };\n}\n\nexport function resolveInitialToolNames(\n templateActions: Record<string, ActionEntry>,\n configured?: string[],\n): string[] {\n return configured ?? Object.keys(templateActions);\n}\n"]}
@@ -26,9 +26,9 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
26
26
  expiresAt?: undefined;
27
27
  ttlSeconds?: undefined;
28
28
  } | {
29
- error?: undefined;
30
29
  token: string;
31
30
  expiresAt: string;
32
31
  ttlSeconds: number;
32
+ error?: undefined;
33
33
  }>>;
34
34
  //# sourceMappingURL=realtime-token.d.ts.map
@@ -20,7 +20,7 @@ export declare function createTranscribeVoiceHandler(): import("h3").EventHandle
20
20
  error: string;
21
21
  text?: undefined;
22
22
  } | {
23
- error?: undefined;
24
23
  text: string;
24
+ error?: undefined;
25
25
  }>>;
26
26
  //# sourceMappingURL=transcribe-voice.d.ts.map
@@ -227,15 +227,20 @@ Core routes plugin mounts these under `/_agent-native/secrets/` automatically:
227
227
  prefer `<APP_NAME>_SECRETS_ENCRYPTION_KEY` (for example,
228
228
  `ANALYTICS_SECRETS_ENCRYPTION_KEY`), then `SECRETS_ENCRYPTION_KEY`, then
229
229
  `BETTER_AUTH_SECRET`.
230
- - Workspace-shared `app_secrets` prefer `SECRETS_ENCRYPTION_KEY`, then a
231
- purpose-derived key from `A2A_SECRET`. Better Auth and app-scoped keys remain
232
- legacy read candidates; a successful legacy decrypt is compare-and-swap
233
- migrated to the preferred shared key without changing the row timestamp.
234
- - Set the same stable `SECRETS_ENCRYPTION_KEY` in every app that reads a shared
235
- vault. If the vault relies on `A2A_SECRET`, rotating A2A material also rotates
236
- its encryption key. Before rotating A2A, add the stable vault key everywhere
237
- and read/migrate every existing row while the old A2A material is still
238
- available.
230
+ - Workspace-shared `app_secrets` prefer
231
+ `WORKSPACE_SECRETS_ENCRYPTION_KEY`, then the legacy shared
232
+ `SECRETS_ENCRYPTION_KEY`, then a purpose-derived key from `A2A_SECRET`.
233
+ Better Auth and app-scoped keys remain legacy read candidates; a successful
234
+ legacy decrypt is compare-and-swap migrated to the preferred shared key
235
+ without changing the row timestamp.
236
+ - Set the same stable `WORKSPACE_SECRETS_ENCRYPTION_KEY` in every app that
237
+ reads a shared vault. It is intentionally separate from app-local OAuth
238
+ encryption. If the vault still relies on `A2A_SECRET`, rotating A2A material
239
+ also rotates its encryption key. Add the stable vault key everywhere and
240
+ read/migrate existing rows before rotating A2A.
241
+ - To rotate the dedicated workspace key itself, deploy the new value together
242
+ with `WORKSPACE_SECRETS_ENCRYPTION_KEY_PREVIOUS=<old value>`, let reads
243
+ migrate ciphertext, then remove the previous key after the migration window.
239
244
  - If no configured key material exists, development uses a machine-local
240
245
  fallback and logs a one-time warning. Production fails closed.
241
246
 
@@ -227,15 +227,20 @@ Core routes plugin mounts these under `/_agent-native/secrets/` automatically:
227
227
  prefer `<APP_NAME>_SECRETS_ENCRYPTION_KEY` (for example,
228
228
  `ANALYTICS_SECRETS_ENCRYPTION_KEY`), then `SECRETS_ENCRYPTION_KEY`, then
229
229
  `BETTER_AUTH_SECRET`.
230
- - Workspace-shared `app_secrets` prefer `SECRETS_ENCRYPTION_KEY`, then a
231
- purpose-derived key from `A2A_SECRET`. Better Auth and app-scoped keys remain
232
- legacy read candidates; a successful legacy decrypt is compare-and-swap
233
- migrated to the preferred shared key without changing the row timestamp.
234
- - Set the same stable `SECRETS_ENCRYPTION_KEY` in every app that reads a shared
235
- vault. If the vault relies on `A2A_SECRET`, rotating A2A material also rotates
236
- its encryption key. Before rotating A2A, add the stable vault key everywhere
237
- and read/migrate every existing row while the old A2A material is still
238
- available.
230
+ - Workspace-shared `app_secrets` prefer
231
+ `WORKSPACE_SECRETS_ENCRYPTION_KEY`, then the legacy shared
232
+ `SECRETS_ENCRYPTION_KEY`, then a purpose-derived key from `A2A_SECRET`.
233
+ Better Auth and app-scoped keys remain legacy read candidates; a successful
234
+ legacy decrypt is compare-and-swap migrated to the preferred shared key
235
+ without changing the row timestamp.
236
+ - Set the same stable `WORKSPACE_SECRETS_ENCRYPTION_KEY` in every app that
237
+ reads a shared vault. It is intentionally separate from app-local OAuth
238
+ encryption. If the vault still relies on `A2A_SECRET`, rotating A2A material
239
+ also rotates its encryption key. Add the stable vault key everywhere and
240
+ read/migrate existing rows before rotating A2A.
241
+ - To rotate the dedicated workspace key itself, deploy the new value together
242
+ with `WORKSPACE_SECRETS_ENCRYPTION_KEY_PREVIOUS=<old value>`, let reads
243
+ migrate ciphertext, then remove the previous key after the migration window.
239
244
  - If no configured key material exists, development uses a machine-local
240
245
  fallback and logs a one-time warning. Production fails closed.
241
246