@agent-native/core 0.107.1 → 0.107.2
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/core/CHANGELOG.md +6 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/artifact-response.ts +32 -10
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +107 -3
- package/corpus/core/src/integrations/pending-tasks-store.ts +98 -1
- package/corpus/core/src/integrations/plugin.ts +129 -4
- package/corpus/core/src/integrations/webhook-handler.ts +339 -36
- package/corpus/core/src/server/agent-chat-plugin.ts +93 -8
- package/dist/a2a/artifact-response.d.ts +5 -1
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +18 -12
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/integrations/a2a-continuation-processor.js +62 -5
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +3 -0
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +75 -1
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +81 -5
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts +23 -2
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +257 -35
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-chat-plugin.d.ts +6 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +71 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "h3";
|
|
15
15
|
|
|
16
16
|
import {
|
|
17
|
+
appendA2AArtifactLinks,
|
|
17
18
|
buildA2ARecoverableArtifactMessage,
|
|
18
19
|
type A2AToolResultSummary,
|
|
19
20
|
} from "../a2a/artifact-response.js";
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
createA2AApproval,
|
|
28
29
|
updateTaskStatusMessage,
|
|
29
30
|
} from "../a2a/task-store.js";
|
|
31
|
+
import type { Message as A2AMessage } from "../a2a/types.js";
|
|
30
32
|
import type { ActionHttpConfig } from "../action.js";
|
|
31
33
|
import {
|
|
32
34
|
canUpdateAgentAppModelDefaultSettings,
|
|
@@ -275,6 +277,74 @@ export { loadRunCodeToolEntries };
|
|
|
275
277
|
export { shouldDisableRecurringJobsRuntime };
|
|
276
278
|
export { finalizeClaimedAgentChatProcessRunFailure };
|
|
277
279
|
|
|
280
|
+
export function createSerializedA2ATaskStatusWriter(
|
|
281
|
+
taskId: string,
|
|
282
|
+
writeStatus: (
|
|
283
|
+
taskId: string,
|
|
284
|
+
message: A2AMessage,
|
|
285
|
+
) => Promise<void> = updateTaskStatusMessage,
|
|
286
|
+
onError: (error: unknown) => void = (error) => {
|
|
287
|
+
console.error(
|
|
288
|
+
`[A2A] Failed to persist recoverable artifact message for task ${taskId}:`,
|
|
289
|
+
error,
|
|
290
|
+
);
|
|
291
|
+
},
|
|
292
|
+
): {
|
|
293
|
+
enqueue: (message: A2AMessage) => void;
|
|
294
|
+
flush: () => Promise<void>;
|
|
295
|
+
} {
|
|
296
|
+
const maxAttempts = 3;
|
|
297
|
+
let latestWrite: Promise<void> = Promise.resolve();
|
|
298
|
+
|
|
299
|
+
const persistWithRetry = async (message: A2AMessage): Promise<void> => {
|
|
300
|
+
let lastError: unknown;
|
|
301
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
302
|
+
try {
|
|
303
|
+
await writeStatus(taskId, message);
|
|
304
|
+
return;
|
|
305
|
+
} catch (error) {
|
|
306
|
+
lastError = error;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
onError(lastError);
|
|
311
|
+
} catch {
|
|
312
|
+
// The durable-write error below remains the authoritative failure.
|
|
313
|
+
}
|
|
314
|
+
throw lastError;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
enqueue(message) {
|
|
319
|
+
// A newer checkpoint supersedes an earlier failed checkpoint, so keep
|
|
320
|
+
// the queue moving. flush() still rejects when the latest write itself
|
|
321
|
+
// cannot be made durable after bounded retries.
|
|
322
|
+
latestWrite = latestWrite
|
|
323
|
+
.catch(() => undefined)
|
|
324
|
+
.then(() => {
|
|
325
|
+
return persistWithRetry(message);
|
|
326
|
+
});
|
|
327
|
+
},
|
|
328
|
+
flush() {
|
|
329
|
+
return latestWrite;
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export async function resolveA2ARecoverableArtifactSecret(
|
|
335
|
+
orgId: string | null | undefined = getRequestOrgId(),
|
|
336
|
+
): Promise<string | undefined> {
|
|
337
|
+
const globalSecret = process.env.A2A_SECRET?.trim();
|
|
338
|
+
if (globalSecret) return globalSecret;
|
|
339
|
+
if (!orgId) return undefined;
|
|
340
|
+
try {
|
|
341
|
+
const { getOrgA2ASecret } = await import("../org/context.js");
|
|
342
|
+
return (await getOrgA2ASecret(orgId))?.trim() || undefined;
|
|
343
|
+
} catch {
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
278
348
|
export function buildLeanRunPolicyPrompt(
|
|
279
349
|
codeEditingSurfaceRestriction: string,
|
|
280
350
|
prodCodeExecPromptNote: string,
|
|
@@ -1468,6 +1538,10 @@ export function createAgentChatPlugin(
|
|
|
1468
1538
|
const a2aEvents: AgentChatEvent[] = [];
|
|
1469
1539
|
const a2aToolResults: A2AToolResultSummary[] = [];
|
|
1470
1540
|
let lastRecoverableArtifactText = "";
|
|
1541
|
+
const recoverableArtifactSecret =
|
|
1542
|
+
await resolveA2ARecoverableArtifactSecret();
|
|
1543
|
+
const recoverableArtifactStatusWriter =
|
|
1544
|
+
createSerializedA2ATaskStatusWriter(context.taskId);
|
|
1471
1545
|
const controller = new AbortController();
|
|
1472
1546
|
|
|
1473
1547
|
console.log(
|
|
@@ -1504,16 +1578,28 @@ export function createAgentChatPlugin(
|
|
|
1504
1578
|
isError: event.isError,
|
|
1505
1579
|
completedSideEffect: event.completedSideEffect,
|
|
1506
1580
|
});
|
|
1507
|
-
const
|
|
1581
|
+
const artifactBaseUrl = resolveArtifactBaseUrl(context.event);
|
|
1582
|
+
const recoverableArtifactMessage =
|
|
1508
1583
|
buildA2ARecoverableArtifactMessage(a2aToolResults, {
|
|
1509
|
-
baseUrl:
|
|
1584
|
+
baseUrl: artifactBaseUrl,
|
|
1510
1585
|
});
|
|
1586
|
+
const recoverableArtifactText = recoverableArtifactMessage
|
|
1587
|
+
? appendA2AArtifactLinks(
|
|
1588
|
+
recoverableArtifactMessage,
|
|
1589
|
+
a2aToolResults,
|
|
1590
|
+
{
|
|
1591
|
+
baseUrl: artifactBaseUrl,
|
|
1592
|
+
includePersistedArtifactMarker: true,
|
|
1593
|
+
persistedArtifactSecret: recoverableArtifactSecret,
|
|
1594
|
+
},
|
|
1595
|
+
)
|
|
1596
|
+
: null;
|
|
1511
1597
|
if (
|
|
1512
1598
|
recoverableArtifactText &&
|
|
1513
1599
|
recoverableArtifactText !== lastRecoverableArtifactText
|
|
1514
1600
|
) {
|
|
1515
1601
|
lastRecoverableArtifactText = recoverableArtifactText;
|
|
1516
|
-
|
|
1602
|
+
recoverableArtifactStatusWriter.enqueue({
|
|
1517
1603
|
role: "agent",
|
|
1518
1604
|
metadata: { agentNativeRecoverableArtifacts: true },
|
|
1519
1605
|
parts: [
|
|
@@ -1522,11 +1608,6 @@ export function createAgentChatPlugin(
|
|
|
1522
1608
|
text: recoverableArtifactText,
|
|
1523
1609
|
},
|
|
1524
1610
|
],
|
|
1525
|
-
}).catch((err) => {
|
|
1526
|
-
console.error(
|
|
1527
|
-
`[A2A] Failed to persist recoverable artifact message for task ${context.taskId}:`,
|
|
1528
|
-
err,
|
|
1529
|
-
);
|
|
1530
1611
|
});
|
|
1531
1612
|
}
|
|
1532
1613
|
} else if (event.type === "error") {
|
|
@@ -1548,6 +1629,10 @@ export function createAgentChatPlugin(
|
|
|
1548
1629
|
},
|
|
1549
1630
|
);
|
|
1550
1631
|
|
|
1632
|
+
// The continuation can observe terminal output immediately, so make
|
|
1633
|
+
// its latest mutation checkpoint durable first.
|
|
1634
|
+
await recoverableArtifactStatusWriter.flush();
|
|
1635
|
+
|
|
1551
1636
|
const approval = [...a2aEvents]
|
|
1552
1637
|
.reverse()
|
|
1553
1638
|
.find(
|
|
@@ -8,6 +8,10 @@ export interface A2AArtifactResponseOptions {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
includeReferencedArtifacts?: boolean;
|
|
10
10
|
includePersistedArtifactMarker?: boolean;
|
|
11
|
+
persistedArtifactSecret?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface A2AArtifactIdentityOptions {
|
|
14
|
+
persistedArtifactSecrets?: readonly string[];
|
|
11
15
|
}
|
|
12
16
|
export interface A2AArtifactIdentity {
|
|
13
17
|
resourceType: "document" | "deck" | "dashboard" | "analysis" | "image" | "design" | "monitor" | "form";
|
|
@@ -22,7 +26,7 @@ export declare function stripA2APersistedArtifactMarkers(text: string): string;
|
|
|
22
26
|
* The ledger deliberately excludes raw tool results so it is safe to retain in
|
|
23
27
|
* long-lived thread context and stable even when a resource is later renamed.
|
|
24
28
|
*/
|
|
25
|
-
export declare function extractA2AArtifactIdentities(results: A2AToolResultSummary[]): A2AArtifactIdentity[];
|
|
29
|
+
export declare function extractA2AArtifactIdentities(results: A2AToolResultSummary[], options?: A2AArtifactIdentityOptions): A2AArtifactIdentity[];
|
|
26
30
|
export declare function appendA2AArtifactLinks(responseText: string, toolResults: A2AToolResultSummary[], options?: A2AArtifactResponseOptions): string;
|
|
27
31
|
export declare function buildA2ARecoverableArtifactMessage(toolResults: A2AToolResultSummary[], options?: A2AArtifactResponseOptions): string | null;
|
|
28
32
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-response.d.ts","sourceRoot":"","sources":["../../src/a2a/artifact-response.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,8BAA8B,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"artifact-response.d.ts","sourceRoot":"","sources":["../../src/a2a/artifact-response.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,0BAA0B;IACzC,wBAAwB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EACR,UAAU,GACV,MAAM,GACN,WAAW,GACX,UAAU,GACV,OAAO,GACP,QAAQ,GACR,SAAS,GACT,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA4GD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErE;AA4uBD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,oBAAoB,EAAE,EAC/B,OAAO,GAAE,0BAA+B,GACvC,mBAAmB,EAAE,CAsGvB;AA2YD,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,CAkJR;AAED,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,GAAG,IAAI,CA8Bf;AAmCD;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,GAAG,IAAI,CAqBf"}
|
|
@@ -39,19 +39,23 @@ const ARTIFACT_RESOURCE_TYPES = new Set([
|
|
|
39
39
|
"monitor",
|
|
40
40
|
"form",
|
|
41
41
|
]);
|
|
42
|
-
function persistedArtifactIdentitiesFromMarker(result
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
function persistedArtifactIdentitiesFromMarker(result, secrets = process.env.A2A_SECRET
|
|
43
|
+
? [process.env.A2A_SECRET]
|
|
44
|
+
: []) {
|
|
45
|
+
if (secrets.length === 0)
|
|
45
46
|
return [];
|
|
46
47
|
const match = result.match(/<!--\s*agent-native:persisted-artifacts=([A-Za-z0-9_-]+)\.([a-f0-9]{64})\s*-->/);
|
|
47
48
|
if (!match)
|
|
48
49
|
return [];
|
|
49
50
|
try {
|
|
50
51
|
const payload = match[1];
|
|
51
|
-
const expected = createHmac("sha256", secret).update(payload).digest();
|
|
52
52
|
const supplied = Buffer.from(match[2], "hex");
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const verified = secrets.some((secret) => {
|
|
54
|
+
const expected = createHmac("sha256", secret).update(payload).digest();
|
|
55
|
+
return (supplied.length === expected.length &&
|
|
56
|
+
timingSafeEqual(supplied, expected));
|
|
57
|
+
});
|
|
58
|
+
if (!verified) {
|
|
55
59
|
return [];
|
|
56
60
|
}
|
|
57
61
|
const parsed = JSON.parse(Buffer.from(payload, "base64url").toString());
|
|
@@ -71,9 +75,11 @@ function persistedArtifactIdentitiesFromMarker(result) {
|
|
|
71
75
|
return [];
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
|
-
function withPersistedArtifactMarker(text, toolResults) {
|
|
75
|
-
const
|
|
76
|
-
const
|
|
78
|
+
function withPersistedArtifactMarker(text, toolResults, secret = process.env.A2A_SECRET) {
|
|
79
|
+
const verificationSecrets = [secret, process.env.A2A_SECRET].filter((value, index, values) => !!value && values.indexOf(value) === index);
|
|
80
|
+
const identities = extractA2AArtifactIdentities(toolResults, {
|
|
81
|
+
persistedArtifactSecrets: verificationSecrets,
|
|
82
|
+
}).slice(0, 12);
|
|
77
83
|
if (identities.length === 0 || !secret)
|
|
78
84
|
return text;
|
|
79
85
|
const payload = Buffer.from(JSON.stringify(identities)).toString("base64url");
|
|
@@ -667,7 +673,7 @@ function collectArtifacts(results) {
|
|
|
667
673
|
* The ledger deliberately excludes raw tool results so it is safe to retain in
|
|
668
674
|
* long-lived thread context and stable even when a resource is later renamed.
|
|
669
675
|
*/
|
|
670
|
-
export function extractA2AArtifactIdentities(results) {
|
|
676
|
+
export function extractA2AArtifactIdentities(results, options = {}) {
|
|
671
677
|
const identities = new Map();
|
|
672
678
|
const remember = (identity) => {
|
|
673
679
|
identities.set(`${identity.resourceType}:${identity.id}`, identity);
|
|
@@ -676,7 +682,7 @@ export function extractA2AArtifactIdentities(results) {
|
|
|
676
682
|
if (result.isError === true || result.completedSideEffect === false)
|
|
677
683
|
continue;
|
|
678
684
|
if (result.tool === "call-agent") {
|
|
679
|
-
for (const identity of persistedArtifactIdentitiesFromMarker(result.result)) {
|
|
685
|
+
for (const identity of persistedArtifactIdentitiesFromMarker(result.result, options.persistedArtifactSecrets)) {
|
|
680
686
|
remember({ ...identity, sourceAction: "call-agent" });
|
|
681
687
|
}
|
|
682
688
|
continue;
|
|
@@ -1070,7 +1076,7 @@ export function appendA2AArtifactLinks(responseText, toolResults, options = {})
|
|
|
1070
1076
|
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
1071
1077
|
const includeReferencedArtifacts = options.includeReferencedArtifacts ?? false;
|
|
1072
1078
|
const finalize = (value) => options.includePersistedArtifactMarker
|
|
1073
|
-
? withPersistedArtifactMarker(value, toolResults)
|
|
1079
|
+
? withPersistedArtifactMarker(value, toolResults, options.persistedArtifactSecret ?? process.env.A2A_SECRET)
|
|
1074
1080
|
: value;
|
|
1075
1081
|
const { documents, decks, dashboards, analyses, images, designShells, generatedDesigns, monitors, forms, } = collectArtifacts(toolResults);
|
|
1076
1082
|
const generatedDesignIds = new Set(generatedDesigns.map((design) => design.id));
|