@agent-native/core 0.122.1 → 0.122.3
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/README.md +1 -13
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +65 -1
- package/corpus/core/src/agent/run-loop-with-resume.ts +12 -0
- package/corpus/core/src/agent/run-store.ts +61 -1
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +182 -0
- package/corpus/core/src/integrations/a2a-continuations-store.ts +122 -12
- package/corpus/core/src/integrations/integration-campaign-recovery.ts +127 -0
- package/corpus/core/src/integrations/integration-campaigns-store.ts +1039 -0
- package/corpus/core/src/integrations/integration-durable-dispatch.ts +28 -3
- package/corpus/core/src/integrations/pending-tasks-retry-job.ts +8 -0
- package/corpus/core/src/integrations/plugin.ts +453 -35
- package/corpus/core/src/integrations/webhook-handler.ts +469 -11
- package/corpus/core/src/server/builder-design-systems.ts +1 -1
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +15 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -3
- package/corpus/templates/analytics/changelog/2026-07-25-analytics-dashboards-and-scheduled-reports-are-faster-and-mo.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +12 -0
- package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +8 -4
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +136 -5
- package/corpus/templates/analytics/server/lib/dashboard-time-scope.ts +250 -1
- package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +167 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +34 -9
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +105 -23
- package/corpus/templates/analytics/server/lib/first-party-unbounded-panel-repair.ts +169 -0
- package/corpus/templates/analytics/server/plugins/db.ts +41 -1
- package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +6 -3
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +7 -3
- package/corpus/templates/content/app/components/editor/body-hydration.ts +10 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +1 -0
- package/corpus/templates/content/app/root.tsx +12 -1
- package/corpus/templates/content/changelog/2026-07-23-new-pages-open-immediately-while-slow-network-work-continues.md +6 -0
- package/corpus/templates/content/changelog/2026-07-25-database-preview-actions-open-reliably.md +6 -0
- package/corpus/templates/content/e2e/playwright.config.ts +1 -1
- package/corpus/templates/design/actions/edit-design.ts +66 -27
- package/corpus/templates/design/changelog/2026-07-25-design-edits-retry-concurrent-changes.md +6 -0
- package/corpus/templates/design/server/source-workspace.ts +5 -1
- package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +6 -4
- package/corpus/templates/forms/actions/create-form.ts +5 -1
- package/corpus/templates/forms/actions/export-responses.ts +22 -11
- package/corpus/templates/forms/actions/update-form.ts +5 -1
- package/corpus/templates/forms/changelog/2026-07-25-fields-can-be-created-without-ids.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-25-response-exports-use-file-storage.md +6 -0
- package/corpus/templates/forms/server/lib/validate-fields.ts +43 -0
- package/corpus/templates/slides/actions/extract-pdf.ts +4 -4
- package/corpus/templates/slides/actions/import-file.ts +3 -4
- package/corpus/templates/slides/changelog/2026-07-25-gemini-image-models-updated.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-25-pdf-imports-tolerate-missing-canvas.md +6 -0
- package/corpus/templates/slides/server/handlers/image-providers/gemini.ts +5 -2
- package/corpus/templates/slides/server/lib/pdf-parse-setup.ts +150 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +63 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +7 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +7 -0
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +49 -0
- package/dist/agent/run-store.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 +2 -2
- package/dist/integrations/a2a-continuation-processor.d.ts +14 -0
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +134 -1
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/a2a-continuations-store.d.ts +23 -0
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +99 -13
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/integration-campaign-recovery.d.ts +16 -0
- package/dist/integrations/integration-campaign-recovery.d.ts.map +1 -0
- package/dist/integrations/integration-campaign-recovery.js +94 -0
- package/dist/integrations/integration-campaign-recovery.js.map +1 -0
- package/dist/integrations/integration-campaigns-store.d.ts +121 -0
- package/dist/integrations/integration-campaigns-store.d.ts.map +1 -0
- package/dist/integrations/integration-campaigns-store.js +784 -0
- package/dist/integrations/integration-campaigns-store.js.map +1 -0
- package/dist/integrations/integration-durable-dispatch.d.ts +3 -0
- package/dist/integrations/integration-durable-dispatch.d.ts.map +1 -1
- package/dist/integrations/integration-durable-dispatch.js +22 -3
- package/dist/integrations/integration-durable-dispatch.js.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.js +6 -0
- package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +325 -18
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts +16 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +368 -13
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/builder-design-systems.js +1 -1
- package/dist/server/builder-design-systems.js.map +1 -1
- package/package.json +3 -3
- package/src/agent/production-agent.ts +65 -1
- package/src/agent/run-loop-with-resume.ts +12 -0
- package/src/agent/run-store.ts +61 -1
- package/src/integrations/a2a-continuation-processor.ts +182 -0
- package/src/integrations/a2a-continuations-store.ts +122 -12
- package/src/integrations/integration-campaign-recovery.ts +127 -0
- package/src/integrations/integration-campaigns-store.ts +1039 -0
- package/src/integrations/integration-durable-dispatch.ts +28 -3
- package/src/integrations/pending-tasks-retry-job.ts +8 -0
- package/src/integrations/plugin.ts +453 -35
- package/src/integrations/webhook-handler.ts +469 -11
- package/src/server/builder-design-systems.ts +1 -1
|
@@ -418,6 +418,35 @@ export async function getA2AContinuationForIntegrationTask(
|
|
|
418
418
|
return rows[0] ? rowToContinuation(rows[0] as Record<string, unknown>) : null;
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
export async function hasActiveA2AContinuationsForIntegrationTask(
|
|
422
|
+
integrationTaskId: string,
|
|
423
|
+
): Promise<boolean> {
|
|
424
|
+
await ensureTable();
|
|
425
|
+
const { rows } = await getDbExec().execute({
|
|
426
|
+
sql: `SELECT 1 AS active FROM integration_a2a_continuations
|
|
427
|
+
WHERE integration_task_id = ?
|
|
428
|
+
AND status IN ('pending', 'processing', 'delivering')
|
|
429
|
+
LIMIT 1`,
|
|
430
|
+
args: [integrationTaskId],
|
|
431
|
+
});
|
|
432
|
+
return rows.length > 0;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export async function failA2AContinuationsForIntegrationTask(
|
|
436
|
+
integrationTaskId: string,
|
|
437
|
+
errorMessage: string,
|
|
438
|
+
): Promise<void> {
|
|
439
|
+
await ensureTable();
|
|
440
|
+
const now = Date.now();
|
|
441
|
+
await getDbExec().execute({
|
|
442
|
+
sql: `UPDATE integration_a2a_continuations
|
|
443
|
+
SET status = 'failed', error_message = ?, updated_at = ?, completed_at = ?
|
|
444
|
+
WHERE integration_task_id = ?
|
|
445
|
+
AND status IN ('pending', 'processing', 'delivering')`,
|
|
446
|
+
args: [errorMessage.slice(0, 2000), now, now, integrationTaskId],
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
421
450
|
export async function getA2AContinuationsForIntegrationTaskAgent(
|
|
422
451
|
integrationTaskId: string,
|
|
423
452
|
agentUrl: string,
|
|
@@ -532,40 +561,121 @@ export async function claimA2AContinuation(
|
|
|
532
561
|
export async function claimDueA2AContinuations(
|
|
533
562
|
limit = 5,
|
|
534
563
|
): Promise<A2AContinuation[]> {
|
|
564
|
+
const ids = await recoverDueA2AContinuationIds(limit);
|
|
565
|
+
const claimed: A2AContinuation[] = [];
|
|
566
|
+
for (const id of ids) {
|
|
567
|
+
const continuation = await claimA2AContinuation(id);
|
|
568
|
+
if (continuation) claimed.push(continuation);
|
|
569
|
+
}
|
|
570
|
+
return claimed;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Makes stale leases eligible again and returns a bounded set of due ids.
|
|
575
|
+
*
|
|
576
|
+
* This intentionally does not claim anything. Durable schedulers use it only
|
|
577
|
+
* to wake the normal processor, whose atomic claim remains the sole progress
|
|
578
|
+
* and delivery owner under overlapping scheduler/self-dispatch executions.
|
|
579
|
+
*/
|
|
580
|
+
export async function recoverDueA2AContinuationIds(
|
|
581
|
+
limit = 5,
|
|
582
|
+
integrationTaskIds?: string[],
|
|
583
|
+
): Promise<string[]> {
|
|
535
584
|
await ensureTable();
|
|
536
585
|
const client = getDbExec();
|
|
537
586
|
const now = Date.now();
|
|
538
587
|
const processingCutoff = now - PROCESSING_STUCK_AFTER_MS;
|
|
539
588
|
const staleNextCheckCutoff = now - PROCESSING_NEXT_CHECK_STALE_AFTER_MS;
|
|
589
|
+
if (integrationTaskIds && integrationTaskIds.length === 0) return [];
|
|
590
|
+
const taskFilter = integrationTaskIds?.length
|
|
591
|
+
? ` AND integration_task_id IN (${integrationTaskIds.map(() => "?").join(", ")})`
|
|
592
|
+
: "";
|
|
593
|
+
const taskArgs = integrationTaskIds ?? [];
|
|
540
594
|
// If a processor dies while holding a delivery claim, retry the final send.
|
|
541
595
|
// The stale cutoff preserves the in-flight delivery guard while keeping
|
|
542
596
|
// final integration replies at-least-once.
|
|
543
597
|
await client.execute({
|
|
544
598
|
sql: `UPDATE integration_a2a_continuations
|
|
545
599
|
SET status = ?, next_check_at = ?, updated_at = ?
|
|
546
|
-
WHERE status = 'delivering' AND updated_at <=
|
|
547
|
-
args: ["pending", now, now, now - 5 * 60 * 1000],
|
|
600
|
+
WHERE status = 'delivering' AND updated_at <= ?${taskFilter}`,
|
|
601
|
+
args: ["pending", now, now, now - 5 * 60 * 1000, ...taskArgs],
|
|
548
602
|
});
|
|
549
603
|
await client.execute({
|
|
550
604
|
sql: `UPDATE integration_a2a_continuations
|
|
551
605
|
SET status = ?, next_check_at = ?, updated_at = ?
|
|
552
606
|
WHERE status = 'processing'
|
|
553
|
-
AND (updated_at <= ? OR next_check_at <= ?)`,
|
|
554
|
-
args: [
|
|
607
|
+
AND (updated_at <= ? OR next_check_at <= ?)${taskFilter}`,
|
|
608
|
+
args: [
|
|
609
|
+
"pending",
|
|
610
|
+
now,
|
|
611
|
+
now,
|
|
612
|
+
processingCutoff,
|
|
613
|
+
staleNextCheckCutoff,
|
|
614
|
+
...taskArgs,
|
|
615
|
+
],
|
|
555
616
|
});
|
|
556
617
|
const { rows } = await client.execute({
|
|
557
618
|
sql: `SELECT id FROM integration_a2a_continuations
|
|
558
|
-
WHERE status = 'pending' AND next_check_at <=
|
|
619
|
+
WHERE status = 'pending' AND next_check_at <= ?${taskFilter}
|
|
559
620
|
ORDER BY next_check_at ASC
|
|
560
621
|
LIMIT ?`,
|
|
561
|
-
args: [now, limit],
|
|
622
|
+
args: [now, ...taskArgs, limit],
|
|
562
623
|
});
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
624
|
+
return rows.map((row) => row.id as string);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export async function listRecoverableA2AIntegrationTaskIds(
|
|
628
|
+
limit = 50,
|
|
629
|
+
): Promise<string[]> {
|
|
630
|
+
const tasks = await listRecoverableA2AIntegrationTasks(limit);
|
|
631
|
+
return tasks.map((task) => task.id);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export interface RecoverableA2AIntegrationTask {
|
|
635
|
+
id: string;
|
|
636
|
+
platform: string;
|
|
637
|
+
externalThreadId: string;
|
|
638
|
+
dispatchScope: string | null;
|
|
639
|
+
status: string;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Read due continuation owners and their rollout scope in one query. Recovery
|
|
644
|
+
* can filter the canary in memory without an N+1 pending-task lookup loop.
|
|
645
|
+
*/
|
|
646
|
+
export async function listRecoverableA2AIntegrationTasks(
|
|
647
|
+
limit = 50,
|
|
648
|
+
): Promise<RecoverableA2AIntegrationTask[]> {
|
|
649
|
+
await ensureTable();
|
|
650
|
+
const now = Date.now();
|
|
651
|
+
const { rows } = await getDbExec().execute({
|
|
652
|
+
sql: `SELECT DISTINCT c.integration_task_id, t.platform,
|
|
653
|
+
t.external_thread_id, t.dispatch_scope, t.status
|
|
654
|
+
FROM integration_a2a_continuations c
|
|
655
|
+
INNER JOIN integration_pending_tasks t
|
|
656
|
+
ON t.id = c.integration_task_id
|
|
657
|
+
WHERE t.status = 'processing'
|
|
658
|
+
AND ((c.status = 'pending' AND c.next_check_at <= ?)
|
|
659
|
+
OR (c.status = 'processing' AND
|
|
660
|
+
(c.updated_at <= ? OR c.next_check_at <= ?))
|
|
661
|
+
OR (c.status = 'delivering' AND c.updated_at <= ?))
|
|
662
|
+
ORDER BY c.integration_task_id ASC
|
|
663
|
+
LIMIT ?`,
|
|
664
|
+
args: [
|
|
665
|
+
now,
|
|
666
|
+
now - PROCESSING_STUCK_AFTER_MS,
|
|
667
|
+
now - PROCESSING_NEXT_CHECK_STALE_AFTER_MS,
|
|
668
|
+
now - 5 * 60 * 1000,
|
|
669
|
+
Math.max(1, Math.min(Math.floor(limit), 200)),
|
|
670
|
+
],
|
|
671
|
+
});
|
|
672
|
+
return rows.map((row) => ({
|
|
673
|
+
id: String(row.integration_task_id),
|
|
674
|
+
platform: String(row.platform),
|
|
675
|
+
externalThreadId: String(row.external_thread_id),
|
|
676
|
+
dispatchScope: (row.dispatch_scope as string | null) ?? null,
|
|
677
|
+
status: String(row.status),
|
|
678
|
+
}));
|
|
569
679
|
}
|
|
570
680
|
|
|
571
681
|
export async function claimA2AContinuationDelivery(
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getIntegrationCampaign,
|
|
3
|
+
failDisabledIntegrationCampaignTask,
|
|
4
|
+
listDueIntegrationCampaignIds,
|
|
5
|
+
} from "./integration-campaigns-store.js";
|
|
6
|
+
import {
|
|
7
|
+
dispatchPendingIntegrationTask,
|
|
8
|
+
isIntegrationDurableDispatchEnabledForTask,
|
|
9
|
+
} from "./integration-durable-dispatch.js";
|
|
10
|
+
import {
|
|
11
|
+
getNextPendingTaskForThread,
|
|
12
|
+
getPendingTask,
|
|
13
|
+
} from "./pending-tasks-store.js";
|
|
14
|
+
|
|
15
|
+
export interface IntegrationCampaignRecoveryResult {
|
|
16
|
+
selected: number;
|
|
17
|
+
dispatched: number;
|
|
18
|
+
skipped: number;
|
|
19
|
+
failed: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function hasConfirmedDeliveryReceipt(payload: string): boolean {
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(payload) as {
|
|
25
|
+
kind?: unknown;
|
|
26
|
+
deliveryReceipt?: { status?: unknown };
|
|
27
|
+
};
|
|
28
|
+
return (
|
|
29
|
+
parsed.kind === "response-delivery" &&
|
|
30
|
+
parsed.deliveryReceipt?.status === "delivered"
|
|
31
|
+
);
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Wake due campaign chunks without claiming or executing them in the sweep.
|
|
39
|
+
* The signed process-task endpoint owns the lease and all mutations.
|
|
40
|
+
*/
|
|
41
|
+
export async function recoverDueIntegrationCampaigns(options: {
|
|
42
|
+
limit?: number;
|
|
43
|
+
event?: unknown;
|
|
44
|
+
webhookBaseUrl?: string;
|
|
45
|
+
}): Promise<IntegrationCampaignRecoveryResult> {
|
|
46
|
+
const ids = await listDueIntegrationCampaignIds(options.limit ?? 20);
|
|
47
|
+
const result: IntegrationCampaignRecoveryResult = {
|
|
48
|
+
selected: ids.length,
|
|
49
|
+
dispatched: 0,
|
|
50
|
+
skipped: 0,
|
|
51
|
+
failed: 0,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
for (const id of ids) {
|
|
55
|
+
try {
|
|
56
|
+
const campaign = await getIntegrationCampaign(id);
|
|
57
|
+
if (!campaign) {
|
|
58
|
+
result.skipped += 1;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const task = await getPendingTask(campaign.integrationTaskId);
|
|
62
|
+
if (!task || task.status !== "processing") {
|
|
63
|
+
result.skipped += 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const durableDispatchEnabled = isIntegrationDurableDispatchEnabledForTask(
|
|
67
|
+
{
|
|
68
|
+
platform: task.platform,
|
|
69
|
+
externalThreadId: task.externalThreadId,
|
|
70
|
+
platformContext: task.dispatchScope
|
|
71
|
+
? { channelId: task.dispatchScope }
|
|
72
|
+
: undefined,
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
const confirmedReceipt = hasConfirmedDeliveryReceipt(task.payload);
|
|
76
|
+
if (!durableDispatchEnabled && !confirmedReceipt) {
|
|
77
|
+
await failDisabledIntegrationCampaignTask(task.id);
|
|
78
|
+
const nextTask = await getNextPendingTaskForThread(
|
|
79
|
+
task.platform,
|
|
80
|
+
task.externalThreadId,
|
|
81
|
+
);
|
|
82
|
+
if (nextTask) {
|
|
83
|
+
await dispatchPendingIntegrationTask({
|
|
84
|
+
taskId: nextTask.id,
|
|
85
|
+
task: {
|
|
86
|
+
platform: task.platform,
|
|
87
|
+
externalThreadId: task.externalThreadId,
|
|
88
|
+
platformContext: nextTask.dispatchScope
|
|
89
|
+
? { channelId: nextTask.dispatchScope }
|
|
90
|
+
: undefined,
|
|
91
|
+
},
|
|
92
|
+
event: options.event,
|
|
93
|
+
baseUrl: options.webhookBaseUrl,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
result.skipped += 1;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const outcome = await dispatchPendingIntegrationTask({
|
|
100
|
+
taskId: task.id,
|
|
101
|
+
task: {
|
|
102
|
+
platform: task.platform,
|
|
103
|
+
externalThreadId: task.externalThreadId,
|
|
104
|
+
platformContext: task.dispatchScope
|
|
105
|
+
? { channelId: task.dispatchScope }
|
|
106
|
+
: undefined,
|
|
107
|
+
},
|
|
108
|
+
event: options.event,
|
|
109
|
+
baseUrl: options.webhookBaseUrl,
|
|
110
|
+
campaignContinuation: true,
|
|
111
|
+
...(confirmedReceipt && !durableDispatchEnabled
|
|
112
|
+
? { allowPortableConfirmedReceiptReconciliation: true }
|
|
113
|
+
: {}),
|
|
114
|
+
});
|
|
115
|
+
if (outcome === "failed") result.failed += 1;
|
|
116
|
+
else result.dispatched += 1;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
result.failed += 1;
|
|
119
|
+
console.error(
|
|
120
|
+
`[integrations] Failed to wake integration campaign ${id}:`,
|
|
121
|
+
error,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return result;
|
|
127
|
+
}
|