@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.
Files changed (114) hide show
  1. package/README.md +1 -13
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +12 -0
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/agent/production-agent.ts +65 -1
  6. package/corpus/core/src/agent/run-loop-with-resume.ts +12 -0
  7. package/corpus/core/src/agent/run-store.ts +61 -1
  8. package/corpus/core/src/integrations/a2a-continuation-processor.ts +182 -0
  9. package/corpus/core/src/integrations/a2a-continuations-store.ts +122 -12
  10. package/corpus/core/src/integrations/integration-campaign-recovery.ts +127 -0
  11. package/corpus/core/src/integrations/integration-campaigns-store.ts +1039 -0
  12. package/corpus/core/src/integrations/integration-durable-dispatch.ts +28 -3
  13. package/corpus/core/src/integrations/pending-tasks-retry-job.ts +8 -0
  14. package/corpus/core/src/integrations/plugin.ts +453 -35
  15. package/corpus/core/src/integrations/webhook-handler.ts +469 -11
  16. package/corpus/core/src/server/builder-design-systems.ts +1 -1
  17. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +15 -0
  18. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -3
  19. package/corpus/templates/analytics/changelog/2026-07-25-analytics-dashboards-and-scheduled-reports-are-faster-and-mo.md +6 -0
  20. package/corpus/templates/analytics/server/db/schema.ts +12 -0
  21. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +8 -4
  22. package/corpus/templates/analytics/server/lib/dashboard-report.ts +136 -5
  23. package/corpus/templates/analytics/server/lib/dashboard-time-scope.ts +250 -1
  24. package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +167 -0
  25. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +34 -9
  26. package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +105 -23
  27. package/corpus/templates/analytics/server/lib/first-party-unbounded-panel-repair.ts +169 -0
  28. package/corpus/templates/analytics/server/plugins/db.ts +41 -1
  29. package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +6 -3
  30. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +7 -3
  31. package/corpus/templates/content/app/components/editor/body-hydration.ts +10 -0
  32. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +1 -0
  33. package/corpus/templates/content/app/root.tsx +12 -1
  34. package/corpus/templates/content/changelog/2026-07-23-new-pages-open-immediately-while-slow-network-work-continues.md +6 -0
  35. package/corpus/templates/content/changelog/2026-07-25-database-preview-actions-open-reliably.md +6 -0
  36. package/corpus/templates/content/e2e/playwright.config.ts +1 -1
  37. package/corpus/templates/design/actions/edit-design.ts +66 -27
  38. package/corpus/templates/design/changelog/2026-07-25-design-edits-retry-concurrent-changes.md +6 -0
  39. package/corpus/templates/design/server/source-workspace.ts +5 -1
  40. package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +6 -4
  41. package/corpus/templates/forms/actions/create-form.ts +5 -1
  42. package/corpus/templates/forms/actions/export-responses.ts +22 -11
  43. package/corpus/templates/forms/actions/update-form.ts +5 -1
  44. package/corpus/templates/forms/changelog/2026-07-25-fields-can-be-created-without-ids.md +6 -0
  45. package/corpus/templates/forms/changelog/2026-07-25-response-exports-use-file-storage.md +6 -0
  46. package/corpus/templates/forms/server/lib/validate-fields.ts +43 -0
  47. package/corpus/templates/slides/actions/extract-pdf.ts +4 -4
  48. package/corpus/templates/slides/actions/import-file.ts +3 -4
  49. package/corpus/templates/slides/changelog/2026-07-25-gemini-image-models-updated.md +6 -0
  50. package/corpus/templates/slides/changelog/2026-07-25-pdf-imports-tolerate-missing-canvas.md +6 -0
  51. package/corpus/templates/slides/server/handlers/image-providers/gemini.ts +5 -2
  52. package/corpus/templates/slides/server/lib/pdf-parse-setup.ts +150 -0
  53. package/dist/agent/production-agent.d.ts.map +1 -1
  54. package/dist/agent/production-agent.js +63 -1
  55. package/dist/agent/production-agent.js.map +1 -1
  56. package/dist/agent/run-loop-with-resume.d.ts +7 -1
  57. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  58. package/dist/agent/run-loop-with-resume.js +7 -0
  59. package/dist/agent/run-loop-with-resume.js.map +1 -1
  60. package/dist/agent/run-store.d.ts.map +1 -1
  61. package/dist/agent/run-store.js +49 -0
  62. package/dist/agent/run-store.js.map +1 -1
  63. package/dist/collab/routes.d.ts +1 -1
  64. package/dist/collab/struct-routes.d.ts +1 -1
  65. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  66. package/dist/integrations/a2a-continuation-processor.d.ts +14 -0
  67. package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
  68. package/dist/integrations/a2a-continuation-processor.js +134 -1
  69. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  70. package/dist/integrations/a2a-continuations-store.d.ts +23 -0
  71. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  72. package/dist/integrations/a2a-continuations-store.js +99 -13
  73. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  74. package/dist/integrations/integration-campaign-recovery.d.ts +16 -0
  75. package/dist/integrations/integration-campaign-recovery.d.ts.map +1 -0
  76. package/dist/integrations/integration-campaign-recovery.js +94 -0
  77. package/dist/integrations/integration-campaign-recovery.js.map +1 -0
  78. package/dist/integrations/integration-campaigns-store.d.ts +121 -0
  79. package/dist/integrations/integration-campaigns-store.d.ts.map +1 -0
  80. package/dist/integrations/integration-campaigns-store.js +784 -0
  81. package/dist/integrations/integration-campaigns-store.js.map +1 -0
  82. package/dist/integrations/integration-durable-dispatch.d.ts +3 -0
  83. package/dist/integrations/integration-durable-dispatch.d.ts.map +1 -1
  84. package/dist/integrations/integration-durable-dispatch.js +22 -3
  85. package/dist/integrations/integration-durable-dispatch.js.map +1 -1
  86. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  87. package/dist/integrations/pending-tasks-retry-job.js +6 -0
  88. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  89. package/dist/integrations/plugin.d.ts.map +1 -1
  90. package/dist/integrations/plugin.js +325 -18
  91. package/dist/integrations/plugin.js.map +1 -1
  92. package/dist/integrations/webhook-handler.d.ts +16 -1
  93. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  94. package/dist/integrations/webhook-handler.js +368 -13
  95. package/dist/integrations/webhook-handler.js.map +1 -1
  96. package/dist/observability/routes.d.ts +1 -1
  97. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  98. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  99. package/dist/secrets/routes.d.ts +9 -9
  100. package/dist/server/builder-design-systems.js +1 -1
  101. package/dist/server/builder-design-systems.js.map +1 -1
  102. package/package.json +3 -3
  103. package/src/agent/production-agent.ts +65 -1
  104. package/src/agent/run-loop-with-resume.ts +12 -0
  105. package/src/agent/run-store.ts +61 -1
  106. package/src/integrations/a2a-continuation-processor.ts +182 -0
  107. package/src/integrations/a2a-continuations-store.ts +122 -12
  108. package/src/integrations/integration-campaign-recovery.ts +127 -0
  109. package/src/integrations/integration-campaigns-store.ts +1039 -0
  110. package/src/integrations/integration-durable-dispatch.ts +28 -3
  111. package/src/integrations/pending-tasks-retry-job.ts +8 -0
  112. package/src/integrations/plugin.ts +453 -35
  113. package/src/integrations/webhook-handler.ts +469 -11
  114. 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: ["pending", now, now, processingCutoff, staleNextCheckCutoff],
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
- const claimed: A2AContinuation[] = [];
564
- for (const row of rows) {
565
- const continuation = await claimA2AContinuation(row.id as string);
566
- if (continuation) claimed.push(continuation);
567
- }
568
- return claimed;
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
+ }