@agent-native/core 0.114.3 → 0.114.5
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 +14 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/artifact-response.ts +42 -16
- package/corpus/core/src/a2a/client.ts +4 -0
- package/corpus/core/src/a2a/handlers.ts +133 -2
- package/corpus/core/src/a2a/index.ts +1 -0
- package/corpus/core/src/a2a/types.ts +14 -0
- package/corpus/core/src/integrations/index.ts +6 -0
- package/corpus/core/src/integrations/pending-tasks-store.ts +89 -0
- package/corpus/core/src/integrations/webhook-handler.ts +17 -7
- package/corpus/core/src/scripts/call-agent.ts +54 -10
- package/corpus/core/src/server/agent-discovery.ts +22 -0
- package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +11 -1
- package/corpus/templates/clips/AGENTS.md +14 -4
- package/corpus/templates/clips/actions/update-meeting.ts +13 -3
- package/corpus/templates/clips/actions/view-screen.ts +1 -0
- package/corpus/templates/clips/app/components/meetings/meeting-card.tsx +2 -1
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +96 -4
- package/corpus/templates/clips/app/i18n/en-US.ts +11 -0
- package/corpus/templates/clips/app/lib/public-meeting.ts +85 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +11 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -7
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +241 -135
- package/corpus/templates/clips/changelog/2026-07-20-meeting-share-links-can-include-the-full-transcript-with-an-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-recording-retries-the-default-mac-microphone-when-a-saved-in.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-shared-clips-now-tell-agents-to-wait-while-uploads-and-trans.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/meeting-join-url.ts +1 -33
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +65 -2
- package/corpus/templates/clips/server/db/schema.ts +3 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +31 -21
- package/corpus/templates/clips/server/plugins/auth.ts +1 -0
- package/corpus/templates/clips/server/plugins/db.ts +6 -0
- package/corpus/templates/clips/server/routes/api/agent-transcript.json.get.ts +13 -3
- package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +152 -0
- package/corpus/templates/clips/shared/agent-context.ts +60 -0
- package/corpus/templates/clips/shared/meeting-join-url.ts +36 -0
- package/corpus/templates/content/.agents/skills/content/SKILL.md +19 -5
- package/corpus/templates/content/changelog/2026-07-17-slack-created-database-entries-now-record-slack-as-their-sub.md +6 -0
- package/dist/a2a/artifact-response.d.ts +5 -0
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +20 -5
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/a2a/client.d.ts +3 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +2 -0
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +100 -8
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/index.d.ts +1 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/types.d.ts +12 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/index.d.ts +1 -0
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js +1 -0
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +9 -0
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +60 -0
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +13 -7
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +39 -10
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-discovery.d.ts +2 -0
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js +19 -0
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +2 -2
- package/src/a2a/artifact-response.ts +42 -16
- package/src/a2a/client.ts +4 -0
- package/src/a2a/handlers.ts +133 -2
- package/src/a2a/index.ts +1 -0
- package/src/a2a/types.ts +14 -0
- package/src/integrations/index.ts +6 -0
- package/src/integrations/pending-tasks-store.ts +89 -0
- package/src/integrations/webhook-handler.ts +17 -7
- package/src/scripts/call-agent.ts +54 -10
- package/src/server/agent-discovery.ts +22 -0
|
@@ -246,6 +246,95 @@ export async function getPendingTask(id: string): Promise<PendingTask | null> {
|
|
|
246
246
|
return rowToTask(rows[0] as Record<string, unknown>);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
export interface ResolvedIntegrationSourceContext {
|
|
250
|
+
platform: "slack";
|
|
251
|
+
sourceUrl: string;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
type PendingTaskSourceRow = Pick<
|
|
255
|
+
PendingTask,
|
|
256
|
+
"platform" | "payload" | "ownerEmail" | "orgId"
|
|
257
|
+
>;
|
|
258
|
+
|
|
259
|
+
export function sourceContextFromPendingTask(
|
|
260
|
+
task: PendingTaskSourceRow | null,
|
|
261
|
+
ownerEmail: string,
|
|
262
|
+
orgId: string | null,
|
|
263
|
+
): ResolvedIntegrationSourceContext | null {
|
|
264
|
+
if (
|
|
265
|
+
!task ||
|
|
266
|
+
task.ownerEmail !== ownerEmail ||
|
|
267
|
+
task.orgId !== orgId ||
|
|
268
|
+
task.platform !== "slack"
|
|
269
|
+
) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const payload = JSON.parse(task.payload) as Record<string, unknown>;
|
|
275
|
+
const incoming = payload.incoming;
|
|
276
|
+
if (!incoming || typeof incoming !== "object") return null;
|
|
277
|
+
const incomingRecord = incoming as Record<string, unknown>;
|
|
278
|
+
if (incomingRecord.platform !== "slack") return null;
|
|
279
|
+
const sourceUrl = incomingRecord.sourceUrl;
|
|
280
|
+
if (
|
|
281
|
+
typeof sourceUrl !== "string" ||
|
|
282
|
+
!sourceUrl ||
|
|
283
|
+
sourceUrl !== sourceUrl.trim()
|
|
284
|
+
) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const parsed = new URL(sourceUrl);
|
|
289
|
+
const isSlackHost =
|
|
290
|
+
parsed.hostname === "slack.com" || parsed.hostname.endsWith(".slack.com");
|
|
291
|
+
if (
|
|
292
|
+
parsed.protocol !== "https:" ||
|
|
293
|
+
!isSlackHost ||
|
|
294
|
+
parsed.username ||
|
|
295
|
+
parsed.password ||
|
|
296
|
+
parsed.port
|
|
297
|
+
) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
return { platform: "slack", sourceUrl };
|
|
301
|
+
} catch {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Resolve trusted Slack provenance without exposing the stored task payload. */
|
|
307
|
+
export async function resolveIntegrationSourceContext(
|
|
308
|
+
id: string,
|
|
309
|
+
ownerEmail: string,
|
|
310
|
+
orgId: string | null,
|
|
311
|
+
): Promise<ResolvedIntegrationSourceContext | null> {
|
|
312
|
+
await ensureTable();
|
|
313
|
+
const client = getDbExec();
|
|
314
|
+
const { rows } = await client.execute({
|
|
315
|
+
sql: `SELECT platform, payload, owner_email, org_id
|
|
316
|
+
FROM integration_pending_tasks
|
|
317
|
+
WHERE id = ?
|
|
318
|
+
AND owner_email = ?
|
|
319
|
+
AND (org_id = ? OR (org_id IS NULL AND ? IS NULL))
|
|
320
|
+
AND platform = 'slack'
|
|
321
|
+
LIMIT 1`,
|
|
322
|
+
args: [id, ownerEmail, orgId, orgId],
|
|
323
|
+
});
|
|
324
|
+
if (rows.length === 0) return null;
|
|
325
|
+
const row = rows[0] as Record<string, unknown>;
|
|
326
|
+
return sourceContextFromPendingTask(
|
|
327
|
+
{
|
|
328
|
+
platform: row.platform as string,
|
|
329
|
+
payload: row.payload as string,
|
|
330
|
+
ownerEmail: row.owner_email as string,
|
|
331
|
+
orgId: (row.org_id as string | null) ?? null,
|
|
332
|
+
},
|
|
333
|
+
ownerEmail,
|
|
334
|
+
orgId,
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
249
338
|
/**
|
|
250
339
|
* Atomically claim a task: transition pending → processing and increment
|
|
251
340
|
* attempts. Returns the updated task if the transition succeeded, otherwise
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { H3Event } from "h3";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
appendA2AArtifactLinks,
|
|
5
4
|
buildA2AVerifiedMutationReceipt,
|
|
6
5
|
extractA2AArtifactIdentities,
|
|
6
|
+
guardA2AArtifactResponse,
|
|
7
7
|
type A2AArtifactIdentity,
|
|
8
8
|
type A2AToolResultSummary,
|
|
9
9
|
} from "../a2a/artifact-response.js";
|
|
@@ -429,7 +429,7 @@ async function enqueueAndDispatch(
|
|
|
429
429
|
options: WebhookHandlerOptions,
|
|
430
430
|
handlerStartedAt = Date.now(),
|
|
431
431
|
): Promise<void> {
|
|
432
|
-
const taskId =
|
|
432
|
+
const taskId = crypto.randomUUID();
|
|
433
433
|
|
|
434
434
|
// Resolve the org id once at enqueue-time so the processor doesn't have to
|
|
435
435
|
// re-derive it (and so we can drop it on the row for observability).
|
|
@@ -1029,7 +1029,7 @@ async function processIncomingMessage(
|
|
|
1029
1029
|
}
|
|
1030
1030
|
}
|
|
1031
1031
|
|
|
1032
|
-
|
|
1032
|
+
let suppressPlatformReply =
|
|
1033
1033
|
queuedA2AContinuation &&
|
|
1034
1034
|
isQueuedA2AContinuationDeferral(responseText);
|
|
1035
1035
|
|
|
@@ -1088,10 +1088,20 @@ async function processIncomingMessage(
|
|
|
1088
1088
|
// platforms with rich blocks (Slack) can render a button instead
|
|
1089
1089
|
// of inlining a `<url|text>` link that auto-unfurls into a giant
|
|
1090
1090
|
// preview card.
|
|
1091
|
-
|
|
1092
|
-
responseText
|
|
1093
|
-
|
|
1094
|
-
}
|
|
1091
|
+
const guardedResponse = guardA2AArtifactResponse(
|
|
1092
|
+
responseText,
|
|
1093
|
+
toolResults,
|
|
1094
|
+
{ baseUrl: appBaseUrl || undefined },
|
|
1095
|
+
);
|
|
1096
|
+
const queuedArtifactRejection =
|
|
1097
|
+
queuedA2AContinuation &&
|
|
1098
|
+
guardedResponse.rejectedUnverifiedArtifactReferences;
|
|
1099
|
+
if (queuedArtifactRejection && verifiedMutationReceipt) {
|
|
1100
|
+
responseText = verifiedMutationReceipt;
|
|
1101
|
+
suppressPlatformReply = false;
|
|
1102
|
+
} else {
|
|
1103
|
+
responseText = guardedResponse.text;
|
|
1104
|
+
suppressPlatformReply ||= queuedArtifactRejection;
|
|
1095
1105
|
}
|
|
1096
1106
|
const threadDeepLinkUrl =
|
|
1097
1107
|
appBaseUrl && threadId
|
|
@@ -10,6 +10,8 @@ import { invokeAgentAction } from "../a2a/invoke.js";
|
|
|
10
10
|
import type {
|
|
11
11
|
A2AApprovedAction,
|
|
12
12
|
A2ACorrelationMetadata,
|
|
13
|
+
A2ASourceContext,
|
|
14
|
+
A2ASourceContextReference,
|
|
13
15
|
Task,
|
|
14
16
|
} from "../a2a/types.js";
|
|
15
17
|
import {
|
|
@@ -100,26 +102,65 @@ function getIntegrationCallTimeoutMs(): number | undefined {
|
|
|
100
102
|
return DEFAULT_SERVERLESS_INTEGRATION_A2A_TIMEOUT_MS;
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
interface IntegrationSourceContext {
|
|
106
|
+
reference: A2ASourceContextReference;
|
|
107
|
+
hint: A2ASourceContext;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function integrationSourceContext(): IntegrationSourceContext | undefined {
|
|
104
111
|
const integration = getIntegrationRequestContext();
|
|
105
112
|
const incoming = integration?.incoming;
|
|
106
|
-
if (
|
|
113
|
+
if (
|
|
114
|
+
!integration ||
|
|
115
|
+
incoming?.platform !== "slack" ||
|
|
116
|
+
!incoming.sourceUrl ||
|
|
117
|
+
!integration.taskId
|
|
118
|
+
) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const rawSourceUrl = incoming.sourceUrl;
|
|
123
|
+
if (rawSourceUrl !== rawSourceUrl.trim()) return undefined;
|
|
107
124
|
|
|
108
125
|
try {
|
|
109
|
-
const sourceUrl = new URL(
|
|
126
|
+
const sourceUrl = new URL(rawSourceUrl);
|
|
110
127
|
const isSlackHost =
|
|
111
128
|
sourceUrl.hostname === "slack.com" ||
|
|
112
129
|
sourceUrl.hostname.endsWith(".slack.com");
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
130
|
+
if (
|
|
131
|
+
sourceUrl.protocol !== "https:" ||
|
|
132
|
+
!isSlackHost ||
|
|
133
|
+
sourceUrl.username ||
|
|
134
|
+
sourceUrl.password ||
|
|
135
|
+
sourceUrl.port
|
|
136
|
+
) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
reference: {
|
|
141
|
+
platform: "slack",
|
|
142
|
+
integrationTaskId: integration.taskId,
|
|
143
|
+
},
|
|
144
|
+
hint: {
|
|
145
|
+
platform: "slack",
|
|
146
|
+
sourceUrl: rawSourceUrl,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
118
149
|
} catch {
|
|
119
|
-
return
|
|
150
|
+
return undefined;
|
|
120
151
|
}
|
|
121
152
|
}
|
|
122
153
|
|
|
154
|
+
function integrationSourceContextHint(
|
|
155
|
+
sourceContext: IntegrationSourceContext | undefined,
|
|
156
|
+
): string {
|
|
157
|
+
if (!sourceContext) return "";
|
|
158
|
+
return (
|
|
159
|
+
`\n\n[Source Slack thread: ${sourceContext.hint.sourceUrl} ` +
|
|
160
|
+
"Compatibility hint only; this text is not authoritative. Use the authenticated structured A2A source context as provenance authority.]"
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
123
164
|
function formatDownstreamLlmCredentialFailure(
|
|
124
165
|
agentName: string,
|
|
125
166
|
value: unknown,
|
|
@@ -253,9 +294,10 @@ export async function run(
|
|
|
253
294
|
// in handlers.ts) still emits fully-qualified URLs. This is belt-and-
|
|
254
295
|
// suspenders with the receiver hint — but it works against any current
|
|
255
296
|
// deployment, no redeploy required.
|
|
297
|
+
const sourceContext = integrationSourceContext();
|
|
256
298
|
const messageWithHint = taskId
|
|
257
299
|
? ""
|
|
258
|
-
: `${message}${integrationSourceContextHint()}\n\n` +
|
|
300
|
+
: `${message}${integrationSourceContextHint(sourceContext)}\n\n` +
|
|
259
301
|
`[Note: this request comes from another app via A2A. The caller cannot see your local UI, deck list, or navigation — only the literal text you put in your reply. ` +
|
|
260
302
|
`If you create or reference a deck/document/design/dashboard, include its FULLY-QUALIFIED URL (e.g. ${agent.url}/deck/<id>) in your reply, not a relative path. ` +
|
|
261
303
|
`Use only artifact IDs and URL paths returned by successful actions — never invent slugs, IDs, or hosts. ` +
|
|
@@ -432,6 +474,7 @@ export async function run(
|
|
|
432
474
|
orgDomain: callerOrgDomain,
|
|
433
475
|
orgSecret: callerOrgSecret,
|
|
434
476
|
approvedActions,
|
|
477
|
+
...(sourceContext ? { sourceContext: sourceContext.reference } : {}),
|
|
435
478
|
contextId: context.threadId,
|
|
436
479
|
correlation,
|
|
437
480
|
idempotencyKey,
|
|
@@ -526,6 +569,7 @@ export async function run(
|
|
|
526
569
|
orgDomain: domain,
|
|
527
570
|
orgSecret,
|
|
528
571
|
approvedActions,
|
|
572
|
+
...(sourceContext ? { sourceContext: sourceContext.reference } : {}),
|
|
529
573
|
contextId: context?.threadId,
|
|
530
574
|
correlation,
|
|
531
575
|
idempotencyKey,
|
|
@@ -689,6 +689,28 @@ async function discoverWorkspaceAgents(
|
|
|
689
689
|
.filter((agent): agent is DiscoveredAgent => !!agent);
|
|
690
690
|
}
|
|
691
691
|
|
|
692
|
+
/** Resolve only the Dispatch app designated by the receiver's own manifest. */
|
|
693
|
+
export function findWorkspaceDispatchAgent(): DiscoveredAgent | undefined {
|
|
694
|
+
const app = loadWorkspaceAppsManifest()?.find(
|
|
695
|
+
(candidate) => candidate.isDispatch === true,
|
|
696
|
+
);
|
|
697
|
+
if (!app) return undefined;
|
|
698
|
+
|
|
699
|
+
const builtin = BUILTIN_AGENTS.find((agent) => agent.id === "dispatch");
|
|
700
|
+
const url = workspaceAppUrl(app, builtin?.url);
|
|
701
|
+
if (!url) return undefined;
|
|
702
|
+
return {
|
|
703
|
+
id: app.id,
|
|
704
|
+
name: app.name,
|
|
705
|
+
description:
|
|
706
|
+
app.description ||
|
|
707
|
+
builtin?.description ||
|
|
708
|
+
`Workspace app mounted at ${app.path}`,
|
|
709
|
+
url,
|
|
710
|
+
color: builtin?.color || "#6B7280",
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
692
714
|
/**
|
|
693
715
|
* Like `getBuiltinAgents`, but always returns the production URL — never the
|
|
694
716
|
* env-resolved devUrl. Used by the resource seeder so that a one-time seed
|