@agent-native/core 0.125.0 → 0.127.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +79 -0
- package/corpus/core/docs/content/external-agents-catalog.mdx +14 -11
- package/corpus/core/docs/content/mcp-protocol.mdx +9 -4
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/index.ts +2 -0
- package/corpus/core/src/agent/production-agent.ts +6 -1
- package/corpus/core/src/agent/run-manager.ts +37 -0
- package/corpus/core/src/agent/run-store.ts +18 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +75 -43
- package/corpus/core/src/client/agent-chat.ts +19 -1
- package/corpus/core/src/client/chat/tool-call-display.tsx +25 -0
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +23 -0
- package/corpus/core/src/client/settings/AgentsSection.tsx +565 -71
- package/corpus/core/src/client/settings/SecretsSection.tsx +71 -36
- package/corpus/core/src/client/use-chat-models.ts +54 -37
- package/corpus/core/src/localization/default-messages.ts +11 -0
- package/corpus/core/src/mcp/ask-app-task-handle.ts +183 -0
- package/corpus/core/src/mcp/builtin-tools.ts +146 -34
- package/corpus/core/src/server/agent-capabilities.ts +8 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +17 -0
- package/corpus/core/src/server/agent-discovery.ts +1 -1
- package/corpus/core/src/server/agent-peer-probe.ts +133 -0
- package/corpus/core/src/server/core-routes-plugin.ts +67 -0
- package/corpus/core/src/server/email-template.ts +13 -0
- package/corpus/core/src/server/email.ts +40 -4
- package/corpus/core/src/shared/mcp-embed-headers.ts +4 -0
- package/corpus/core/src/sharing/actions/share-resource.ts +55 -5
- package/corpus/core/src/sharing/registry.ts +41 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +159 -119
- package/corpus/templates/assets/actions/edit-image.ts +31 -18
- package/corpus/templates/assets/actions/refine-image.ts +43 -29
- package/corpus/templates/assets/actions/restyle-image.ts +30 -19
- package/corpus/templates/assets/actions/variant-slots.ts +26 -0
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +85 -17
- package/corpus/templates/clips/changelog/2026-07-27-share-notification-emails-now-include-a-clickable-recording-.md +6 -0
- package/corpus/templates/clips/server/db/index.ts +28 -6
- package/corpus/templates/clips/server/lib/share-email-hero.ts +105 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +100 -12
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +17 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +169 -22
- package/corpus/templates/design/app/hooks/use-question-flow.ts +21 -1
- package/corpus/templates/design/changelog/2026-07-28-the-model-you-pick-when-starting-a-new-design-is-now-used-fo.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-28-pending-apps-are-hidden-by-default-and-app-ownership-details.md +6 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +5 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +5 -0
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +31 -8
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +15 -0
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +78 -8
- package/corpus/templates/slides/app/components/presentation/PresenterView.tsx +179 -0
- package/corpus/templates/slides/app/components/presentation/present-channel.ts +15 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +10 -1
- package/corpus/templates/slides/app/lib/export-google-slides-client.ts +67 -0
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +16 -3
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +11 -0
- package/corpus/templates/slides/app/pages/Presentation.tsx +11 -3
- package/corpus/templates/slides/changelog/2026-07-28-export-to-google-slides-now-creates-the-deck-directly-in-you.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-28-opening-a-presentation-link-directly-no-longer-bounces-back-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-28-presenter-view-open-a-second-window-while-presenting-to-see-.md +6 -0
- package/corpus/templates/slides/server/routes/api/exports/google-slides.post.ts +90 -0
- package/corpus/toolkit/CHANGELOG.md +6 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/composer/TiptapComposer.tsx +143 -111
- package/corpus/toolkit/src/composer/runtime-adapters.tsx +2 -0
- package/dist/a2a/index.d.ts +2 -0
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -0
- package/dist/a2a/index.js.map +1 -1
- package/dist/agent/production-agent.d.ts +2 -2
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +6 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +11 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +34 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +8 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +16 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +60 -31
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts +6 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +13 -1
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +14 -0
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts +6 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +16 -0
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/settings/AgentsSection.d.ts.map +1 -1
- package/dist/client/settings/AgentsSection.js +250 -30
- package/dist/client/settings/AgentsSection.js.map +1 -1
- package/dist/client/settings/SecretsSection.d.ts.map +1 -1
- package/dist/client/settings/SecretsSection.js +16 -2
- package/dist/client/settings/SecretsSection.js.map +1 -1
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +46 -27
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +9 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +9 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/ask-app-task-handle.d.ts +25 -0
- package/dist/mcp/ask-app-task-handle.d.ts.map +1 -0
- package/dist/mcp/ask-app-task-handle.js +136 -0
- package/dist/mcp/ask-app-task-handle.js.map +1 -0
- package/dist/mcp/builtin-tools.d.ts +3 -3
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +115 -38
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +6 -6
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-capabilities.d.ts +7 -1
- package/dist/server/agent-capabilities.d.ts.map +1 -1
- package/dist/server/agent-capabilities.js +1 -0
- package/dist/server/agent-capabilities.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +7 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +16 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-discovery.d.ts +1 -0
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js +1 -1
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/agent-peer-probe.d.ts +37 -0
- package/dist/server/agent-peer-probe.d.ts.map +1 -0
- package/dist/server/agent-peer-probe.js +90 -0
- package/dist/server/agent-peer-probe.js.map +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +53 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/email-template.d.ts +6 -0
- package/dist/server/email-template.d.ts.map +1 -1
- package/dist/server/email-template.js +6 -0
- package/dist/server/email-template.js.map +1 -1
- package/dist/server/email.d.ts +7 -0
- package/dist/server/email.d.ts.map +1 -1
- package/dist/server/email.js +31 -6
- package/dist/server/email.js.map +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +1 -0
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +4 -0
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/sharing/actions/share-resource.d.ts.map +1 -1
- package/dist/sharing/actions/share-resource.js +49 -5
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/sharing/registry.d.ts +40 -1
- package/dist/sharing/registry.d.ts.map +1 -1
- package/dist/sharing/registry.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +159 -119
- package/docs/content/external-agents-catalog.mdx +14 -11
- package/docs/content/mcp-protocol.mdx +9 -4
- package/package.json +2 -2
- package/src/a2a/index.ts +2 -0
- package/src/agent/production-agent.ts +6 -1
- package/src/agent/run-manager.ts +37 -0
- package/src/agent/run-store.ts +18 -0
- package/src/client/MultiTabAssistantChat.tsx +75 -43
- package/src/client/agent-chat.ts +19 -1
- package/src/client/chat/tool-call-display.tsx +25 -0
- package/src/client/resources/mcp-integration-catalog.ts +23 -0
- package/src/client/settings/AgentsSection.tsx +565 -71
- package/src/client/settings/SecretsSection.tsx +71 -36
- package/src/client/use-chat-models.ts +54 -37
- package/src/localization/default-messages.ts +11 -0
- package/src/mcp/ask-app-task-handle.ts +183 -0
- package/src/mcp/builtin-tools.ts +146 -34
- package/src/server/agent-capabilities.ts +8 -1
- package/src/server/agent-chat-plugin.ts +17 -0
- package/src/server/agent-discovery.ts +1 -1
- package/src/server/agent-peer-probe.ts +133 -0
- package/src/server/core-routes-plugin.ts +67 -0
- package/src/server/email-template.ts +13 -0
- package/src/server/email.ts +40 -4
- package/src/shared/mcp-embed-headers.ts +4 -0
- package/src/sharing/actions/share-resource.ts +55 -5
- package/src/sharing/registry.ts +41 -1
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +159 -119
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask-app-task-handle.js","sourceRoot":"","sources":["../../src/mcp/ask-app-task-handle.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHmac } from \"node:crypto\";\n\nimport { CompactEncrypt, compactDecrypt } from \"jose\";\n\nimport { getAuthSecret } from \"../server/better-auth-instance.js\";\n\nconst HANDLE_VERSION = 1;\nconst HANDLE_TTL_SECONDS = 60 * 60;\nconst INVALID_HANDLE_ERROR = \"Invalid or expired ask_app task handle.\";\n\nexport interface AskAppTaskHandleRoute {\n app: string;\n origin: string;\n routedVia: \"local\" | \"a2a\";\n requestOrigin?: string;\n}\n\ninterface AskAppTaskHandleClaims {\n version: number;\n issuerApp: string;\n issuerAudience: string;\n organization: string;\n subject: string;\n route: AskAppTaskHandleRoute;\n taskId: string;\n expiresAt: number;\n}\n\nfunction normalizedIdentity(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction normalizedAudience(value: string): string | null {\n const url = validHttpUrl(value);\n if (!url || url.search || url.hash) return null;\n const pathname = url.pathname.replace(/\\/+$/, \"\");\n return `${url.origin}${pathname}`;\n}\n\nfunction rootSecrets(): string[] {\n const a2a = process.env.A2A_SECRET?.trim();\n const auth = getAuthSecret();\n return [...new Set([a2a, auth].filter((value): value is string => !!value))];\n}\n\nfunction handleKey(rootSecret: string): Uint8Array {\n return createHmac(\"sha256\", rootSecret)\n .update(\"agent-native:ask-app-task-handle:v1\")\n .digest();\n}\n\nfunction validHttpUrl(value: string): URL | null {\n try {\n const url = new URL(value);\n if (![\"http:\", \"https:\"].includes(url.protocol)) return null;\n if (url.username || url.password) return null;\n return url;\n } catch {\n return null;\n }\n}\n\nfunction validRoute(value: unknown): value is AskAppTaskHandleRoute {\n if (!value || typeof value !== \"object\") return false;\n const route = value as Partial<AskAppTaskHandleRoute>;\n if (typeof route.app !== \"string\" || !route.app.trim()) return false;\n if (route.routedVia !== \"local\" && route.routedVia !== \"a2a\") return false;\n if (typeof route.origin !== \"string\") return false;\n const endpoint = validHttpUrl(route.origin);\n if (!endpoint) return false;\n if (route.requestOrigin == null) return true;\n if (typeof route.requestOrigin !== \"string\") return false;\n const requestOrigin = validHttpUrl(route.requestOrigin);\n return requestOrigin?.origin === endpoint.origin;\n}\n\nfunction invalidHandle(): Error {\n return new Error(INVALID_HANDLE_ERROR);\n}\n\nexport async function signAskAppTaskHandle(params: {\n issuerApp: string;\n issuerAudience: string;\n organization: string;\n subject: string;\n route: AskAppTaskHandleRoute;\n taskId: string;\n expiresInSeconds?: number;\n}): Promise<string> {\n const issuerApp = normalizedIdentity(params.issuerApp);\n const issuerAudience = normalizedAudience(params.issuerAudience);\n const organization = normalizedIdentity(params.organization);\n const subject = normalizedIdentity(params.subject);\n const taskId = params.taskId.trim();\n if (\n !issuerApp ||\n !issuerAudience ||\n !subject ||\n !taskId ||\n !validRoute(params.route)\n ) {\n throw invalidHandle();\n }\n\n const claims: AskAppTaskHandleClaims = {\n version: HANDLE_VERSION,\n issuerApp,\n issuerAudience,\n organization,\n subject,\n route: {\n ...params.route,\n app: normalizedIdentity(params.route.app),\n },\n taskId,\n expiresAt:\n Math.floor(Date.now() / 1000) +\n (params.expiresInSeconds ?? HANDLE_TTL_SECONDS),\n };\n const payload = new TextEncoder().encode(JSON.stringify(claims));\n return new CompactEncrypt(payload)\n .setProtectedHeader({\n alg: \"dir\",\n enc: \"A256GCM\",\n typ: \"agent-native-ask-app-task-handle\",\n })\n .encrypt(handleKey(rootSecrets()[0]));\n}\n\nexport async function verifyAskAppTaskHandle(\n handle: string,\n expected: {\n issuerApp: string;\n issuerAudience: string;\n organization: string;\n subject: string;\n },\n): Promise<{ route: AskAppTaskHandleRoute; taskId: string }> {\n const issuerApp = normalizedIdentity(expected.issuerApp);\n const issuerAudience = normalizedAudience(expected.issuerAudience);\n const organization = normalizedIdentity(expected.organization);\n const subject = normalizedIdentity(expected.subject);\n if (!handle.trim() || !issuerApp || !issuerAudience || !subject) {\n throw invalidHandle();\n }\n\n for (const rootSecret of rootSecrets()) {\n try {\n const { plaintext, protectedHeader } = await compactDecrypt(\n handle,\n handleKey(rootSecret),\n );\n if (\n protectedHeader.alg !== \"dir\" ||\n protectedHeader.enc !== \"A256GCM\" ||\n protectedHeader.typ !== \"agent-native-ask-app-task-handle\"\n ) {\n continue;\n }\n const claims = JSON.parse(\n new TextDecoder().decode(plaintext),\n ) as Partial<AskAppTaskHandleClaims>;\n if (\n claims.version !== HANDLE_VERSION ||\n claims.issuerApp !== issuerApp ||\n claims.issuerAudience !== issuerAudience ||\n claims.organization !== organization ||\n claims.subject !== subject ||\n typeof claims.taskId !== \"string\" ||\n !claims.taskId ||\n typeof claims.expiresAt !== \"number\" ||\n claims.expiresAt <= Math.floor(Date.now() / 1000) ||\n !validRoute(claims.route)\n ) {\n continue;\n }\n return { route: claims.route, taskId: claims.taskId };\n } catch {\n // All handle failures are deliberately indistinguishable to callers.\n }\n }\n throw invalidHandle();\n}\n"]}
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
* `open_app` / `create_workspace_app` return an **absolute** URL on the
|
|
22
22
|
* *target* app's origin when it differs from this app (so a workspace link
|
|
23
23
|
* lands in the right app), and a relative path for the same app / standalone.
|
|
24
|
-
* `ask_app` routes
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* `ask_app` routes a known *different* workspace app over A2A and reports
|
|
25
|
+
* `routedVia: "a2a"`; unknown cross-app targets fail closed instead of running
|
|
26
|
+
* on the current app. Same-app requests report `routedVia: "local"`.
|
|
27
27
|
* | `list_templates` | none | `{ templates: [...] }` (allow-list only) |
|
|
28
28
|
*
|
|
29
29
|
* Node-only at call time (workspace resolution + scaffolding use `fs`), but
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/builtin-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"builtin-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/builtin-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAahE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AA6DnD,KAAK,iBAAiB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAm9ChE;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,WAAW,CAAC,EAAE,iBAAiB,GAC9B,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAU7B"}
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
* `open_app` / `create_workspace_app` return an **absolute** URL on the
|
|
22
22
|
* *target* app's origin when it differs from this app (so a workspace link
|
|
23
23
|
* lands in the right app), and a relative path for the same app / standalone.
|
|
24
|
-
* `ask_app` routes
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* `ask_app` routes a known *different* workspace app over A2A and reports
|
|
25
|
+
* `routedVia: "a2a"`; unknown cross-app targets fail closed instead of running
|
|
26
|
+
* on the current app. Same-app requests report `routedVia: "local"`.
|
|
27
27
|
* | `list_templates` | none | `{ templates: [...] }` (allow-list only) |
|
|
28
28
|
*
|
|
29
29
|
* Node-only at call time (workspace resolution + scaffolding use `fs`), but
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
*/
|
|
33
33
|
import { getConfiguredAppBasePath } from "../server/app-base-path.js";
|
|
34
34
|
import { buildDeepLink } from "../server/deep-link.js";
|
|
35
|
+
import { getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
|
|
35
36
|
import { MCP_APP_CHAT_BRIDGE_QUERY_PARAM } from "../shared/embed-auth.js";
|
|
37
|
+
import { signAskAppTaskHandle, verifyAskAppTaskHandle, } from "./ask-app-task-handle.js";
|
|
36
38
|
import { embedApp } from "./embed-app.js";
|
|
37
39
|
import { fetchOrgApps } from "./org-directory.js";
|
|
38
40
|
/**
|
|
@@ -145,6 +147,26 @@ function selfA2AEndpointUrl(requestMeta) {
|
|
|
145
147
|
const basePath = requestMeta?.basePath || getConfiguredAppBasePath();
|
|
146
148
|
return agentNativeA2AEndpoint(`${origin}${basePath}`);
|
|
147
149
|
}
|
|
150
|
+
function askAppIssuerAudience(requestMeta) {
|
|
151
|
+
const origin = requestMeta?.origin?.replace(/\/+$/, "");
|
|
152
|
+
if (!origin)
|
|
153
|
+
return null;
|
|
154
|
+
try {
|
|
155
|
+
const originUrl = new URL(origin);
|
|
156
|
+
if (!["http:", "https:"].includes(originUrl.protocol) ||
|
|
157
|
+
originUrl.username ||
|
|
158
|
+
originUrl.password) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const basePath = requestMeta?.basePath || getConfiguredAppBasePath();
|
|
162
|
+
const audience = new URL(basePath || "/", `${originUrl.origin}/`);
|
|
163
|
+
const pathname = audience.pathname.replace(/\/+$/, "");
|
|
164
|
+
return `${audience.origin}${pathname}`;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
148
170
|
function boundedAskAppWaitMs(raw) {
|
|
149
171
|
if (raw == null || raw === "")
|
|
150
172
|
return ASK_APP_DEFAULT_INLINE_WAIT_MS;
|
|
@@ -169,13 +191,14 @@ function taskText(task) {
|
|
|
169
191
|
.join("\n")
|
|
170
192
|
.trim() ?? "");
|
|
171
193
|
}
|
|
172
|
-
function askAppTaskResult(route, task) {
|
|
194
|
+
function askAppTaskResult(route, task, taskHandle) {
|
|
173
195
|
const status = taskState(task);
|
|
174
196
|
const response = taskText(task);
|
|
175
197
|
const base = {
|
|
176
198
|
app: route.app,
|
|
177
199
|
routedVia: route.routedVia,
|
|
178
200
|
taskId: task.id,
|
|
201
|
+
...(taskHandle ? { taskHandle } : {}),
|
|
179
202
|
status,
|
|
180
203
|
...(route.note ? { note: route.note } : {}),
|
|
181
204
|
};
|
|
@@ -206,10 +229,16 @@ function askAppTaskResult(route, task) {
|
|
|
206
229
|
pollAfterMs: ASK_APP_POLL_INTERVAL_MS,
|
|
207
230
|
poll: {
|
|
208
231
|
tool: "ask_app_status",
|
|
209
|
-
arguments: {
|
|
232
|
+
arguments: {
|
|
233
|
+
app: route.app,
|
|
234
|
+
taskId: task.id,
|
|
235
|
+
...(taskHandle ? { taskHandle } : {}),
|
|
236
|
+
},
|
|
210
237
|
},
|
|
211
238
|
message: `ask_app is still ${status}. Call ask_app_status with ` +
|
|
212
|
-
|
|
239
|
+
(taskHandle
|
|
240
|
+
? "the returned taskHandle to retrieve the final response."
|
|
241
|
+
: `taskId "${task.id}" to retrieve the final response.`),
|
|
213
242
|
};
|
|
214
243
|
}
|
|
215
244
|
/**
|
|
@@ -311,7 +340,7 @@ async function waitForA2ATask(client, initialTask, deadline) {
|
|
|
311
340
|
}
|
|
312
341
|
return current;
|
|
313
342
|
}
|
|
314
|
-
async function submitAskAppA2ATask(route, message, maxWaitMs, approvedActions) {
|
|
343
|
+
async function submitAskAppA2ATask(route, issuerApp, issuerAudience, message, maxWaitMs, approvedActions) {
|
|
315
344
|
const deadline = maxWaitMs > 0 ? Date.now() + maxWaitMs : undefined;
|
|
316
345
|
const { client, metadata } = await createA2AClientForAskApp(route.origin, route.requestOrigin, deadline);
|
|
317
346
|
const task = await client.send({
|
|
@@ -323,16 +352,25 @@ async function submitAskAppA2ATask(route, message, maxWaitMs, approvedActions) {
|
|
|
323
352
|
...(approvedActions?.length ? { approvedActions } : {}),
|
|
324
353
|
});
|
|
325
354
|
const finalOrRunning = await waitForA2ATask(client, task, deadline);
|
|
326
|
-
|
|
355
|
+
const subject = typeof metadata.userEmail === "string" ? metadata.userEmail : "anonymous";
|
|
356
|
+
const taskHandle = await signAskAppTaskHandle({
|
|
357
|
+
issuerApp,
|
|
358
|
+
issuerAudience,
|
|
359
|
+
organization: getRequestOrgId() ?? "",
|
|
360
|
+
subject,
|
|
361
|
+
route,
|
|
362
|
+
taskId: task.id,
|
|
363
|
+
});
|
|
364
|
+
return askAppTaskResult(route, finalOrRunning, taskHandle);
|
|
327
365
|
}
|
|
328
|
-
async function fetchAskAppA2ATask(route, taskId) {
|
|
366
|
+
async function fetchAskAppA2ATask(route, taskId, taskHandle) {
|
|
329
367
|
const { client } = await createA2AClientForAskApp(route.origin);
|
|
330
368
|
const maxAttempts = ASK_APP_STATUS_RETRY_DELAYS_MS.length + 1;
|
|
331
369
|
for (let attempt = 0; attempt <= ASK_APP_STATUS_RETRY_DELAYS_MS.length; attempt++) {
|
|
332
370
|
const startedAt = Date.now();
|
|
333
371
|
try {
|
|
334
372
|
const task = await client.getTask(taskId);
|
|
335
|
-
return askAppTaskResult(route, task);
|
|
373
|
+
return askAppTaskResult(route, task, taskHandle);
|
|
336
374
|
}
|
|
337
375
|
catch (err) {
|
|
338
376
|
const delayMs = ASK_APP_STATUS_RETRY_DELAYS_MS[attempt];
|
|
@@ -358,7 +396,7 @@ async function fetchAskAppA2ATask(route, taskId) {
|
|
|
358
396
|
throw err;
|
|
359
397
|
}
|
|
360
398
|
if (delayMs == null) {
|
|
361
|
-
return askAppStatusReadUnavailableResult(route, taskId, errorCategory, maxAttempts);
|
|
399
|
+
return askAppStatusReadUnavailableResult(route, taskId, errorCategory, maxAttempts, taskHandle);
|
|
362
400
|
}
|
|
363
401
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
364
402
|
}
|
|
@@ -405,11 +443,12 @@ function askAppStatusOriginHost(origin) {
|
|
|
405
443
|
return "unknown";
|
|
406
444
|
}
|
|
407
445
|
}
|
|
408
|
-
function askAppStatusReadUnavailableResult(route, taskId, errorCategory, attempts) {
|
|
446
|
+
function askAppStatusReadUnavailableResult(route, taskId, errorCategory, attempts, taskHandle) {
|
|
409
447
|
return {
|
|
410
448
|
app: route.app,
|
|
411
449
|
routedVia: route.routedVia,
|
|
412
450
|
taskId,
|
|
451
|
+
...(taskHandle ? { taskHandle } : {}),
|
|
413
452
|
status: "unknown",
|
|
414
453
|
statusRead: "unavailable",
|
|
415
454
|
retryable: true,
|
|
@@ -418,11 +457,17 @@ function askAppStatusReadUnavailableResult(route, taskId, errorCategory, attempt
|
|
|
418
457
|
pollAfterMs: ASK_APP_POLL_INTERVAL_MS,
|
|
419
458
|
poll: {
|
|
420
459
|
tool: "ask_app_status",
|
|
421
|
-
arguments: {
|
|
460
|
+
arguments: {
|
|
461
|
+
app: route.app,
|
|
462
|
+
taskId,
|
|
463
|
+
...(taskHandle ? { taskHandle } : {}),
|
|
464
|
+
},
|
|
422
465
|
},
|
|
423
466
|
message: "The durable ask_app task status could not be read after bounded retries. " +
|
|
424
467
|
"The task may still be running or completed. Retry ask_app_status " +
|
|
425
|
-
|
|
468
|
+
(taskHandle
|
|
469
|
+
? "with the same taskHandle; do not resubmit ask_app."
|
|
470
|
+
: "with the same app and taskId; do not resubmit ask_app."),
|
|
426
471
|
};
|
|
427
472
|
}
|
|
428
473
|
/**
|
|
@@ -487,10 +532,13 @@ function listAppsTool(config, requestMeta) {
|
|
|
487
532
|
livePort = 0;
|
|
488
533
|
}
|
|
489
534
|
}
|
|
490
|
-
const selfId = (config
|
|
535
|
+
const selfId = currentAppId(config);
|
|
491
536
|
const isSelf = (id) => !!liveOrigin &&
|
|
492
537
|
(!ws.isWorkspace || (!!selfId && id.toLowerCase() === selfId));
|
|
493
|
-
const
|
|
538
|
+
const resolvedApps = ws.isWorkspace
|
|
539
|
+
? ws.apps
|
|
540
|
+
: ws.apps.map((app) => ({ ...app, id: selfId, name: config.name }));
|
|
541
|
+
const apps = resolvedApps.map((a) => isSelf(a.id)
|
|
494
542
|
? {
|
|
495
543
|
id: a.id,
|
|
496
544
|
url: liveOrigin,
|
|
@@ -778,12 +826,15 @@ function createEmbedSessionTool(requestMeta) {
|
|
|
778
826
|
*/
|
|
779
827
|
async function routeAskOverA2A(origin, id, message, options) {
|
|
780
828
|
if (options?.durable) {
|
|
829
|
+
if (!options.issuerApp || !options.issuerAudience) {
|
|
830
|
+
throw new Error("ask_app durable routing requires an issuer app id and audience.");
|
|
831
|
+
}
|
|
781
832
|
return submitAskAppA2ATask({
|
|
782
833
|
app: id,
|
|
783
834
|
origin: agentNativeA2AEndpoint(origin),
|
|
784
835
|
routedVia: "a2a",
|
|
785
836
|
requestOrigin: options.requestOrigin ?? origin,
|
|
786
|
-
}, message, options.maxWaitMs ?? ASK_APP_DEFAULT_INLINE_WAIT_MS, options.approvedActions);
|
|
837
|
+
}, options.issuerApp, options.issuerAudience, message, options.maxWaitMs ?? ASK_APP_DEFAULT_INLINE_WAIT_MS, options.approvedActions);
|
|
787
838
|
}
|
|
788
839
|
const { callAgent } = await import("../a2a/client.js");
|
|
789
840
|
const { resolveA2ACallerAuth } = await import("../a2a/caller-auth.js");
|
|
@@ -854,8 +905,8 @@ function askAppTool(config, requestMeta) {
|
|
|
854
905
|
"param is optional (defaults to this app). When 'app' names a " +
|
|
855
906
|
"different workspace app it is routed there over A2A; the result's " +
|
|
856
907
|
"'routedVia' field reports whether it ran cross-app or locally. " +
|
|
857
|
-
"On hosted MCP, long tasks may return a durable
|
|
858
|
-
"final response;
|
|
908
|
+
"On hosted MCP, long tasks may return a durable taskHandle instead of " +
|
|
909
|
+
"a final response; pass that handle to ask_app_status until completed.", {
|
|
859
910
|
app: {
|
|
860
911
|
type: "string",
|
|
861
912
|
description: "App id to route to (optional in a single-app project)",
|
|
@@ -866,11 +917,11 @@ function askAppTool(config, requestMeta) {
|
|
|
866
917
|
},
|
|
867
918
|
async: {
|
|
868
919
|
type: "boolean",
|
|
869
|
-
description: "When true, start a durable task and return immediately with a taskId.",
|
|
920
|
+
description: "When true, start a durable task and return immediately with a taskHandle and legacy taskId.",
|
|
870
921
|
},
|
|
871
922
|
maxWaitMs: {
|
|
872
923
|
type: "number",
|
|
873
|
-
description: "Maximum time to wait inline before returning a
|
|
924
|
+
description: "Maximum time to wait inline before returning a taskHandle. Hosted MCP clamps this to 25000ms.",
|
|
874
925
|
},
|
|
875
926
|
approvedActions: {
|
|
876
927
|
type: "array",
|
|
@@ -892,6 +943,10 @@ function askAppTool(config, requestMeta) {
|
|
|
892
943
|
const requestedApp = String(args.app ?? "").trim();
|
|
893
944
|
const selfId = currentAppId(config);
|
|
894
945
|
const useDurableA2A = Boolean(requestMeta?.origin);
|
|
946
|
+
const issuerAudience = askAppIssuerAudience(requestMeta);
|
|
947
|
+
if (useDurableA2A && !issuerAudience) {
|
|
948
|
+
throw new Error("ask_app durable routing requires a valid HTTP(S) issuer audience.");
|
|
949
|
+
}
|
|
895
950
|
const maxWaitMs = isExplicitAsyncAsk(args.async)
|
|
896
951
|
? 0
|
|
897
952
|
: boundedAskAppWaitMs(args.maxWaitMs);
|
|
@@ -907,6 +962,8 @@ function askAppTool(config, requestMeta) {
|
|
|
907
962
|
try {
|
|
908
963
|
return await routeAskOverA2A(targetApp.origin, targetApp.id, message, {
|
|
909
964
|
durable: useDurableA2A,
|
|
965
|
+
issuerApp: selfId,
|
|
966
|
+
issuerAudience: issuerAudience ?? undefined,
|
|
910
967
|
maxWaitMs,
|
|
911
968
|
requestOrigin: targetApp.origin,
|
|
912
969
|
approvedActions,
|
|
@@ -931,6 +988,8 @@ function askAppTool(config, requestMeta) {
|
|
|
931
988
|
try {
|
|
932
989
|
return await routeAskOverA2A(dirMatch.a2aUrl, dirMatch.id, message, {
|
|
933
990
|
durable: useDurableA2A,
|
|
991
|
+
issuerApp: selfId,
|
|
992
|
+
issuerAudience: issuerAudience ?? undefined,
|
|
934
993
|
maxWaitMs,
|
|
935
994
|
requestOrigin: dirMatch.url,
|
|
936
995
|
approvedActions,
|
|
@@ -942,19 +1001,16 @@ function askAppTool(config, requestMeta) {
|
|
|
942
1001
|
}
|
|
943
1002
|
}
|
|
944
1003
|
}
|
|
945
|
-
|
|
1004
|
+
if (requestedApp && requestedApp.toLowerCase() !== selfId) {
|
|
1005
|
+
throw new Error(`No reachable ask_app route for app "${requestedApp}". ` +
|
|
1006
|
+
"Call list_apps and retry with an available app id.");
|
|
1007
|
+
}
|
|
1008
|
+
// Same app (or no target): answer locally with this
|
|
946
1009
|
// app's own ask-agent handler — the same entry point the HTTP MCP mount
|
|
947
1010
|
// + A2A use, so there is no second agent runner.
|
|
948
1011
|
if (!config.askAgent) {
|
|
949
1012
|
throw new Error("This app does not expose an agent (no ask-agent handler).");
|
|
950
1013
|
}
|
|
951
|
-
// If the caller named an app we couldn't route to (unknown id, or no
|
|
952
|
-
// workspace), say so honestly instead of claiming we reached it.
|
|
953
|
-
const unresolved = !!requestedApp && requestedApp.toLowerCase() !== selfId;
|
|
954
|
-
const note = unresolved
|
|
955
|
-
? `Requested app "${requestedApp}" is not a reachable workspace ` +
|
|
956
|
-
`app; answered with this app ("${selfId}") instead.`
|
|
957
|
-
: undefined;
|
|
958
1014
|
// Hosted MCP cannot safely keep a JSON request/response open for a full
|
|
959
1015
|
// agent loop: serverless gateways can return an inactivity 504 before
|
|
960
1016
|
// the result body exists. When we know the running app origin, submit the
|
|
@@ -967,8 +1023,7 @@ function askAppTool(config, requestMeta) {
|
|
|
967
1023
|
origin: localA2AEndpointUrl,
|
|
968
1024
|
routedVia: "local",
|
|
969
1025
|
requestOrigin: requestMeta?.origin,
|
|
970
|
-
|
|
971
|
-
}, message, maxWaitMs, approvedActions);
|
|
1026
|
+
}, selfId, issuerAudience ?? "", message, maxWaitMs, approvedActions);
|
|
972
1027
|
}
|
|
973
1028
|
// No derivable app origin at all (e.g. stdio / no request context) —
|
|
974
1029
|
// there is no `/_agent-native/a2a` endpoint to submit a durable task
|
|
@@ -984,7 +1039,6 @@ function askAppTool(config, requestMeta) {
|
|
|
984
1039
|
return {
|
|
985
1040
|
app: selfId,
|
|
986
1041
|
routedVia: "local",
|
|
987
|
-
...(note ? { note } : {}),
|
|
988
1042
|
response: inline.response || "(no response)",
|
|
989
1043
|
};
|
|
990
1044
|
}
|
|
@@ -993,7 +1047,7 @@ function askAppTool(config, requestMeta) {
|
|
|
993
1047
|
// same way the old unbounded `await config.askAgent(message)` did.
|
|
994
1048
|
throw new Error(inline.error || "ask_app task failed.");
|
|
995
1049
|
}
|
|
996
|
-
return askAppInlineTaskResult(selfId, inline.taskId, inline
|
|
1050
|
+
return askAppInlineTaskResult(selfId, inline.taskId, inline);
|
|
997
1051
|
},
|
|
998
1052
|
};
|
|
999
1053
|
}
|
|
@@ -1010,15 +1064,38 @@ function askAppStatusTool(config, requestMeta) {
|
|
|
1010
1064
|
},
|
|
1011
1065
|
taskId: {
|
|
1012
1066
|
type: "string",
|
|
1013
|
-
description: "
|
|
1067
|
+
description: "Legacy durable task id returned by ask_app. Use taskHandle when present.",
|
|
1014
1068
|
},
|
|
1015
|
-
|
|
1069
|
+
taskHandle: {
|
|
1070
|
+
type: "string",
|
|
1071
|
+
description: "Opaque task handle returned by ask_app. It preserves the original route across cold starts and discovery changes.",
|
|
1072
|
+
},
|
|
1073
|
+
}),
|
|
1016
1074
|
readOnly: true,
|
|
1017
1075
|
parallelSafe: true,
|
|
1018
1076
|
run: async (args) => {
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1077
|
+
const suppliedTaskId = String(args.taskId ?? "").trim();
|
|
1078
|
+
const taskHandle = String(args.taskHandle ?? "").trim();
|
|
1079
|
+
if (!taskHandle && !suppliedTaskId) {
|
|
1080
|
+
throw new Error("ask_app_status requires 'taskHandle' or 'taskId'.");
|
|
1081
|
+
}
|
|
1082
|
+
if (taskHandle) {
|
|
1083
|
+
const verified = await verifyAskAppTaskHandle(taskHandle, {
|
|
1084
|
+
issuerApp: currentAppId(config),
|
|
1085
|
+
issuerAudience: askAppIssuerAudience(requestMeta) ?? "",
|
|
1086
|
+
organization: getRequestOrgId() ?? "",
|
|
1087
|
+
subject: getRequestUserEmail() ?? "anonymous",
|
|
1088
|
+
});
|
|
1089
|
+
const suppliedApp = String(args.app ?? "")
|
|
1090
|
+
.trim()
|
|
1091
|
+
.toLowerCase();
|
|
1092
|
+
if ((suppliedTaskId && suppliedTaskId !== verified.taskId) ||
|
|
1093
|
+
(suppliedApp && suppliedApp !== verified.route.app.toLowerCase())) {
|
|
1094
|
+
throw new Error("Invalid or expired ask_app task handle.");
|
|
1095
|
+
}
|
|
1096
|
+
return fetchAskAppA2ATask(verified.route, verified.taskId, taskHandle);
|
|
1097
|
+
}
|
|
1098
|
+
const taskId = suppliedTaskId;
|
|
1022
1099
|
// The no-derivable-origin ask_app fallback tracks its tasks in a
|
|
1023
1100
|
// process-local map, not the durable A2A store. Check it FIRST —
|
|
1024
1101
|
// before any origin requirement — so a taskId minted by that fallback
|