@agent-native/core 0.101.10 → 0.101.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +6 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +23 -1
  5. package/corpus/core/src/a2a/handlers.ts +65 -1
  6. package/corpus/core/src/a2a/server.ts +124 -0
  7. package/corpus/core/src/a2a/task-store.ts +253 -0
  8. package/corpus/core/src/a2a/types.ts +26 -0
  9. package/corpus/core/src/agent/production-agent.ts +5 -2
  10. package/corpus/core/src/mcp/builtin-tools.ts +25 -1
  11. package/corpus/core/src/scripts/call-agent.ts +22 -3
  12. package/corpus/core/src/server/agent-chat-plugin.ts +86 -1
  13. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
  14. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +23 -0
  15. package/corpus/templates/content/app/components/editor/MathRenderer.tsx +43 -0
  16. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +260 -4
  17. package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +78 -0
  18. package/corpus/templates/content/app/global.css +53 -0
  19. package/corpus/templates/content/app/i18n/zh-TW.ts +13 -0
  20. package/corpus/templates/content/app/i18n-data.ts +163 -0
  21. package/corpus/templates/content/app/root.tsx +2 -0
  22. package/corpus/templates/content/changelog/2026-07-14-latex-equations-render-in-documents-public-pages-and-exports.md +6 -0
  23. package/corpus/templates/content/package.json +1 -0
  24. package/corpus/templates/content/shared/document-export.ts +296 -25
  25. package/corpus/templates/content/shared/inline-math.ts +128 -0
  26. package/corpus/templates/content/shared/math-rendering.ts +50 -0
  27. package/corpus/templates/content/shared/nfm.ts +17 -14
  28. package/corpus/templates/content/vite.config.ts +0 -1
  29. package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +17 -0
  30. package/corpus/templates/mail/AGENTS.md +21 -19
  31. package/corpus/templates/mail/actions/create-attachment-upload.ts +49 -0
  32. package/corpus/templates/mail/changelog/2026-07-14-connected-agents-can-now-securely-upload-local-files-for-mai.md +6 -0
  33. package/corpus/templates/mail/server/handlers/media.ts +84 -61
  34. package/corpus/templates/mail/server/lib/attachment-upload-ticket.ts +234 -0
  35. package/corpus/templates/mail/server/lib/mail-connector-catalog.ts +8 -4
  36. package/corpus/templates/mail/server/lib/media-upload.ts +114 -0
  37. package/corpus/templates/mail/server/plugins/auth.ts +9 -1
  38. package/corpus/templates/mail/server/routes/api/media/attachment-upload/[uploadId].put.ts +1 -0
  39. package/dist/a2a/client.d.ts +5 -1
  40. package/dist/a2a/client.d.ts.map +1 -1
  41. package/dist/a2a/client.js +18 -1
  42. package/dist/a2a/client.js.map +1 -1
  43. package/dist/a2a/handlers.d.ts.map +1 -1
  44. package/dist/a2a/handlers.js +57 -8
  45. package/dist/a2a/handlers.js.map +1 -1
  46. package/dist/a2a/server.d.ts.map +1 -1
  47. package/dist/a2a/server.js +87 -1
  48. package/dist/a2a/server.js.map +1 -1
  49. package/dist/a2a/task-store.d.ts +27 -0
  50. package/dist/a2a/task-store.d.ts.map +1 -1
  51. package/dist/a2a/task-store.js +216 -0
  52. package/dist/a2a/task-store.js.map +1 -1
  53. package/dist/a2a/types.d.ts +24 -0
  54. package/dist/a2a/types.d.ts.map +1 -1
  55. package/dist/a2a/types.js.map +1 -1
  56. package/dist/agent/production-agent.d.ts +1 -0
  57. package/dist/agent/production-agent.d.ts.map +1 -1
  58. package/dist/agent/production-agent.js +5 -2
  59. package/dist/agent/production-agent.js.map +1 -1
  60. package/dist/collab/struct-routes.d.ts +1 -1
  61. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  62. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  63. package/dist/mcp/builtin-tools.js +22 -3
  64. package/dist/mcp/builtin-tools.js.map +1 -1
  65. package/dist/notifications/routes.d.ts +3 -3
  66. package/dist/observability/routes.d.ts +5 -5
  67. package/dist/resources/handlers.d.ts +3 -3
  68. package/dist/scripts/call-agent.d.ts +1 -1
  69. package/dist/scripts/call-agent.d.ts.map +1 -1
  70. package/dist/scripts/call-agent.js +19 -1
  71. package/dist/scripts/call-agent.js.map +1 -1
  72. package/dist/secrets/routes.d.ts +9 -9
  73. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  74. package/dist/server/agent-chat-plugin.js +71 -2
  75. package/dist/server/agent-chat-plugin.js.map +1 -1
  76. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  77. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
  78. package/package.json +1 -1
  79. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
@@ -0,0 +1,234 @@
1
+ import crypto from "node:crypto";
2
+
3
+ import { getDbExec, isPostgres } from "@agent-native/core/db";
4
+ import { getUserSetting } from "@agent-native/core/settings";
5
+ import { nanoid } from "nanoid";
6
+
7
+ import { extensionForUpload, mimeTypeForUpload } from "./media-upload.js";
8
+
9
+ const SETTING_KEY = "mail-attachment-upload-ticket";
10
+ const TICKET_TTL_MS = 5 * 60 * 1000;
11
+ const MAX_PENDING_TICKETS = 20;
12
+ const MAX_CAS_ATTEMPTS = 8;
13
+
14
+ export interface AttachmentUploadTicket extends Record<string, unknown> {
15
+ uploadId: string;
16
+ filename: string;
17
+ originalName: string;
18
+ mimeType: string;
19
+ tokenHash: string;
20
+ expiresAt: number;
21
+ }
22
+
23
+ interface AttachmentUploadTickets extends Record<string, unknown> {
24
+ tickets: Record<string, AttachmentUploadTicket>;
25
+ }
26
+
27
+ function tokenHash(token: string): string {
28
+ return crypto.createHash("sha256").update(token).digest("hex");
29
+ }
30
+
31
+ function encodeOwner(ownerEmail: string): string {
32
+ return Buffer.from(ownerEmail, "utf8").toString("base64url");
33
+ }
34
+
35
+ function decodeOwner(token: string): string | null {
36
+ const ownerPart = token.split(".", 1)[0];
37
+ if (!ownerPart) return null;
38
+ try {
39
+ const owner = Buffer.from(ownerPart, "base64url").toString("utf8");
40
+ return owner.includes("@") ? owner : null;
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ function hashesMatch(left: string, right: string): boolean {
47
+ const leftBuffer = Buffer.from(left, "utf8");
48
+ const rightBuffer = Buffer.from(right, "utf8");
49
+ if (leftBuffer.length !== rightBuffer.length) return false;
50
+ return crypto.timingSafeEqual(leftBuffer, rightBuffer);
51
+ }
52
+
53
+ function settingStorageKey(ownerEmail: string): string {
54
+ return `u:${ownerEmail}:${SETTING_KEY}`;
55
+ }
56
+
57
+ function settingsTable(): string {
58
+ return isPostgres() ? "public.settings" : "settings";
59
+ }
60
+
61
+ function parseTickets(raw: string | null): AttachmentUploadTickets {
62
+ if (!raw) return { tickets: {} };
63
+ try {
64
+ const parsed = JSON.parse(raw) as Partial<AttachmentUploadTickets>;
65
+ if (!parsed.tickets || typeof parsed.tickets !== "object") {
66
+ return { tickets: {} };
67
+ }
68
+ return {
69
+ tickets: Object.fromEntries(
70
+ Object.entries(parsed.tickets).filter(
71
+ ([uploadId, ticket]) =>
72
+ uploadId &&
73
+ ticket &&
74
+ typeof ticket === "object" &&
75
+ ticket.uploadId === uploadId,
76
+ ),
77
+ ),
78
+ };
79
+ } catch {
80
+ return { tickets: {} };
81
+ }
82
+ }
83
+
84
+ function pruneTickets(
85
+ tickets: Record<string, AttachmentUploadTicket>,
86
+ now: number,
87
+ ): Record<string, AttachmentUploadTicket> {
88
+ return Object.fromEntries(
89
+ Object.entries(tickets)
90
+ .filter(
91
+ ([, ticket]) =>
92
+ Number.isFinite(ticket.expiresAt) && ticket.expiresAt >= now,
93
+ )
94
+ .sort(([, left], [, right]) => right.expiresAt - left.expiresAt)
95
+ .slice(0, MAX_PENDING_TICKETS),
96
+ );
97
+ }
98
+
99
+ async function readTicketsRow(
100
+ ownerEmail: string,
101
+ ): Promise<{ raw: string | null; collection: AttachmentUploadTickets }> {
102
+ // This initializes the framework-owned settings table without duplicating
103
+ // its schema/startup logic. The raw read below deliberately bypasses the
104
+ // per-request settings cache because compare-and-swap retries need fresh data.
105
+ await getUserSetting(ownerEmail, SETTING_KEY);
106
+ const { rows } = await getDbExec().execute({
107
+ sql: `SELECT value FROM ${settingsTable()} WHERE key = ?`,
108
+ args: [settingStorageKey(ownerEmail)],
109
+ });
110
+ const raw = rows.length ? String(rows[0].value ?? rows[0][0]) : null;
111
+ return { raw, collection: parseTickets(raw) };
112
+ }
113
+
114
+ async function compareAndSwapTickets(
115
+ ownerEmail: string,
116
+ expectedRaw: string | null,
117
+ collection: AttachmentUploadTickets,
118
+ ): Promise<boolean> {
119
+ const value = JSON.stringify(collection);
120
+ const key = settingStorageKey(ownerEmail);
121
+ const client = getDbExec();
122
+ if (expectedRaw === null) {
123
+ const result = await client.execute({
124
+ sql: isPostgres()
125
+ ? `INSERT INTO ${settingsTable()} (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT (key) DO NOTHING`
126
+ : `INSERT OR IGNORE INTO ${settingsTable()} (key, value, updated_at) VALUES (?, ?, ?)`,
127
+ args: [key, value, Date.now()],
128
+ });
129
+ return result.rowsAffected === 1;
130
+ }
131
+ const result = await client.execute({
132
+ sql: `UPDATE ${settingsTable()} SET value = ?, updated_at = ? WHERE key = ? AND value = ?`,
133
+ args: [value, Date.now(), key, expectedRaw],
134
+ });
135
+ return result.rowsAffected === 1;
136
+ }
137
+
138
+ export async function createAttachmentUploadTicket(
139
+ ownerEmail: string,
140
+ originalName: string,
141
+ ): Promise<AttachmentUploadTicket & { token: string }> {
142
+ const uploadId = nanoid(12);
143
+ const filename = `${uploadId}${extensionForUpload(originalName)}`;
144
+ const token = `${encodeOwner(ownerEmail)}.${crypto.randomBytes(32).toString("base64url")}`;
145
+ const ticket: AttachmentUploadTicket = {
146
+ uploadId,
147
+ filename,
148
+ originalName,
149
+ mimeType: mimeTypeForUpload(originalName),
150
+ tokenHash: tokenHash(token),
151
+ expiresAt: Date.now() + TICKET_TTL_MS,
152
+ };
153
+
154
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt += 1) {
155
+ const { raw, collection } = await readTicketsRow(ownerEmail);
156
+ const tickets = pruneTickets(
157
+ // Put the new ticket first so stable sorting keeps it when many tickets
158
+ // share the same millisecond expiry at the collection limit.
159
+ { [uploadId]: ticket, ...collection.tickets },
160
+ Date.now(),
161
+ );
162
+ if (await compareAndSwapTickets(ownerEmail, raw, { tickets })) {
163
+ return { ...ticket, token };
164
+ }
165
+ }
166
+ throw new Error("Could not reserve an attachment upload ticket");
167
+ }
168
+
169
+ export async function verifyAttachmentUploadTicket(
170
+ uploadId: string,
171
+ token: string,
172
+ ): Promise<{ ownerEmail: string; ticket: AttachmentUploadTicket } | null> {
173
+ const ownerEmail = decodeOwner(token);
174
+ if (!ownerEmail) return null;
175
+
176
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt += 1) {
177
+ const { raw, collection } = await readTicketsRow(ownerEmail);
178
+ const tickets = pruneTickets(collection.tickets, Date.now());
179
+ const ticket = tickets[uploadId];
180
+ if (JSON.stringify(tickets) !== JSON.stringify(collection.tickets)) {
181
+ if (!(await compareAndSwapTickets(ownerEmail, raw, { tickets })))
182
+ continue;
183
+ }
184
+ if (
185
+ !ticket ||
186
+ typeof ticket.tokenHash !== "string" ||
187
+ !hashesMatch(ticket.tokenHash, tokenHash(token))
188
+ ) {
189
+ return null;
190
+ }
191
+ return { ownerEmail, ticket };
192
+ }
193
+ return null;
194
+ }
195
+
196
+ /**
197
+ * Atomically validates and removes a one-time upload capability.
198
+ *
199
+ * The caller must claim immediately before the storage side effect. Once this
200
+ * returns a ticket it cannot be reclaimed, even if storage later fails. That
201
+ * fail-closed behavior prevents retries from turning an ambiguous write into a
202
+ * replay vulnerability.
203
+ */
204
+ export async function claimAttachmentUploadTicket(
205
+ uploadId: string,
206
+ token: string,
207
+ ): Promise<{ ownerEmail: string; ticket: AttachmentUploadTicket } | null> {
208
+ const ownerEmail = decodeOwner(token);
209
+ if (!ownerEmail) return null;
210
+
211
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt += 1) {
212
+ const { raw, collection } = await readTicketsRow(ownerEmail);
213
+ const tickets = pruneTickets(collection.tickets, Date.now());
214
+ const ticket = tickets[uploadId];
215
+ if (
216
+ !ticket ||
217
+ typeof ticket.tokenHash !== "string" ||
218
+ !hashesMatch(ticket.tokenHash, tokenHash(token))
219
+ ) {
220
+ if (JSON.stringify(tickets) !== JSON.stringify(collection.tickets)) {
221
+ if (!(await compareAndSwapTickets(ownerEmail, raw, { tickets }))) {
222
+ continue;
223
+ }
224
+ }
225
+ return null;
226
+ }
227
+
228
+ delete tickets[uploadId];
229
+ if (await compareAndSwapTickets(ownerEmail, raw, { tickets })) {
230
+ return { ownerEmail, ticket };
231
+ }
232
+ }
233
+ return null;
234
+ }
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * Deliberately narrow authenticated MCP surface for Mail.
3
3
  *
4
- * External callers may read inbox coverage through list-emails. Other actions
5
- * remain available through the in-app agent, ask_app, or an explicit
6
- * full-catalog connection; tool-search alone never makes them callable.
4
+ * External callers may read inbox coverage and mint a short-lived attachment
5
+ * upload capability. Other actions remain available through the in-app agent,
6
+ * ask_app, or an explicit full-catalog connection; tool-search alone never
7
+ * makes them callable.
7
8
  */
8
- export const MAIL_CONNECTOR_CATALOG = ["list-emails"] as const;
9
+ export const MAIL_CONNECTOR_CATALOG = [
10
+ "list-emails",
11
+ "create-attachment-upload",
12
+ ] as const;
@@ -0,0 +1,114 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { uploadFile } from "@agent-native/core/file-upload";
5
+
6
+ import { getStoredUpload, putStoredUpload } from "./upload-store.js";
7
+
8
+ const UPLOADS_DIR = path.resolve("data/uploads");
9
+
10
+ const MIME_MAP: Record<string, string> = {
11
+ ".png": "image/png",
12
+ ".jpg": "image/jpeg",
13
+ ".jpeg": "image/jpeg",
14
+ ".gif": "image/gif",
15
+ ".webp": "image/webp",
16
+ ".svg": "image/svg+xml",
17
+ ".pdf": "application/pdf",
18
+ ".txt": "text/plain",
19
+ ".csv": "text/csv",
20
+ ".doc": "application/msword",
21
+ ".docx":
22
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
23
+ ".xls": "application/vnd.ms-excel",
24
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
25
+ ".zip": "application/zip",
26
+ };
27
+
28
+ export const MAX_UPLOAD_BYTES = 10 * 1024 * 1024;
29
+
30
+ export interface StoredMediaUpload {
31
+ url: string;
32
+ filename: string;
33
+ originalName: string;
34
+ mimeType: string;
35
+ size: number;
36
+ provider?: string;
37
+ }
38
+
39
+ export class MediaStorageSetupError extends Error {
40
+ readonly storageSetupRequired = true;
41
+ }
42
+
43
+ export function extensionForUpload(originalName: string): string {
44
+ return path.extname(originalName).toLowerCase() || ".bin";
45
+ }
46
+
47
+ export function mimeTypeForUpload(originalName: string): string {
48
+ return (
49
+ MIME_MAP[extensionForUpload(originalName)] || "application/octet-stream"
50
+ );
51
+ }
52
+
53
+ export function uploadsDirectory(): string {
54
+ return UPLOADS_DIR;
55
+ }
56
+
57
+ export async function storeMediaUpload(input: {
58
+ ownerEmail: string;
59
+ data: Uint8Array;
60
+ filename: string;
61
+ originalName: string;
62
+ }): Promise<StoredMediaUpload> {
63
+ if (input.data.byteLength > MAX_UPLOAD_BYTES) {
64
+ throw new Error("File too large (max 10 MB)");
65
+ }
66
+
67
+ const mimeType = mimeTypeForUpload(input.originalName);
68
+ const payload = {
69
+ url: `/api/media/${input.filename}`,
70
+ filename: input.filename,
71
+ originalName: input.originalName,
72
+ mimeType,
73
+ size: input.data.byteLength,
74
+ };
75
+
76
+ try {
77
+ const uploaded = await uploadFile({
78
+ data: input.data,
79
+ filename: input.originalName,
80
+ mimeType,
81
+ ownerEmail: input.ownerEmail,
82
+ recordAsset: false,
83
+ });
84
+ if (uploaded?.url) {
85
+ await putStoredUpload(input.ownerEmail, {
86
+ ...payload,
87
+ url: uploaded.url,
88
+ createdAt: Date.now(),
89
+ });
90
+ const persisted = await getStoredUpload(input.ownerEmail, input.filename);
91
+ if (persisted?.url !== uploaded.url) {
92
+ throw new Error("Uploaded file metadata did not persist");
93
+ }
94
+ return { ...payload, url: uploaded.url, provider: uploaded.provider };
95
+ }
96
+ } catch (error) {
97
+ if (process.env.NODE_ENV === "production") throw error;
98
+ }
99
+
100
+ if (process.env.NODE_ENV === "production") {
101
+ throw new MediaStorageSetupError(
102
+ "File storage is not configured. Connect Builder.io or another upload provider before attaching files in hosted environments.",
103
+ );
104
+ }
105
+
106
+ fs.mkdirSync(UPLOADS_DIR, { recursive: true });
107
+ const filePath = path.join(UPLOADS_DIR, input.filename);
108
+ fs.writeFileSync(filePath, input.data);
109
+ const storedSize = fs.statSync(filePath).size;
110
+ if (storedSize !== input.data.byteLength) {
111
+ throw new Error("Uploaded file did not persist completely");
112
+ }
113
+ return payload;
114
+ }
@@ -51,5 +51,13 @@ export default createAuthPlugin({
51
51
  // GMAIL_PUSH_AUDIENCE is configured.
52
52
  // Cloud Scheduler POSTs to /api/gmail/watch/renew every 6h for watch
53
53
  // lifecycle; same OIDC-verification pattern.
54
- publicPaths: ["/api/gmail/push", "/api/gmail/watch/renew", "/api/tracking"],
54
+ // Attachment upload capabilities carry their own short-lived, owner-bound
55
+ // bearer credential because a local MCP caller cannot attach the browser's
56
+ // session cookie to the subsequent raw-byte PUT.
57
+ publicPaths: [
58
+ "/api/gmail/push",
59
+ "/api/gmail/watch/renew",
60
+ "/api/tracking",
61
+ "/api/media/attachment-upload",
62
+ ],
55
63
  });
@@ -0,0 +1 @@
1
+ export { uploadAttachmentWithTicket as default } from "../../../../handlers/media.js";
@@ -1,4 +1,4 @@
1
- import type { AgentCard, Message, Task } from "./types.js";
1
+ import type { A2AApprovedAction, AgentCard, Message, Task } from "./types.js";
2
2
  export declare class A2ATaskTimeoutError extends Error {
3
3
  readonly taskId: string;
4
4
  readonly lastTask: Task;
@@ -51,6 +51,7 @@ export declare class A2AClient {
51
51
  send(message: Message, opts?: {
52
52
  contextId?: string;
53
53
  metadata?: Record<string, unknown>;
54
+ approvedActions?: A2AApprovedAction[];
54
55
  /**
55
56
  * If true, ask the server to return the task immediately in `working`
56
57
  * state and process the handler in the background. The caller should
@@ -77,6 +78,7 @@ export declare class A2AClient {
77
78
  sendAndWait(message: Message, opts?: {
78
79
  contextId?: string;
79
80
  metadata?: Record<string, unknown>;
81
+ approvedActions?: A2AApprovedAction[];
80
82
  /** Total time to wait for completion. Default 5 min. */
81
83
  timeoutMs?: number;
82
84
  /** Poll interval. Default 2s. */
@@ -106,6 +108,8 @@ export declare function callAgent(url: string, text: string, opts?: {
106
108
  orgSecret?: string;
107
109
  /** Origin used to build links back to the receiving app. */
108
110
  requestOrigin?: string;
111
+ /** Exact downstream actions explicitly authorized in the caller's chat. */
112
+ approvedActions?: A2AApprovedAction[];
109
113
  /**
110
114
  * Use async/poll instead of a single blocking POST. Recommended for
111
115
  * cross-app calls that may exceed a synchronous serverless request budget.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/a2a/client.ts"],"names":[],"mappings":"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"}
@@ -160,6 +160,9 @@ export class A2AClient {
160
160
  message,
161
161
  contextId: opts?.contextId,
162
162
  metadata: opts?.metadata,
163
+ ...(opts?.approvedActions?.length
164
+ ? { approvedActions: opts.approvedActions }
165
+ : {}),
163
166
  ...(opts?.async ? { async: true } : {}),
164
167
  });
165
168
  if (response.error) {
@@ -190,9 +193,17 @@ export class A2AClient {
190
193
  const submitted = await this.send(message, {
191
194
  contextId: opts?.contextId,
192
195
  metadata: opts?.metadata,
196
+ ...(opts?.approvedActions?.length
197
+ ? { approvedActions: opts.approvedActions }
198
+ : {}),
193
199
  async: true,
194
200
  });
195
- const terminalStates = new Set(["completed", "failed", "canceled"]);
201
+ const terminalStates = new Set([
202
+ "completed",
203
+ "failed",
204
+ "canceled",
205
+ "input-required",
206
+ ]);
196
207
  if (terminalStates.has(submitted.status.state))
197
208
  return submitted;
198
209
  const timeoutMs = opts?.timeoutMs ?? 5 * 60_000;
@@ -430,6 +441,9 @@ export async function callAgent(url, text, opts) {
430
441
  task = await client.sendAndWait(message, {
431
442
  contextId: opts?.contextId,
432
443
  metadata,
444
+ ...(opts?.approvedActions?.length
445
+ ? { approvedActions: opts.approvedActions }
446
+ : {}),
433
447
  timeoutMs: opts?.timeoutMs,
434
448
  pollIntervalMs: opts?.pollIntervalMs,
435
449
  onUpdate: opts?.onUpdate,
@@ -439,6 +453,9 @@ export async function callAgent(url, text, opts) {
439
453
  task = await client.send(message, {
440
454
  contextId: opts?.contextId,
441
455
  metadata,
456
+ ...(opts?.approvedActions?.length
457
+ ? { approvedActions: opts.approvedActions }
458
+ : {}),
442
459
  });
443
460
  }
444
461
  // Extract text from the response