@agent-native/core 0.145.3 → 0.145.4
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 +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +10 -8
- package/corpus/templates/assets/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +22 -1
- package/corpus/templates/mail/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/plan/server/lib/plan-framework-tools.ts +11 -0
- package/corpus/templates/plan/server/plugins/00-mcp.ts +25 -68
- package/corpus/templates/plan/server/plugins/agent-chat.ts +8 -2
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/framework-tools.d.ts +33 -1
- package/dist/framework-tools.js +88 -4
- package/dist/mcp/build-server.d.ts +15 -0
- package/dist/mcp/build-server.js +94 -30
- package/dist/mcp/oauth-client-metadata.js +6 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-discovery.d.ts +3 -18
- package/dist/server/action-discovery.js +9 -65
- package/dist/server/agent-chat/action-filters-a2a.d.ts +14 -2
- package/dist/server/agent-chat/action-filters-a2a.js +1 -1
- package/dist/server/agent-chat/mcp-options.d.ts +106 -0
- package/dist/server/agent-chat/mcp-options.js +50 -0
- package/dist/server/agent-chat/plugin-options.d.ts +17 -26
- package/dist/server/agent-chat-plugin.js +21 -11
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +7 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -170,12 +170,16 @@ function validateClientMetadataDocument(clientId, value) {
|
|
|
170
170
|
if (tokenEndpointAuthMethod !== "none") {
|
|
171
171
|
throw new Error("Only public Client ID Metadata clients are supported");
|
|
172
172
|
}
|
|
173
|
+
// A grant type we do not support is not a reason to reject the document —
|
|
174
|
+
// clients advertise grants they use elsewhere (Claude.ai's CIMD document
|
|
175
|
+
// lists "urn:ietf:params:oauth:grant-type:jwt-bearer" next to the two we
|
|
176
|
+
// support). The token endpoint independently honors only
|
|
177
|
+
// "authorization_code"/"refresh_token" no matter what this list says.
|
|
173
178
|
const grantTypes = parseStringArray(document.grant_types);
|
|
174
179
|
if ((document.grant_types !== undefined &&
|
|
175
180
|
(!Array.isArray(document.grant_types) ||
|
|
176
181
|
grantTypes.length !== document.grant_types.length)) ||
|
|
177
|
-
grantTypes.length > 10
|
|
178
|
-
!grantTypes.every((grant) => grant === "authorization_code" || grant === "refresh_token")) {
|
|
182
|
+
grantTypes.length > 10) {
|
|
179
183
|
throw new Error("Client metadata document grant_types are unsupported");
|
|
180
184
|
}
|
|
181
185
|
const responseTypes = parseStringArray(document.response_types);
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
14
14
|
count: number;
|
|
15
15
|
updated?: undefined;
|
|
16
|
-
error?: undefined;
|
|
17
16
|
ok?: undefined;
|
|
17
|
+
error?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
count?: undefined;
|
|
20
20
|
updated: number;
|
|
21
|
-
error?: undefined;
|
|
22
21
|
ok?: undefined;
|
|
22
|
+
error?: undefined;
|
|
23
23
|
} | {
|
|
24
24
|
count?: undefined;
|
|
25
25
|
updated?: undefined;
|
|
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
+
error?: undefined;
|
|
44
45
|
summary: import("./types.js").TraceSummary;
|
|
45
46
|
spans: import("./types.js").TraceSpan[];
|
|
46
47
|
id?: undefined;
|
|
47
|
-
error?: undefined;
|
|
48
48
|
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
+
error?: undefined;
|
|
50
51
|
summary?: undefined;
|
|
51
52
|
spans?: undefined;
|
|
52
53
|
id: string;
|
|
53
|
-
error?: undefined;
|
|
54
54
|
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
56
|
summary?: undefined;
|
|
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
59
59
|
error: any;
|
|
60
60
|
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
+
error?: undefined;
|
|
62
63
|
summary?: undefined;
|
|
63
64
|
spans?: undefined;
|
|
64
65
|
id?: undefined;
|
|
65
|
-
error?: undefined;
|
|
66
66
|
ok: boolean;
|
|
67
67
|
}>>;
|
|
@@ -311,8 +311,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
-
deleted?: undefined;
|
|
315
314
|
id?: undefined;
|
|
315
|
+
deleted?: undefined;
|
|
316
316
|
provider?: undefined;
|
|
317
317
|
found?: undefined;
|
|
318
318
|
providers: {
|
|
@@ -329,9 +329,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
329
329
|
label?: undefined;
|
|
330
330
|
message?: undefined;
|
|
331
331
|
} | {
|
|
332
|
+
id?: undefined;
|
|
332
333
|
deleted?: undefined;
|
|
333
334
|
count?: undefined;
|
|
334
|
-
id?: undefined;
|
|
335
335
|
providers?: undefined;
|
|
336
336
|
found: boolean;
|
|
337
337
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
48
48
|
}>;
|
|
49
49
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
50
50
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
51
|
-
error: string;
|
|
52
51
|
ok?: undefined;
|
|
52
|
+
error: string;
|
|
53
53
|
} | {
|
|
54
54
|
error?: undefined;
|
|
55
55
|
ok: boolean;
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
import type { ActionEntry } from "../agent/production-agent.js";
|
|
29
|
-
import
|
|
29
|
+
import { CORE_ACTION_GROUPS } from "../framework-tools.js";
|
|
30
30
|
/**
|
|
31
31
|
* Register a map of actions contributed by a published package.
|
|
32
32
|
*
|
|
@@ -81,22 +81,7 @@ export declare function loadActionsFromStaticRegistry(modules: Record<string, un
|
|
|
81
81
|
* passing to `createAgentChatPlugin({ actions })`.
|
|
82
82
|
*/
|
|
83
83
|
export declare function autoDiscoverActions(from: string): Promise<Record<string, ActionEntry>>;
|
|
84
|
-
|
|
85
|
-
* Which `frameworkTools` switch owns each framework action kit.
|
|
86
|
-
*
|
|
87
|
-
* The group is stamped onto the entry as `frameworkGroup`, which is what lets
|
|
88
|
-
* one filter subtract a whole kit from every agent tool surface at once — the
|
|
89
|
-
* plugin spreads these registries at thirteen composition sites, and a
|
|
90
|
-
* per-site condition would be the same omission waiting to happen thirteen
|
|
91
|
-
* times. The tag also keeps these ~45 schemas out of the DEFAULT first-request
|
|
92
|
-
* tool list; they stay reachable through `tool-search`.
|
|
93
|
-
*
|
|
94
|
-
* Anything absent from this map is always-on and must be listed in
|
|
95
|
-
* `ALWAYS_ON_CORE_ACTIONS` instead. `action-discovery.spec.ts` fails when a new
|
|
96
|
-
* core action appears in neither, so "always-on" stays a decision someone made
|
|
97
|
-
* rather than the default that happens when a map goes un-updated.
|
|
98
|
-
*/
|
|
99
|
-
export declare const CORE_ACTION_GROUPS: Record<string, FrameworkToolGroup>;
|
|
84
|
+
export { CORE_ACTION_GROUPS };
|
|
100
85
|
/**
|
|
101
86
|
* Core actions with no `frameworkTools` switch, and why:
|
|
102
87
|
*
|
|
@@ -104,7 +89,7 @@ export declare const CORE_ACTION_GROUPS: Record<string, FrameworkToolGroup>;
|
|
|
104
89
|
* - The email catalog is mounted everywhere on purpose so Dispatch can ask any
|
|
105
90
|
* app what it sends without that app opting in (see its comment below). It is
|
|
106
91
|
* a read surface, not the `email` group's send capability.
|
|
107
|
-
* - MCP tools and org service tokens are already governed by `
|
|
92
|
+
* - MCP tools and org service tokens are already governed by `mcp.enabled`.
|
|
108
93
|
*/
|
|
109
94
|
export declare const ALWAYS_ON_CORE_ACTIONS: ReadonlySet<string>;
|
|
110
95
|
export declare function mergeCoreSharingActions(registry: Record<string, ActionEntry>): Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import nodePath from "node:path";
|
|
2
|
+
import { CORE_ACTION_GROUPS } from "../framework-tools.js";
|
|
2
3
|
import { captureCliOutput } from "./cli-capture.js";
|
|
3
4
|
// Lazy fs — loaded via dynamic import() on first use.
|
|
4
5
|
// Avoids require() which bundlers convert to createRequire() that crashes on CF Workers.
|
|
@@ -497,70 +498,10 @@ export async function autoDiscoverActions(from) {
|
|
|
497
498
|
}
|
|
498
499
|
return registry;
|
|
499
500
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
* one filter subtract a whole kit from every agent tool surface at once — the
|
|
505
|
-
* plugin spreads these registries at thirteen composition sites, and a
|
|
506
|
-
* per-site condition would be the same omission waiting to happen thirteen
|
|
507
|
-
* times. The tag also keeps these ~45 schemas out of the DEFAULT first-request
|
|
508
|
-
* tool list; they stay reachable through `tool-search`.
|
|
509
|
-
*
|
|
510
|
-
* Anything absent from this map is always-on and must be listed in
|
|
511
|
-
* `ALWAYS_ON_CORE_ACTIONS` instead. `action-discovery.spec.ts` fails when a new
|
|
512
|
-
* core action appears in neither, so "always-on" stays a decision someone made
|
|
513
|
-
* rather than the default that happens when a map goes un-updated.
|
|
514
|
-
*/
|
|
515
|
-
export const CORE_ACTION_GROUPS = {
|
|
516
|
-
"share-resource": "sharing",
|
|
517
|
-
"unshare-resource": "sharing",
|
|
518
|
-
"list-resource-shares": "sharing",
|
|
519
|
-
"set-resource-visibility": "sharing",
|
|
520
|
-
"create-agent-resource-link": "sharing",
|
|
521
|
-
"get-feature-flags": "featureFlags",
|
|
522
|
-
"list-feature-flags": "featureFlags",
|
|
523
|
-
"set-feature-flag": "featureFlags",
|
|
524
|
-
"list-recurring-jobs": "automation",
|
|
525
|
-
"manage-recurring-job": "automation",
|
|
526
|
-
"run-automation-now": "automation",
|
|
527
|
-
"list-automation-runs": "automation",
|
|
528
|
-
"list-automations": "automation",
|
|
529
|
-
"manage-automation": "automation",
|
|
530
|
-
"context-manifest-get": "contextXray",
|
|
531
|
-
"context-preview-get": "contextXray",
|
|
532
|
-
"context-pin": "contextXray",
|
|
533
|
-
"context-evict": "contextXray",
|
|
534
|
-
"context-restore": "contextXray",
|
|
535
|
-
"context-report": "contextXray",
|
|
536
|
-
"get-localization-preference": "localization",
|
|
537
|
-
"set-localization-preference": "localization",
|
|
538
|
-
// Profile, credentials, and appearance share one switch: an app that hides
|
|
539
|
-
// its profile surface from the agent hides password management with it.
|
|
540
|
-
"get-user-profile": "userProfile",
|
|
541
|
-
"update-user-profile": "userProfile",
|
|
542
|
-
"get-auth-methods": "userProfile",
|
|
543
|
-
"set-password": "userProfile",
|
|
544
|
-
"change-password": "userProfile",
|
|
545
|
-
"change-appearance": "userProfile",
|
|
546
|
-
"list-audit-events": "audit",
|
|
547
|
-
"get-audit-event": "audit",
|
|
548
|
-
"export-audit-events": "audit",
|
|
549
|
-
"create-resource-version": "history",
|
|
550
|
-
"list-resource-versions": "history",
|
|
551
|
-
"get-resource-version": "history",
|
|
552
|
-
"restore-resource-version": "history",
|
|
553
|
-
"list-resource-history": "history",
|
|
554
|
-
"list-review-comments": "review",
|
|
555
|
-
"create-review-comment": "review",
|
|
556
|
-
"reply-review-comment": "review",
|
|
557
|
-
"resolve-review-thread": "review",
|
|
558
|
-
"delete-review-comment": "review",
|
|
559
|
-
"consume-review-feedback": "review",
|
|
560
|
-
"get-review-feedback": "review",
|
|
561
|
-
"set-review-status": "review",
|
|
562
|
-
"send-review-thread-to-agent": "review",
|
|
563
|
-
};
|
|
501
|
+
// `CORE_ACTION_GROUPS` lives in `framework-tools.ts` so the group filter can
|
|
502
|
+
// resolve a kit by name without importing this module. Re-exported here
|
|
503
|
+
// because this is where callers have always found it.
|
|
504
|
+
export { CORE_ACTION_GROUPS };
|
|
564
505
|
/**
|
|
565
506
|
* Core actions with no `frameworkTools` switch, and why:
|
|
566
507
|
*
|
|
@@ -568,7 +509,7 @@ export const CORE_ACTION_GROUPS = {
|
|
|
568
509
|
* - The email catalog is mounted everywhere on purpose so Dispatch can ask any
|
|
569
510
|
* app what it sends without that app opting in (see its comment below). It is
|
|
570
511
|
* a read surface, not the `email` group's send capability.
|
|
571
|
-
* - MCP tools and org service tokens are already governed by `
|
|
512
|
+
* - MCP tools and org service tokens are already governed by `mcp.enabled`.
|
|
572
513
|
*/
|
|
573
514
|
export const ALWAYS_ON_CORE_ACTIONS = new Set([
|
|
574
515
|
"upload-image",
|
|
@@ -818,6 +759,9 @@ export async function mergeCoreSharingActions(registry) {
|
|
|
818
759
|
// actions' `toolCallable: false` (audit-H5) is dropped and the
|
|
819
760
|
// tools-iframe bridge 403 in action-routes.ts never fires.
|
|
820
761
|
...preserveActionFlags(def),
|
|
762
|
+
// Pre-resolved copy of what `resolveFrameworkGroup` would compute
|
|
763
|
+
// from the name anyway. Kept so an entry read in isolation still
|
|
764
|
+
// reports its kit; the filters no longer depend on it.
|
|
821
765
|
...(CORE_ACTION_GROUPS[name]
|
|
822
766
|
? { frameworkGroup: CORE_ACTION_GROUPS[name] }
|
|
823
767
|
: {}),
|
|
@@ -3,6 +3,7 @@ import type { EngineTool } from "../../agent/engine/types.js";
|
|
|
3
3
|
import { type ActionEntry, type AgentLoopOutcome } from "../../agent/production-agent.js";
|
|
4
4
|
import { runAgentLoopDirectWithSoftTimeout } from "../../agent/run-loop-with-resume.js";
|
|
5
5
|
import type { AgentChatEvent } from "../../agent/types.js";
|
|
6
|
+
import type { ExternalAgentPolicy } from "../../mcp/external-agent-policy.js";
|
|
6
7
|
import type { AgentChatPluginOptions } from "./plugin-options.js";
|
|
7
8
|
export declare function filterReadOnlyActions(actions: Record<string, ActionEntry>): Record<string, ActionEntry>;
|
|
8
9
|
/** Drop actions that opted out of agent exposure via `agentTool: false`. They
|
|
@@ -25,13 +26,24 @@ export declare function filterPublicAgentActions(actions: Record<string, ActionE
|
|
|
25
26
|
* action out of this rule.
|
|
26
27
|
*/
|
|
27
28
|
export declare function hasRawQueryInput(entry: ActionEntry): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The two policy fields A2A shares with the MCP mount. Structural rather than
|
|
31
|
+
* `Pick<AgentChatPluginOptions, …>` so callers pass the *resolved* MCP options:
|
|
32
|
+
* reading the raw plugin options here would leave A2A on the deprecated
|
|
33
|
+
* top-level keys, so `mcp: { connectorCatalog }` would narrow the MCP surface
|
|
34
|
+
* while A2A kept serving the old one.
|
|
35
|
+
*/
|
|
36
|
+
export interface A2AExternalAgentSurface {
|
|
37
|
+
connectorCatalog?: string[];
|
|
38
|
+
externalAgents?: ExternalAgentPolicy;
|
|
39
|
+
}
|
|
28
40
|
/**
|
|
29
41
|
* Direct A2A action calls share the authenticated external-agent policy with
|
|
30
42
|
* MCP, but remain stricter: only explicitly exposed, authenticated read-only
|
|
31
43
|
* actions can skip the receiver's model loop, and never one that takes a raw
|
|
32
44
|
* query the caller wrote.
|
|
33
45
|
*/
|
|
34
|
-
export declare function filterDirectA2AActions(actions: Record<string, ActionEntry>, options:
|
|
46
|
+
export declare function filterDirectA2AActions(actions: Record<string, ActionEntry>, options: A2AExternalAgentSurface): Record<string, ActionEntry>;
|
|
35
47
|
export declare function buildPublicAgentA2ASkills(actions: Record<string, ActionEntry>): Array<{
|
|
36
48
|
id: string;
|
|
37
49
|
name: string;
|
|
@@ -47,7 +59,7 @@ export declare function buildPublicAgentA2ASkills(actions: Record<string, Action
|
|
|
47
59
|
* `requiresAuth === true` — advertising the public set alone tells siblings
|
|
48
60
|
* an app has nothing callable when it does.
|
|
49
61
|
*/
|
|
50
|
-
export declare function buildAuthenticatedAgentA2ASkills(actions: Record<string, ActionEntry>, options:
|
|
62
|
+
export declare function buildAuthenticatedAgentA2ASkills(actions: Record<string, ActionEntry>, options: A2AExternalAgentSurface): Array<{
|
|
51
63
|
id: string;
|
|
52
64
|
name: string;
|
|
53
65
|
description: string;
|
|
@@ -405,6 +405,6 @@ export function resolveInitialToolNames(templateActions, configured) {
|
|
|
405
405
|
if (configured)
|
|
406
406
|
return configured;
|
|
407
407
|
return Object.entries(templateActions)
|
|
408
|
-
.filter(([, entry]) => !isFrameworkGroupedAction(entry))
|
|
408
|
+
.filter(([name, entry]) => !isFrameworkGroupedAction(name, entry))
|
|
409
409
|
.map(([name]) => name);
|
|
410
410
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { ExternalAgentPolicy } from "../../mcp/external-agent-policy.js";
|
|
2
|
+
/** App icon descriptor surfaced during the MCP `initialize` handshake. */
|
|
3
|
+
export interface AgentChatMcpIcon {
|
|
4
|
+
src: string;
|
|
5
|
+
mimeType?: string;
|
|
6
|
+
sizes?: string[];
|
|
7
|
+
theme?: "light" | "dark";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Everything the agent-chat plugin can configure about its MCP mount, in one
|
|
11
|
+
* object.
|
|
12
|
+
*
|
|
13
|
+
* Before this existed, the MCP settings were five unrelated top-level keys
|
|
14
|
+
* (`disableMcp`, `mcpServerInfo`, `connectorCatalog`, `externalAgents`) and
|
|
15
|
+
* several `MCPConfig` fields with no route through the plugin at all —
|
|
16
|
+
* `builtinCrossAppTools` was reachable only by calling `mountMCP` directly,
|
|
17
|
+
* which is why `frameworkTools` could never remove the cross-app builtins from
|
|
18
|
+
* an app that used the normal plugin entry point.
|
|
19
|
+
*/
|
|
20
|
+
export interface AgentChatMcpOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Mount the remote MCP protocol route. Defaults to `true`.
|
|
23
|
+
*
|
|
24
|
+
* Set `false` for hosted apps with a dedicated early MCP plugin, so their
|
|
25
|
+
* external connector does not depend on the heavier chat plugin
|
|
26
|
+
* initialization path.
|
|
27
|
+
*/
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* `"app"` serves external callers exactly this app's own tool registry,
|
|
31
|
+
* flat — the same actions the in-app agent holds, with no cross-app
|
|
32
|
+
* builtins, no `ask-agent`, no `tool-search`, and no compact/connector
|
|
33
|
+
* trimming. `connectorCatalog` and the `--full-catalog` opt-ins are inert
|
|
34
|
+
* once this is set; `externalAgents.denyActions` and OAuth scopes still
|
|
35
|
+
* apply.
|
|
36
|
+
*
|
|
37
|
+
* Weigh the token cost before setting it: an app registering ~100 actions
|
|
38
|
+
* puts every one of their schemas in the caller's context on `tools/list`,
|
|
39
|
+
* which is the exact footgun the compact default exists to avoid.
|
|
40
|
+
*/
|
|
41
|
+
catalog?: "app";
|
|
42
|
+
/**
|
|
43
|
+
* Curated allow-list of action names served to external connector clients.
|
|
44
|
+
* Trims both the advertised and the callable surface — a name outside the
|
|
45
|
+
* list is rejected, not merely hidden.
|
|
46
|
+
*/
|
|
47
|
+
connectorCatalog?: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Default authenticated external-agent policy. In `auto` read mode, every
|
|
50
|
+
* action explicitly marked as GET + readOnly + publicAgent.requiresAuth is
|
|
51
|
+
* added to the connector surface automatically. Writes remain ask_app-only
|
|
52
|
+
* unless `writes: "allowlisted"` is explicitly selected.
|
|
53
|
+
*/
|
|
54
|
+
externalAgents?: ExternalAgentPolicy;
|
|
55
|
+
/**
|
|
56
|
+
* Merge the generic cross-app builtins (`list_apps`, `open_app`, `ask_app`,
|
|
57
|
+
* `ask_app_status`, `create_embed_session`, `create_workspace_app`,
|
|
58
|
+
* `list_templates`). Defaults to `true`.
|
|
59
|
+
*
|
|
60
|
+
* These are added by the MCP layer itself, downstream of `frameworkTools`,
|
|
61
|
+
* so they are NOT removed by `frameworkTools: "minimal"` or
|
|
62
|
+
* `workspaceApps: false` — this is the switch that turns them off.
|
|
63
|
+
*/
|
|
64
|
+
builtinCrossAppTools?: boolean;
|
|
65
|
+
/** Human-facing title. Defaults to the capitalized app id/name. */
|
|
66
|
+
title?: string;
|
|
67
|
+
/** Host-facing description. Defaults to "Agent-native <app> agent". */
|
|
68
|
+
description?: string;
|
|
69
|
+
/** Canonical app URL. Relative URLs are resolved against the request origin. */
|
|
70
|
+
websiteUrl?: string;
|
|
71
|
+
/** App icons. Relative `src` values are resolved against the request origin. */
|
|
72
|
+
icons?: AgentChatMcpIcon[];
|
|
73
|
+
}
|
|
74
|
+
/** The legacy top-level keys `mcp` replaces. */
|
|
75
|
+
export interface AgentChatMcpLegacyInput {
|
|
76
|
+
/** @deprecated Use `mcp.enabled: false`. */
|
|
77
|
+
disableMcp?: boolean;
|
|
78
|
+
/** @deprecated Use `mcp.title` / `mcp.description` / `mcp.websiteUrl` / `mcp.icons`. */
|
|
79
|
+
mcpServerInfo?: {
|
|
80
|
+
title?: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
websiteUrl?: string;
|
|
83
|
+
icons?: AgentChatMcpIcon[];
|
|
84
|
+
};
|
|
85
|
+
/** @deprecated Use `mcp.connectorCatalog`. */
|
|
86
|
+
connectorCatalog?: string[];
|
|
87
|
+
/** @deprecated Use `mcp.externalAgents`. */
|
|
88
|
+
externalAgents?: ExternalAgentPolicy;
|
|
89
|
+
mcp?: AgentChatMcpOptions;
|
|
90
|
+
}
|
|
91
|
+
export interface ResolvedAgentChatMcp {
|
|
92
|
+
enabled: boolean;
|
|
93
|
+
catalog: "app" | undefined;
|
|
94
|
+
connectorCatalog: string[] | undefined;
|
|
95
|
+
externalAgents: ExternalAgentPolicy | undefined;
|
|
96
|
+
builtinCrossAppTools: boolean | undefined;
|
|
97
|
+
title: string | undefined;
|
|
98
|
+
description: string | undefined;
|
|
99
|
+
websiteUrl: string | undefined;
|
|
100
|
+
icons: AgentChatMcpIcon[] | undefined;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Collapse the nested `mcp` option and the legacy top-level keys into the one
|
|
104
|
+
* shape the plugin threads into `mountMCP`.
|
|
105
|
+
*/
|
|
106
|
+
export declare function resolveAgentChatMcpOptions(input: AgentChatMcpLegacyInput | undefined): ResolvedAgentChatMcp;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
function conflict(key, legacyKey, legacyValue, nestedValue) {
|
|
2
|
+
throw new Error(`[agent-native] Conflicting agent-chat options: \`${legacyKey}: ${JSON.stringify(legacyValue)}\` ` +
|
|
3
|
+
`and \`mcp.${key}: ${JSON.stringify(nestedValue)}\` disagree. ` +
|
|
4
|
+
`Remove the deprecated \`${legacyKey}\` and keep \`mcp.${key}\`.`);
|
|
5
|
+
}
|
|
6
|
+
const warnedLegacyKeys = new Set();
|
|
7
|
+
/**
|
|
8
|
+
* Nested value wins, but only when the two forms agree.
|
|
9
|
+
*
|
|
10
|
+
* Disagreement throws at plugin init rather than picking a side: an app that
|
|
11
|
+
* boots with an MCP surface nobody chose is how a "why can't the connector see
|
|
12
|
+
* this tool" report ends up unexplainable. Same contract as
|
|
13
|
+
* `resolveFrameworkTools`.
|
|
14
|
+
*/
|
|
15
|
+
function pick(key, legacyKey, legacyValue, nestedValue) {
|
|
16
|
+
if (legacyValue === undefined)
|
|
17
|
+
return nestedValue;
|
|
18
|
+
if (nestedValue !== undefined &&
|
|
19
|
+
JSON.stringify(legacyValue) !== JSON.stringify(nestedValue)) {
|
|
20
|
+
conflict(key, legacyKey, legacyValue, nestedValue);
|
|
21
|
+
}
|
|
22
|
+
if (!warnedLegacyKeys.has(legacyKey)) {
|
|
23
|
+
warnedLegacyKeys.add(legacyKey);
|
|
24
|
+
console.warn(`[agent-native] \`${legacyKey}\` is deprecated — use \`mcp: { ${key}: … }\`.`);
|
|
25
|
+
}
|
|
26
|
+
return nestedValue ?? legacyValue;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Collapse the nested `mcp` option and the legacy top-level keys into the one
|
|
30
|
+
* shape the plugin threads into `mountMCP`.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveAgentChatMcpOptions(input) {
|
|
33
|
+
const mcp = input?.mcp ?? {};
|
|
34
|
+
const legacyInfo = input?.mcpServerInfo;
|
|
35
|
+
// `disableMcp` is the inverse of `enabled`, so normalize before comparing —
|
|
36
|
+
// otherwise `disableMcp: true` + `enabled: false` would read as a conflict.
|
|
37
|
+
const legacyEnabled = input?.disableMcp === undefined ? undefined : !input.disableMcp;
|
|
38
|
+
const enabled = pick("enabled", "disableMcp", legacyEnabled, mcp.enabled);
|
|
39
|
+
return {
|
|
40
|
+
enabled: enabled ?? true,
|
|
41
|
+
catalog: mcp.catalog,
|
|
42
|
+
connectorCatalog: pick("connectorCatalog", "connectorCatalog", input?.connectorCatalog, mcp.connectorCatalog),
|
|
43
|
+
externalAgents: pick("externalAgents", "externalAgents", input?.externalAgents, mcp.externalAgents),
|
|
44
|
+
builtinCrossAppTools: mcp.builtinCrossAppTools,
|
|
45
|
+
title: pick("title", "mcpServerInfo.title", legacyInfo?.title, mcp.title),
|
|
46
|
+
description: pick("description", "mcpServerInfo.description", legacyInfo?.description, mcp.description),
|
|
47
|
+
websiteUrl: pick("websiteUrl", "mcpServerInfo.websiteUrl", legacyInfo?.websiteUrl, mcp.websiteUrl),
|
|
48
|
+
icons: pick("icons", "mcpServerInfo.icons", legacyInfo?.icons, mcp.icons),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -5,6 +5,7 @@ import type { FrameworkToolsConfig } from "../../framework-tools.js";
|
|
|
5
5
|
import type { ExternalAgentPolicy } from "../../mcp/external-agent-policy.js";
|
|
6
6
|
import type { DatabaseToolsOption } from "../../scripts/db/tool-mode.js";
|
|
7
7
|
import type { PromptExamples } from "../prompts/index.js";
|
|
8
|
+
import type { AgentChatMcpIcon, AgentChatMcpOptions } from "./mcp-options.js";
|
|
8
9
|
/** Shape of a Nitro plugin function: receives the Nitro app instance at
|
|
9
10
|
* startup and may register routes/hooks synchronously or asynchronously. */
|
|
10
11
|
export type NitroPluginDef = (nitroApp: any) => void | Promise<void>;
|
|
@@ -51,21 +52,23 @@ export interface AgentChatPluginOptions {
|
|
|
51
52
|
mentionProviders?: Record<string, MentionProvider> | (() => Record<string, MentionProvider> | Promise<Record<string, MentionProvider>>);
|
|
52
53
|
/** App ID used to exclude self from agent discovery (e.g., "mail", "calendar") */
|
|
53
54
|
appId?: string;
|
|
54
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Everything about this app's MCP mount — whether it is mounted, which tools
|
|
57
|
+
* external callers see, and the branding sent during the `initialize`
|
|
58
|
+
* handshake. See `AgentChatMcpOptions`.
|
|
59
|
+
*
|
|
60
|
+
* Replaces the top-level `disableMcp`, `mcpServerInfo`, `connectorCatalog`,
|
|
61
|
+
* and `externalAgents`, which stay accepted for one minor. Setting both
|
|
62
|
+
* forms to disagreeing values throws at plugin init rather than silently
|
|
63
|
+
* picking one.
|
|
64
|
+
*/
|
|
65
|
+
mcp?: AgentChatMcpOptions;
|
|
66
|
+
/** @deprecated Use `mcp.title` / `mcp.description` / `mcp.websiteUrl` / `mcp.icons`. */
|
|
55
67
|
mcpServerInfo?: {
|
|
56
|
-
/** Human-facing title. Defaults to the capitalized app id/name. */
|
|
57
68
|
title?: string;
|
|
58
|
-
/** Host-facing description. Defaults to "Agent-native <app> agent". */
|
|
59
69
|
description?: string;
|
|
60
|
-
/** Canonical app URL. Relative URLs are resolved against the request origin. */
|
|
61
70
|
websiteUrl?: string;
|
|
62
|
-
|
|
63
|
-
icons?: Array<{
|
|
64
|
-
src: string;
|
|
65
|
-
mimeType?: string;
|
|
66
|
-
sizes?: string[];
|
|
67
|
-
theme?: "light" | "dark";
|
|
68
|
-
}>;
|
|
71
|
+
icons?: AgentChatMcpIcon[];
|
|
69
72
|
};
|
|
70
73
|
/**
|
|
71
74
|
* Optional callback to resolve the org ID for the current request.
|
|
@@ -330,15 +333,10 @@ export interface AgentChatPluginOptions {
|
|
|
330
333
|
* claim in their connect-minted JWT) or the deployment-wide
|
|
331
334
|
* `AGENT_NATIVE_MCP_FULL_CATALOG=1` env override.
|
|
332
335
|
*
|
|
333
|
-
*
|
|
336
|
+
* @deprecated Use `mcp.connectorCatalog`.
|
|
334
337
|
*/
|
|
335
338
|
connectorCatalog?: string[];
|
|
336
|
-
/**
|
|
337
|
-
* Default authenticated external-agent policy. In `auto` read mode, every
|
|
338
|
-
* action explicitly marked as GET + readOnly + publicAgent.requiresAuth is
|
|
339
|
-
* added to the connector surface automatically. Writes remain ask_app-only
|
|
340
|
-
* unless `writes: "allowlisted"` is explicitly selected.
|
|
341
|
-
*/
|
|
339
|
+
/** @deprecated Use `mcp.externalAgents`. */
|
|
342
340
|
externalAgents?: ExternalAgentPolicy;
|
|
343
341
|
/**
|
|
344
342
|
* Allow this app's A2A agent to delegate to a different app through the
|
|
@@ -359,14 +357,7 @@ export interface AgentChatPluginOptions {
|
|
|
359
357
|
maxRunInputTokens?: number;
|
|
360
358
|
maxToolResultChars?: number;
|
|
361
359
|
};
|
|
362
|
-
/**
|
|
363
|
-
* Skip mounting the remote MCP protocol route.
|
|
364
|
-
*
|
|
365
|
-
* Most apps should leave this off so agent chat, A2A, and MCP share one
|
|
366
|
-
* runtime. Hosted apps with a dedicated early MCP plugin can set this to
|
|
367
|
-
* true so their external connector does not depend on the heavier chat
|
|
368
|
-
* plugin initialization path.
|
|
369
|
-
*/
|
|
360
|
+
/** @deprecated Use `mcp: { enabled: false }`. */
|
|
370
361
|
disableMcp?: boolean;
|
|
371
362
|
/**
|
|
372
363
|
* Code-execution capability for the production agent.
|
|
@@ -110,6 +110,7 @@ import { createA2AEngineToolSurface, DEFAULT_DELEGATED_MAX_ITERATIONS, DEFAULT_D
|
|
|
110
110
|
import { createBuilderBrowserTool, createTeamTools, } from "./agent-chat/browser-team-tools.js";
|
|
111
111
|
import { createDataWidgetActionEntries, createFrameworkContextEntry, createRefreshScreenEntry, createUrlTools, } from "./agent-chat/context-tools.js";
|
|
112
112
|
import { _agentChatPromptSectionsForTests, buildFrameworkPrompts, buildSchemaBlock, collectFiles, corpusToolNamesTaughtByPrompt, generateActionsPrompt, generateCorpusToolsPrompt, } from "./agent-chat/framework-prompts.js";
|
|
113
|
+
import { resolveAgentChatMcpOptions } from "./agent-chat/mcp-options.js";
|
|
113
114
|
import { resolveA2AAgentDelegationEnabled, } from "./agent-chat/plugin-options.js";
|
|
114
115
|
import { finalizeClaimedAgentChatProcessRunFailure } from "./agent-chat/process-run-failure.js";
|
|
115
116
|
import { loadResourcesForPrompt, promptResourceManifestSections, resourceScopeForOwner, } from "./agent-chat/prompt-resources.js";
|
|
@@ -286,6 +287,11 @@ export function createAgentChatPlugin(options) {
|
|
|
286
287
|
// here rather than booting with a surface nobody chose.
|
|
287
288
|
const frameworkTools = resolveFrameworkTools(options);
|
|
288
289
|
const disabledFrameworkGroups = frameworkTools.disabledGroups;
|
|
290
|
+
// Same treatment for the MCP mount: one resolved shape, folding the
|
|
291
|
+
// deprecated `disableMcp` / `mcpServerInfo` / `connectorCatalog` /
|
|
292
|
+
// `externalAgents` into `mcp`. A2A reads the same object, so the
|
|
293
|
+
// connector policy cannot diverge between the two external surfaces.
|
|
294
|
+
const mcpOptions = resolveAgentChatMcpOptions(options);
|
|
289
295
|
// Build the four assembled system prompt strings. These are static for the
|
|
290
296
|
// lifetime of this plugin instance — examples come from options once at
|
|
291
297
|
// startup, not per-request.
|
|
@@ -1055,12 +1061,12 @@ export function createAgentChatPlugin(options) {
|
|
|
1055
1061
|
: "Agent",
|
|
1056
1062
|
description: `Agent-native ${options?.appId ?? "app"} agent`,
|
|
1057
1063
|
skills: buildPublicAgentA2ASkills(allScripts),
|
|
1058
|
-
authenticatedSkills: buildAuthenticatedAgentA2ASkills(mcpFullActions ?? allScripts,
|
|
1064
|
+
authenticatedSkills: buildAuthenticatedAgentA2ASkills(mcpFullActions ?? allScripts, mcpOptions),
|
|
1059
1065
|
publicSkillsOnly: true,
|
|
1060
1066
|
streaming: true,
|
|
1061
1067
|
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
1062
1068
|
executeReadOnlyAction: async ({ action, input, invocationId }) => {
|
|
1063
|
-
const actions = filterDirectA2AActions(mcpFullActions ?? allScripts,
|
|
1069
|
+
const actions = filterDirectA2AActions(mcpFullActions ?? allScripts, mcpOptions);
|
|
1064
1070
|
const entry = actions[action];
|
|
1065
1071
|
if (!entry) {
|
|
1066
1072
|
return {
|
|
@@ -1667,26 +1673,30 @@ export function createAgentChatPlugin(options) {
|
|
|
1667
1673
|
: DEV_FRAMEWORK_PROMPT) + devActionsPrompt;
|
|
1668
1674
|
// Keep legacy names for the composition below
|
|
1669
1675
|
const basePrompt = prodPrompt;
|
|
1670
|
-
if (
|
|
1676
|
+
if (mcpOptions.enabled) {
|
|
1671
1677
|
// Mount MCP remote server — same action registry as A2A + agent chat
|
|
1672
1678
|
const { mountMCP } = await import("../mcp/server.js");
|
|
1673
1679
|
mountMCP(nitroApp, {
|
|
1674
1680
|
name: options?.appId
|
|
1675
1681
|
? options.appId.charAt(0).toUpperCase() + options.appId.slice(1)
|
|
1676
1682
|
: "Agent",
|
|
1677
|
-
title:
|
|
1683
|
+
title: mcpOptions.title,
|
|
1678
1684
|
appId: options?.appId,
|
|
1679
|
-
description:
|
|
1685
|
+
description: mcpOptions.description ??
|
|
1680
1686
|
`Agent-native ${options?.appId ?? "app"} agent`,
|
|
1681
|
-
websiteUrl:
|
|
1682
|
-
icons:
|
|
1687
|
+
websiteUrl: mcpOptions.websiteUrl,
|
|
1688
|
+
icons: mcpOptions.icons,
|
|
1683
1689
|
actions: allScripts,
|
|
1684
1690
|
productionActions: mcpFullActions,
|
|
1685
|
-
...(
|
|
1686
|
-
|
|
1691
|
+
...(mcpOptions.catalog ? { catalogMode: mcpOptions.catalog } : {}),
|
|
1692
|
+
...(mcpOptions.builtinCrossAppTools !== undefined
|
|
1693
|
+
? { builtinCrossAppTools: mcpOptions.builtinCrossAppTools }
|
|
1687
1694
|
: {}),
|
|
1688
|
-
...(
|
|
1689
|
-
? {
|
|
1695
|
+
...(mcpOptions.connectorCatalog
|
|
1696
|
+
? { connectorCatalog: mcpOptions.connectorCatalog }
|
|
1697
|
+
: {}),
|
|
1698
|
+
...(mcpOptions.externalAgents
|
|
1699
|
+
? { externalAgents: mcpOptions.externalAgents }
|
|
1690
1700
|
: {}),
|
|
1691
1701
|
askAgent: async (message) => {
|
|
1692
1702
|
const ownerEmail = getRequestUserEmail();
|
package/dist/server/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export { createObservationalMemoryPlugin, defaultObservationalMemoryPlugin, } fr
|
|
|
32
32
|
export { createGoogleAuthPlugin, type GoogleAuthPluginOptions, } from "./google-auth-plugin.js";
|
|
33
33
|
export type { GoogleAuthMode } from "./google-auth-mode.js";
|
|
34
34
|
export { createAgentChatPlugin, defaultAgentChatPlugin, refreshGlobalMcpManager, type AgentChatPluginOptions, } from "./agent-chat-plugin.js";
|
|
35
|
+
export type { AgentChatMcpIcon, AgentChatMcpOptions, } from "./agent-chat/mcp-options.js";
|
|
35
36
|
export { configureAgentNativeEmbeddedEnvironment, createAgentNativeEmbeddedAuthOptions, createAgentNativeEmbeddedPlugin, mountAgentNativeEmbedded, normalizeAgentNativeEmbeddedSession, type AgentNativeEmbeddedAuthOptions, type AgentNativeEmbeddedGetSession, type AgentNativeEmbeddedHostSession, type AgentNativeEmbeddedPluginOptions, } from "./embedded.js";
|
|
36
37
|
export { createThread, getThread, listThreads, updateThreadData, deleteThread, setThreadArchived, setThreadPinned, setThreadScope, type ChatThread, type ChatThreadScope, type ChatThreadSummary, type ListThreadsOptions, } from "../chat-threads/store.js";
|
|
37
38
|
export { createResourcesPlugin, defaultResourcesPlugin, } from "./resources-plugin.js";
|
|
@@ -52,6 +53,8 @@ export { getH3App, awaitBootstrap, markDefaultPluginProvided, type H3AppShim, }
|
|
|
52
53
|
export { fireInternalDispatch, resolveSelfDispatchBaseUrl, type FireInternalDispatchOptions, } from "./self-dispatch.js";
|
|
53
54
|
export { extractBearerToken as extractInternalBearerToken, verifyInternalToken, } from "../integrations/internal-token.js";
|
|
54
55
|
export { autoDiscoverActions, autoDiscoverScripts, loadActionsFromStaticRegistry, mergeCoreSharingActions, registerPackageActions, } from "./action-discovery.js";
|
|
56
|
+
export { attachToolSearch, createToolSearchEntry, searchToolRegistry, TOOL_SEARCH_ACTION_NAME, } from "../agent/tool-search.js";
|
|
57
|
+
export { filterFrameworkToolGroups, frameworkGroupEnabled, resolveFrameworkTools, FRAMEWORK_TOOL_GROUPS, type FrameworkToolGroup, type FrameworkToolsConfig, type FrameworkToolsOption, type ResolvedFrameworkTools, } from "../framework-tools.js";
|
|
55
58
|
export { registerPromptContextProvider, type PromptContextProvider, type PromptContextProviderContext, type PromptContextProviderContribution, } from "./agent-chat/prompt-resources.js";
|
|
56
59
|
export { mountActionRoutes, type MountActionRoutesOptions, type ActionRouteAuthAdapter, type ActionRouteResolvedCaller, } from "./action-routes.js";
|
|
57
60
|
export { AGENT_RUN_OWNER_CONTEXT_KEY, seedAgentRunOwnerContext, type AgentRunOwnerContext, } from "./agent-run-context.js";
|
package/dist/server/index.js
CHANGED
|
@@ -53,6 +53,13 @@ export { getH3App, awaitBootstrap, markDefaultPluginProvided, } from "./framewor
|
|
|
53
53
|
export { fireInternalDispatch, resolveSelfDispatchBaseUrl, } from "./self-dispatch.js";
|
|
54
54
|
export { extractBearerToken as extractInternalBearerToken, verifyInternalToken, } from "../integrations/internal-token.js";
|
|
55
55
|
export { autoDiscoverActions, autoDiscoverScripts, loadActionsFromStaticRegistry, mergeCoreSharingActions, registerPackageActions, } from "./action-discovery.js";
|
|
56
|
+
// A standalone `mountMCP` plugin has to compose the same action surface the
|
|
57
|
+
// agent-chat plugin does. Without these, the only way to build one was to
|
|
58
|
+
// hand-roll a copy — which is how a template ends up with a `tool-search` that
|
|
59
|
+
// drifts from the framework's, and an MCP mount that silently ignores
|
|
60
|
+
// `frameworkTools`.
|
|
61
|
+
export { attachToolSearch, createToolSearchEntry, searchToolRegistry, TOOL_SEARCH_ACTION_NAME, } from "../agent/tool-search.js";
|
|
62
|
+
export { filterFrameworkToolGroups, frameworkGroupEnabled, resolveFrameworkTools, FRAMEWORK_TOOL_GROUPS, } from "../framework-tools.js";
|
|
56
63
|
export { registerPromptContextProvider, } from "./agent-chat/prompt-resources.js";
|
|
57
64
|
export { mountActionRoutes, } from "./action-routes.js";
|
|
58
65
|
export { AGENT_RUN_OWNER_CONTEXT_KEY, seedAgentRunOwnerContext, } from "./agent-run-context.js";
|