@agent-native/core 0.72.3 → 0.72.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/core/CHANGELOG.md +10 -0
- package/corpus/core/package.json +6 -6
- package/corpus/core/src/a2a/client.ts +7 -3
- package/corpus/core/src/client/api-path.ts +28 -0
- package/corpus/core/src/client/embed-auth.ts +26 -0
- package/corpus/core/src/client/mcp-app-host.ts +6 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +227 -33
- package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
- package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -1
- package/corpus/core/src/demo/fetch-interceptor.ts +1 -1
- package/corpus/core/src/embedding/agent.ts +6 -1
- package/corpus/core/src/embedding/bridge.ts +34 -1
- package/corpus/core/src/mcp/build-server.ts +38 -10
- package/corpus/core/src/mcp/embed-app.ts +120 -45
- package/corpus/core/src/mcp/index.ts +5 -0
- package/corpus/core/src/mcp/org-directory.ts +70 -11
- package/corpus/core/src/mcp/server.ts +14 -0
- package/corpus/core/src/mcp-client/config.ts +12 -0
- package/corpus/core/src/mcp-client/index.ts +2 -0
- package/corpus/core/src/mcp-client/manager.ts +268 -9
- package/corpus/core/src/mcp-client/remote-store.ts +154 -0
- package/corpus/core/src/mcp-client/routes.ts +2 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +8 -0
- package/corpus/core/src/server/index.ts +1 -0
- package/corpus/core/src/shared/mcp-embed-headers.ts +44 -3
- package/corpus/core/src/vite/client.ts +53 -0
- package/corpus/templates/assets/.agents/skills/a2a-assets/SKILL.md +17 -10
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +15 -6
- package/corpus/templates/assets/AGENTS.md +7 -5
- package/corpus/templates/assets/actions/generate-asset.ts +161 -0
- package/corpus/templates/assets/actions/list-assets.ts +4 -2
- package/corpus/templates/assets/actions/open-asset-picker.ts +84 -3
- package/corpus/templates/assets/app/routes/library.tsx +243 -40
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +9 -0
- package/corpus/templates/design/AGENTS.md +10 -5
- package/corpus/templates/design/actions/connect-assets-mcp.ts +131 -0
- package/corpus/templates/design/actions/insert-asset.ts +219 -0
- package/corpus/templates/design/actions/view-screen.ts +3 -1
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +53 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +5 -1
- package/corpus/templates/design/server/plugins/assets-mcp.ts +60 -0
- package/dist/a2a/client.d.ts +1 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +5 -3
- package/dist/a2a/client.js.map +1 -1
- package/dist/client/api-path.d.ts.map +1 -1
- package/dist/client/api-path.js +27 -0
- package/dist/client/api-path.js.map +1 -1
- package/dist/client/embed-auth.d.ts.map +1 -1
- package/dist/client/embed-auth.js +27 -0
- package/dist/client/embed-auth.js.map +1 -1
- package/dist/client/mcp-app-host.d.ts.map +1 -1
- package/dist/client/mcp-app-host.js +5 -0
- package/dist/client/mcp-app-host.js.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.js +179 -33
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
- package/dist/client/resources/use-mcp-servers.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +3 -1
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/demo/fetch-interceptor.js +1 -1
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/embedding/agent.d.ts +1 -1
- package/dist/embedding/agent.d.ts.map +1 -1
- package/dist/embedding/agent.js +1 -1
- package/dist/embedding/agent.js.map +1 -1
- package/dist/embedding/bridge.d.ts.map +1 -1
- package/dist/embedding/bridge.js +27 -1
- package/dist/embedding/bridge.js.map +1 -1
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +32 -9
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +120 -45
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/org-directory.d.ts +1 -0
- package/dist/mcp/org-directory.d.ts.map +1 -1
- package/dist/mcp/org-directory.js +59 -11
- package/dist/mcp/org-directory.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp-client/config.d.ts +12 -0
- package/dist/mcp-client/config.d.ts.map +1 -1
- package/dist/mcp-client/config.js.map +1 -1
- package/dist/mcp-client/index.d.ts +1 -1
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +1 -1
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/manager.d.ts +2 -0
- package/dist/mcp-client/manager.d.ts.map +1 -1
- package/dist/mcp-client/manager.js +201 -9
- package/dist/mcp-client/manager.js.map +1 -1
- package/dist/mcp-client/remote-store.d.ts +27 -0
- package/dist/mcp-client/remote-store.d.ts.map +1 -1
- package/dist/mcp-client/remote-store.js +105 -0
- package/dist/mcp-client/remote-store.js.map +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +1 -0
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/provider-api/actions/github-repo-files.d.ts +2 -2
- package/dist/provider-api/actions/query-staged-dataset.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +8 -8
- package/dist/server/agent-chat-plugin.d.ts +2 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +8 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +3 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +40 -3
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/schema.d.ts +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +44 -0
- package/dist/vite/client.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: a2a-assets
|
|
3
|
-
description:
|
|
3
|
+
description: Use Assets from other apps or MCP hosts to generate, refine, export, and insert brand images or videos.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Assets MCP Tool
|
|
7
7
|
|
|
8
|
-
Use
|
|
8
|
+
Use the Assets MCP tool surface when another app or external host needs brand
|
|
9
|
+
imagery, video, or reusable source media and Assets owns the library. Prefer the
|
|
10
|
+
pure MCP `generate-asset` flow for human-in-the-loop generation because it can
|
|
11
|
+
return the inline picker. A2A remains useful for unattended cross-app
|
|
12
|
+
delegation, but A2A replies cannot render MCP App pickers.
|
|
9
13
|
|
|
10
14
|
## Caller Flow
|
|
11
15
|
|
|
12
|
-
1.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
1. For human selection, call `generate-asset` with the brief, `callerAppId`, and
|
|
17
|
+
`libraryId` when known. It will match the library, generate candidates, and
|
|
18
|
+
return the Assets picker filtered to the new run IDs.
|
|
19
|
+
2. For unattended A2A-style work, call `match-library` or `list-libraries` when
|
|
20
|
+
the library is ambiguous, then call `generate-image-batch` with one slot per
|
|
21
|
+
destination, such as one hero per slide. Pass `source: "a2a"` and
|
|
22
|
+
`callerAppId` with the calling app id (`slides`, `design`, `content`,
|
|
23
|
+
`mail`) so the Assets audit log can group cross-agent generations.
|
|
18
24
|
3. Treat image batches as complete when the action returns. Use returned
|
|
19
25
|
successful `images` entries directly; only regenerate slots that returned
|
|
20
26
|
`ok: false`.
|
|
@@ -25,7 +31,8 @@ Use A2A when another app needs brand imagery, video, or reusable source media an
|
|
|
25
31
|
6. For video, call `generate-video` and then `refresh-generation-run` until the run completes.
|
|
26
32
|
7. Preserve returned `assetId`, `runId`, `previewUrl`, `downloadUrl`, and
|
|
27
33
|
`embedPath` exactly.
|
|
28
|
-
8. Insert exported URLs into the caller's artifact.
|
|
34
|
+
8. Insert chosen/exported URLs into the caller's artifact. Design callers should
|
|
35
|
+
call `insert-asset` after the picker returns a selected asset.
|
|
29
36
|
9. On feedback, call `refine-image` with the prior `assetId`, `source: "a2a"`,
|
|
30
37
|
and the same `callerAppId`, then replace only the affected destination.
|
|
31
38
|
|
|
@@ -16,9 +16,14 @@ or generated image/video assets that another app can reference by ID and URL.
|
|
|
16
16
|
|
|
17
17
|
## Choose The Path
|
|
18
18
|
|
|
19
|
-
- Use `
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
- Use `generate-asset` when a person should get newly generated, on-brand image
|
|
20
|
+
candidates and choose the winner in the inline picker. It matches a library
|
|
21
|
+
when `libraryId` is omitted, generates candidates, returns the picker filtered
|
|
22
|
+
to those run IDs, and works in in-app chat plus external MCP hosts.
|
|
23
|
+
- Use `open-asset-picker` when a person should browse, search, or select an
|
|
24
|
+
existing asset in UI, or when you want the picker to handle generation itself.
|
|
25
|
+
Pass `mediaType: "image"` by default, or `mediaType: "video"` for video
|
|
26
|
+
libraries.
|
|
22
27
|
- Use unattended actions when the agent already knows what to do:
|
|
23
28
|
`search-assets`, `list-assets`, `generate-image`, `generate-image-batch`,
|
|
24
29
|
`generate-video`, `refresh-generation-run`, and `export-asset`.
|
|
@@ -41,7 +46,9 @@ or generated image/video assets that another app can reference by ID and URL.
|
|
|
41
46
|
|
|
42
47
|
## Image Workflows
|
|
43
48
|
|
|
44
|
-
1.
|
|
49
|
+
1. For human-in-the-loop generation, call `generate-asset` first and preserve
|
|
50
|
+
the returned picker/candidate metadata. For unattended generation, pick or
|
|
51
|
+
match the library with `list-libraries` or `match-library`.
|
|
45
52
|
If the user wants a default look rather than a brand library, call
|
|
46
53
|
`list-library-presets` and then `create-library-from-preset`; the resulting
|
|
47
54
|
library is editable and reusable like any other library.
|
|
@@ -85,8 +92,10 @@ deferred.
|
|
|
85
92
|
Do not put shared secrets in skill files.
|
|
86
93
|
- Local customization: run `npx @agent-native/core@latest app-skill launch --local` from the
|
|
87
94
|
Assets app-skill manifest, or pass `--into <path>` for editable source.
|
|
88
|
-
- For
|
|
89
|
-
|
|
95
|
+
- For MCP callers, `generate-asset` is the portable first choice because the
|
|
96
|
+
same MCP App picker renders inline in Agent-Native chat, ChatGPT, and Claude
|
|
97
|
+
when the host supports MCP Apps. Include exact `assetId`, `runId`, media type,
|
|
98
|
+
and URLs in the final response so the caller can attach or embed the media.
|
|
90
99
|
Include `presetId` and `sessionId` when present.
|
|
91
100
|
|
|
92
101
|
## Don't
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Assets — Agent Guide
|
|
2
2
|
|
|
3
3
|
Assets is an agent-native asset library and generation workspace. The agent
|
|
4
|
-
manages libraries, images, generated assets, inline
|
|
5
|
-
collaboration, and
|
|
4
|
+
manages libraries, images, generated assets, inline MCP App pickers,
|
|
5
|
+
notifications, collaboration, and portable asset requests through actions and
|
|
6
|
+
SQL state.
|
|
6
7
|
|
|
7
8
|
Detailed library, generation, image, embed, and engine rules live in
|
|
8
9
|
`.agents/skills/`.
|
|
@@ -61,9 +62,10 @@ Read the relevant skill before deeper work:
|
|
|
61
62
|
plain image-generation requests. Keep `npx @agent-native/core@latest connect` running until
|
|
62
63
|
browser authorization finishes, restart the client if tools are not visible,
|
|
63
64
|
and redact any MCP auth headers or tokens when debugging local config.
|
|
64
|
-
- For human-in-the-loop image creation,
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
- For human-in-the-loop image creation, prefer `generate-asset` so Assets
|
|
66
|
+
matches the library, generates candidates, and returns the inline picker
|
|
67
|
+
filtered to those candidates. Use `open-asset-picker` when the user only needs
|
|
68
|
+
to browse/search/pick or when you want the picker to handle generation itself.
|
|
67
69
|
- If the picker opens as a browser fallback instead of inline, selecting an
|
|
68
70
|
asset copies a handoff summary; ask the caller to paste it back into chat.
|
|
69
71
|
- Treat Codex, Claude Code, and Claude Desktop Code as link-out hosts for MCP
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { defineAction, embedApp } from "@agent-native/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import openAssetPicker from "./open-asset-picker.js";
|
|
4
|
+
import {
|
|
5
|
+
ASPECT_RATIOS,
|
|
6
|
+
IMAGE_QUALITY_TIERS,
|
|
7
|
+
STYLE_STRENGTHS,
|
|
8
|
+
} from "../shared/api.js";
|
|
9
|
+
|
|
10
|
+
const booleanParam = z.preprocess((value) => {
|
|
11
|
+
if (typeof value === "boolean") return value;
|
|
12
|
+
if (typeof value !== "string") return value;
|
|
13
|
+
const normalized = value.trim().toLowerCase();
|
|
14
|
+
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
15
|
+
if (["", "0", "false", "no", "off"].includes(normalized)) return false;
|
|
16
|
+
return value;
|
|
17
|
+
}, z.boolean());
|
|
18
|
+
|
|
19
|
+
const schema = z.object({
|
|
20
|
+
mediaType: z.enum(["image", "video"]).default("image"),
|
|
21
|
+
prompt: z
|
|
22
|
+
.string()
|
|
23
|
+
.min(1)
|
|
24
|
+
.describe("The asset brief to generate or prepare in the picker."),
|
|
25
|
+
libraryId: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Known Assets library ID. Omit to match the best library."),
|
|
29
|
+
libraryHint: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe(
|
|
33
|
+
"Brand, campaign, or use-case hint used when matching a library.",
|
|
34
|
+
),
|
|
35
|
+
aspectRatio: z.enum(ASPECT_RATIOS).default("16:9"),
|
|
36
|
+
presetId: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Optional generation preset ID from the selected library."),
|
|
40
|
+
count: z.coerce
|
|
41
|
+
.number()
|
|
42
|
+
.int()
|
|
43
|
+
.min(1)
|
|
44
|
+
.max(6)
|
|
45
|
+
.default(3)
|
|
46
|
+
.describe("Number of image candidates to generate in the picker."),
|
|
47
|
+
tier: z.enum(IMAGE_QUALITY_TIERS).optional(),
|
|
48
|
+
styleStrength: z.enum(STYLE_STRENGTHS).default("balanced"),
|
|
49
|
+
includeLogo: booleanParam.default(false),
|
|
50
|
+
callerAppId: z
|
|
51
|
+
.string()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe("Calling app id, for audit grouping, e.g. design."),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
type ActionWithToolParameters = {
|
|
57
|
+
tool: { parameters?: { properties?: Record<string, any> } };
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function allowStringifiedCountInToolSchema<T extends ActionWithToolParameters>(
|
|
61
|
+
action: T,
|
|
62
|
+
): T {
|
|
63
|
+
const parameters = action.tool.parameters;
|
|
64
|
+
const count = parameters?.properties?.count;
|
|
65
|
+
if (count && typeof count === "object" && !Array.isArray(count)) {
|
|
66
|
+
parameters!.properties!.count = {
|
|
67
|
+
description: count.description,
|
|
68
|
+
default: count.default,
|
|
69
|
+
anyOf: [
|
|
70
|
+
count,
|
|
71
|
+
{
|
|
72
|
+
type: "string",
|
|
73
|
+
pattern: "^[1-6]$",
|
|
74
|
+
description: count.description,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return action;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const action = defineAction({
|
|
83
|
+
description:
|
|
84
|
+
"Open the real Assets picker and start on-brand image generation there so the tool returns immediately and the user can choose the final image/video. Use this for human-in-the-loop brand media requests from Design, Slides, ChatGPT, Claude, or Codex. Preserve returned asset IDs and URLs exactly after the user picks.",
|
|
85
|
+
schema,
|
|
86
|
+
publicAgent: {
|
|
87
|
+
expose: true,
|
|
88
|
+
readOnly: false,
|
|
89
|
+
requiresAuth: true,
|
|
90
|
+
title: "Generate an on-brand asset",
|
|
91
|
+
description:
|
|
92
|
+
"Start brand-consistent image generation in the Assets picker.",
|
|
93
|
+
},
|
|
94
|
+
mcpApp: {
|
|
95
|
+
compactCatalog: true,
|
|
96
|
+
resource: embedApp({
|
|
97
|
+
title: "Generate Assets",
|
|
98
|
+
description:
|
|
99
|
+
"Generate image candidates and choose the final asset in the real Assets Library picker.",
|
|
100
|
+
iframeTitle: "Agent-Native Assets",
|
|
101
|
+
openLabel: "Open Assets picker",
|
|
102
|
+
height: 760,
|
|
103
|
+
connectDomains: ["https://cdn.builder.io"],
|
|
104
|
+
resourceDomains: ["https://cdn.builder.io"],
|
|
105
|
+
}),
|
|
106
|
+
},
|
|
107
|
+
link: ({ result }) => {
|
|
108
|
+
const url =
|
|
109
|
+
result && typeof result === "object"
|
|
110
|
+
? (result as { url?: unknown }).url
|
|
111
|
+
: null;
|
|
112
|
+
return {
|
|
113
|
+
url: typeof url === "string" && url ? url : "/library",
|
|
114
|
+
label: "Open Assets picker",
|
|
115
|
+
view: "picker",
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
run: async (args) => {
|
|
119
|
+
if (args.mediaType === "video") {
|
|
120
|
+
const picker = (await openAssetPicker.run({
|
|
121
|
+
mediaType: "video",
|
|
122
|
+
prompt: args.prompt,
|
|
123
|
+
libraryId: args.libraryId,
|
|
124
|
+
libraryHint: args.libraryHint,
|
|
125
|
+
count: args.count,
|
|
126
|
+
callerAppId: args.callerAppId,
|
|
127
|
+
})) as Record<string, unknown>;
|
|
128
|
+
return {
|
|
129
|
+
...picker,
|
|
130
|
+
generated: false,
|
|
131
|
+
message:
|
|
132
|
+
"Assets video picker is ready. Generate or select the video in the picker, then choose the asset to send it back.",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const picker = (await openAssetPicker.run({
|
|
137
|
+
mediaType: "image",
|
|
138
|
+
prompt: args.prompt,
|
|
139
|
+
libraryId: args.libraryId,
|
|
140
|
+
libraryHint: args.libraryHint,
|
|
141
|
+
aspectRatio: args.aspectRatio,
|
|
142
|
+
presetId: args.presetId,
|
|
143
|
+
count: args.count,
|
|
144
|
+
autoGenerate: true,
|
|
145
|
+
tier: args.tier,
|
|
146
|
+
styleStrength: args.styleStrength,
|
|
147
|
+
includeLogo: args.includeLogo,
|
|
148
|
+
callerAppId: args.callerAppId,
|
|
149
|
+
})) as Record<string, unknown>;
|
|
150
|
+
return {
|
|
151
|
+
...picker,
|
|
152
|
+
generated: false,
|
|
153
|
+
generationStarted: false,
|
|
154
|
+
generationMode: "picker-auto-generate",
|
|
155
|
+
message:
|
|
156
|
+
"Assets picker is ready and will start image generation inside the picker. If this org has no libraries yet, the picker will create a starter library first. Ask the user to pick one candidate; preserve the chosen assetId, runId, and URLs exactly.",
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
export default allowStringifiedCountInToolSchema(action);
|
|
@@ -95,13 +95,15 @@ export default defineAction({
|
|
|
95
95
|
.filter((asset) =>
|
|
96
96
|
shouldIncludeAssetInLibraryResults(
|
|
97
97
|
asset,
|
|
98
|
-
includeCandidates ||
|
|
98
|
+
includeCandidates ||
|
|
99
|
+
status === "candidate" ||
|
|
100
|
+
candidateRunIdSet.size > 0,
|
|
99
101
|
),
|
|
100
102
|
)
|
|
101
103
|
.filter((asset) => {
|
|
102
104
|
if (!candidateRunIdSet.size) return true;
|
|
103
105
|
if (!(asset.role === "generated" && asset.status === "candidate")) {
|
|
104
|
-
return
|
|
106
|
+
return false;
|
|
105
107
|
}
|
|
106
108
|
return Boolean(
|
|
107
109
|
asset.generationRunId && candidateRunIdSet.has(asset.generationRunId),
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { defineAction, embedApp } from "@agent-native/core";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { IMAGE_QUALITY_TIERS, STYLE_STRENGTHS } from "../shared/api.js";
|
|
3
4
|
|
|
4
5
|
const mediaTypeSchema = z.enum(["image", "video"]);
|
|
6
|
+
const booleanParam = z.preprocess((value) => {
|
|
7
|
+
if (typeof value === "boolean") return value;
|
|
8
|
+
if (typeof value !== "string") return value;
|
|
9
|
+
const normalized = value.trim().toLowerCase();
|
|
10
|
+
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
11
|
+
if (["", "0", "false", "no", "off"].includes(normalized)) return false;
|
|
12
|
+
return value;
|
|
13
|
+
}, z.boolean());
|
|
5
14
|
|
|
6
15
|
const schema = z.object({
|
|
7
16
|
mediaType: mediaTypeSchema.default("image"),
|
|
@@ -17,6 +26,12 @@ const schema = z.object({
|
|
|
17
26
|
.string()
|
|
18
27
|
.optional()
|
|
19
28
|
.describe("Optional asset library to open in the picker."),
|
|
29
|
+
libraryHint: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe(
|
|
33
|
+
"Brand, campaign, or use-case hint used to preselect the best-matching library when libraryId is omitted.",
|
|
34
|
+
),
|
|
20
35
|
aspectRatio: z
|
|
21
36
|
.string()
|
|
22
37
|
.optional()
|
|
@@ -32,16 +47,62 @@ const schema = z.object({
|
|
|
32
47
|
.max(6)
|
|
33
48
|
.default(3)
|
|
34
49
|
.describe("Number of image candidates to generate in the picker."),
|
|
35
|
-
|
|
36
|
-
.
|
|
50
|
+
candidateRunIds: z
|
|
51
|
+
.array(z.string())
|
|
52
|
+
.optional()
|
|
53
|
+
.describe(
|
|
54
|
+
"Generation run IDs to show as the candidate set when returning from a tool-generated batch.",
|
|
55
|
+
),
|
|
56
|
+
autoGenerate: booleanParam
|
|
37
57
|
.default(false)
|
|
38
58
|
.describe(
|
|
39
59
|
"When true and prompt is provided, generate candidates as soon as the picker opens.",
|
|
40
60
|
),
|
|
61
|
+
tier: z
|
|
62
|
+
.enum(IMAGE_QUALITY_TIERS)
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("Optional image quality tier to use for auto-generation."),
|
|
65
|
+
styleStrength: z
|
|
66
|
+
.enum(STYLE_STRENGTHS)
|
|
67
|
+
.default("balanced")
|
|
68
|
+
.describe("How strongly to follow the library style during generation."),
|
|
69
|
+
includeLogo: booleanParam
|
|
70
|
+
.default(false)
|
|
71
|
+
.describe("Whether auto-generation should include the library logo."),
|
|
72
|
+
callerAppId: z
|
|
73
|
+
.string()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Calling app id, for audit grouping, e.g. design."),
|
|
41
76
|
});
|
|
42
77
|
|
|
43
78
|
type OpenAssetPickerArgs = z.infer<typeof schema>;
|
|
44
79
|
|
|
80
|
+
type ActionWithToolParameters = {
|
|
81
|
+
tool: { parameters?: { properties?: Record<string, any> } };
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function allowStringifiedCountInToolSchema<T extends ActionWithToolParameters>(
|
|
85
|
+
action: T,
|
|
86
|
+
): T {
|
|
87
|
+
const parameters = action.tool.parameters;
|
|
88
|
+
const count = parameters?.properties?.count;
|
|
89
|
+
if (count && typeof count === "object" && !Array.isArray(count)) {
|
|
90
|
+
parameters!.properties!.count = {
|
|
91
|
+
description: count.description,
|
|
92
|
+
default: count.default,
|
|
93
|
+
anyOf: [
|
|
94
|
+
count,
|
|
95
|
+
{
|
|
96
|
+
type: "string",
|
|
97
|
+
pattern: "^[1-6]$",
|
|
98
|
+
description: count.description,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return action;
|
|
104
|
+
}
|
|
105
|
+
|
|
45
106
|
const FALLBACK_INSTRUCTIONS =
|
|
46
107
|
'If the picker opens in a normal browser tab instead of inline, the user has two ways to choose: (1) click an asset — the picker auto-copies a short handoff summary they paste back into chat, or (2) just tell you which one in words (e.g. "use the second image"). Either way, continue with the chosen asset. In Codex, Claude Code, and other code-editor chats, do not expect MCP Apps to render inline; provide the asset link, and if the final answer needs an inline image preview, download the selected image URL locally and embed the absolute local file path because remote CDN markdown previews may not render there.';
|
|
47
108
|
|
|
@@ -51,16 +112,28 @@ function pickerPath(args: Partial<OpenAssetPickerArgs>): string {
|
|
|
51
112
|
if (args.prompt?.trim()) params.set("prompt", args.prompt.trim());
|
|
52
113
|
if (args.query?.trim()) params.set("q", args.query.trim());
|
|
53
114
|
if (args.libraryId?.trim()) params.set("libraryId", args.libraryId.trim());
|
|
115
|
+
if (args.libraryHint?.trim()) {
|
|
116
|
+
params.set("libraryHint", args.libraryHint.trim());
|
|
117
|
+
}
|
|
54
118
|
if (args.aspectRatio?.trim()) {
|
|
55
119
|
params.set("aspectRatio", args.aspectRatio.trim());
|
|
56
120
|
}
|
|
57
121
|
if (args.presetId?.trim()) params.set("presetId", args.presetId.trim());
|
|
58
122
|
if (args.count && args.count !== 3) params.set("count", String(args.count));
|
|
123
|
+
if (args.tier) params.set("tier", args.tier);
|
|
124
|
+
if (args.styleStrength && args.styleStrength !== "balanced") {
|
|
125
|
+
params.set("styleStrength", args.styleStrength);
|
|
126
|
+
}
|
|
127
|
+
if (args.includeLogo) params.set("includeLogo", "1");
|
|
128
|
+
if (args.callerAppId?.trim()) params.set("callerAppId", args.callerAppId);
|
|
129
|
+
for (const runId of args.candidateRunIds ?? []) {
|
|
130
|
+
if (runId.trim()) params.append("candidateRunIds", runId.trim());
|
|
131
|
+
}
|
|
59
132
|
if (args.autoGenerate) params.set("autoGenerate", "1");
|
|
60
133
|
return `/library?${params.toString()}`;
|
|
61
134
|
}
|
|
62
135
|
|
|
63
|
-
|
|
136
|
+
const action = defineAction({
|
|
64
137
|
description:
|
|
65
138
|
'Open the image Library picker inline so a person can browse, search, generate, and select an image or video asset. When the user asks to create a specific image and choose the best one, pass prompt, autoGenerate: true, and count: 3 so the Library opens with generated candidates. If the host can only open a browser link (e.g. a CLI or code editor), surface that link: after the user picks, the page auto-copies a short paste-back summary — or the user can simply tell you which candidate they want (e.g. "use image A"). Use search-assets, generate-image, generate-video, and export-asset for unattended flows.',
|
|
66
139
|
schema,
|
|
@@ -122,10 +195,18 @@ export default defineAction({
|
|
|
122
195
|
query: args.query ?? null,
|
|
123
196
|
prompt: args.prompt ?? null,
|
|
124
197
|
libraryId: args.libraryId ?? null,
|
|
198
|
+
libraryHint: args.libraryHint ?? null,
|
|
125
199
|
aspectRatio: args.aspectRatio ?? null,
|
|
126
200
|
presetId: args.presetId ?? null,
|
|
127
201
|
count: args.count,
|
|
202
|
+
tier: args.tier ?? null,
|
|
203
|
+
styleStrength: args.styleStrength,
|
|
204
|
+
includeLogo: args.includeLogo,
|
|
205
|
+
callerAppId: args.callerAppId ?? null,
|
|
206
|
+
candidateRunIds: args.candidateRunIds ?? [],
|
|
128
207
|
autoGenerate: args.autoGenerate,
|
|
129
208
|
};
|
|
130
209
|
},
|
|
131
210
|
});
|
|
211
|
+
|
|
212
|
+
export default allowStringifiedCountInToolSchema(action);
|