@agent-native/core 0.157.6 → 0.157.8

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 (93) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/agent-native.config.ts +5 -0
  3. package/corpus/templates/analytics/netlify.toml +1 -0
  4. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +23 -5
  5. package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
  6. package/corpus/templates/assets/netlify.toml +3 -0
  7. package/corpus/templates/brain/netlify.toml +3 -0
  8. package/corpus/templates/calendar/agent-native.config.ts +5 -0
  9. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +4 -1
  10. package/corpus/templates/calendar/netlify.toml +3 -0
  11. package/corpus/templates/chat/agent-native.config.ts +5 -0
  12. package/corpus/templates/chat/netlify.toml +3 -0
  13. package/corpus/templates/clips/actions/lib/meeting-content.ts +28 -0
  14. package/corpus/templates/clips/actions/list-meetings.ts +33 -11
  15. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  16. package/corpus/templates/clips/app/lib/meeting-history-query.ts +11 -0
  17. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +47 -21
  18. package/corpus/templates/clips/netlify.toml +4 -0
  19. package/corpus/templates/content/netlify.toml +3 -0
  20. package/corpus/templates/design/app/i18n-data.ts +2 -0
  21. package/corpus/templates/design/netlify.toml +3 -0
  22. package/corpus/templates/dispatch/netlify.toml +3 -0
  23. package/corpus/templates/factory/netlify.toml +3 -0
  24. package/corpus/templates/forms/netlify.toml +3 -0
  25. package/corpus/templates/macros/netlify.toml +3 -0
  26. package/corpus/templates/mail/agent-native.config.ts +5 -0
  27. package/corpus/templates/mail/netlify.toml +3 -0
  28. package/corpus/templates/plan/netlify.toml +3 -0
  29. package/corpus/templates/slides/netlify.toml +3 -0
  30. package/dist/agent/harness/acp-adapter.js +17 -2
  31. package/dist/agent/harness/ai-sdk-adapter.js +14 -3
  32. package/dist/agent/harness/background.js +10 -5
  33. package/dist/agent/harness/hosted.d.ts +20 -0
  34. package/dist/agent/harness/hosted.js +100 -0
  35. package/dist/agent/harness/runner.js +100 -77
  36. package/dist/agent/observational-memory/observer.js +12 -0
  37. package/dist/agent/production-agent.d.ts +3 -0
  38. package/dist/agent/production-agent.js +74 -4
  39. package/dist/agent/thread-data-builder.d.ts +12 -0
  40. package/dist/agent/thread-data-builder.js +23 -0
  41. package/dist/agent/types.d.ts +6 -0
  42. package/dist/client/AgentPanel.d.ts +5 -1
  43. package/dist/client/AgentPanel.js +113 -17
  44. package/dist/client/AgentTaskCard.d.ts +2 -2
  45. package/dist/client/AgentTaskCard.js +8 -22
  46. package/dist/client/AssistantChat.d.ts +8 -0
  47. package/dist/client/AssistantChat.js +106 -59
  48. package/dist/client/MultiTabAssistantChat.js +50 -6
  49. package/dist/client/NewWorkspaceAppFlow.js +7 -1
  50. package/dist/client/agent-chat-adapter.d.ts +6 -0
  51. package/dist/client/agent-chat-adapter.js +36 -8
  52. package/dist/client/app-chat-sidebar.d.ts +5 -0
  53. package/dist/client/app-chat-sidebar.js +53 -9
  54. package/dist/client/chat/composer-draft.d.ts +4 -0
  55. package/dist/client/chat/composer-draft.js +63 -0
  56. package/dist/client/chat-first/apps-rail.js +10 -1
  57. package/dist/client/chat-first/primary-nav.js +10 -5
  58. package/dist/client/frame-protocol.d.ts +1 -0
  59. package/dist/client/hooks/index.d.ts +1 -1
  60. package/dist/client/hooks/index.js +1 -1
  61. package/dist/client/i18n.js +5 -2
  62. package/dist/client/progress/RunsTray.js +129 -16
  63. package/dist/client/settings/SettingsRow.js +1 -1
  64. package/dist/client/use-chat-threads.js +11 -6
  65. package/dist/config.d.ts +11 -0
  66. package/dist/config.js +52 -0
  67. package/dist/extensions/actions.js +22 -1
  68. package/dist/hosted-harness/actions/get-hosted-harness-config.d.ts +2 -0
  69. package/dist/hosted-harness/actions/get-hosted-harness-config.js +13 -0
  70. package/dist/hosted-harness/actions/set-hosted-harness-enabled.d.ts +4 -0
  71. package/dist/hosted-harness/actions/set-hosted-harness-enabled.js +32 -0
  72. package/dist/localization/default-messages.d.ts +4 -1
  73. package/dist/localization/default-messages.js +5 -2
  74. package/dist/notifications/routes.d.ts +1 -1
  75. package/dist/provider-api/actions/custom-provider-registration.d.ts +6 -6
  76. package/dist/provider-api/actions/provider-api.d.ts +4 -4
  77. package/dist/server/action-discovery.js +12 -0
  78. package/dist/server/agent-chat-plugin.js +24 -4
  79. package/dist/server/agent-teams.d.ts +20 -12
  80. package/dist/server/agent-teams.js +69 -35
  81. package/dist/server/hosted-harness-policy.d.ts +17 -0
  82. package/dist/server/hosted-harness-policy.js +38 -0
  83. package/dist/server/poll.d.ts +4 -4
  84. package/dist/server/poll.js +45 -13
  85. package/dist/server/realtime-token.d.ts +1 -1
  86. package/dist/server/request-context.d.ts +4 -0
  87. package/dist/styles/agent-native.css +39 -0
  88. package/dist/templates/chat/agent-native.config.ts +5 -0
  89. package/dist/templates/chat/netlify.toml +3 -0
  90. package/dist/vite/action-types-plugin.js +8 -0
  91. package/package.json +5 -3
  92. package/src/templates/chat/agent-native.config.ts +5 -0
  93. package/src/templates/chat/netlify.toml +3 -0
@@ -0,0 +1,38 @@
1
+ import { HOSTED_HARNESS_ENV_KEY, HOSTED_HARNESS_ORG_SETTING_KEY, isHostedHarnessConfigured, normalizeHostedHarnessRuntimes, } from "../agent/harness/hosted.js";
2
+ import { getOrgSetting } from "../settings/org-settings.js";
3
+ import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, } from "../vite/agent-native-config-loader.js";
4
+ export function isHostedHarnessEnvEnabled(env = process.env) {
5
+ const value = env[HOSTED_HARNESS_ENV_KEY]?.trim().toLowerCase();
6
+ return value === "1" || value === "true" || value === "yes" || value === "on";
7
+ }
8
+ export async function loadHostedHarnessConfig(cwd = process.cwd()) {
9
+ const production = process.env.NODE_ENV === "production";
10
+ const config = await loadResolvedAgentNativeConfig(cwd, createAgentNativeConfigContext(production ? "build" : "serve", production ? "production" : "development"));
11
+ return config.harness;
12
+ }
13
+ export async function resolveHostedHarnessPolicy(options) {
14
+ const config = options.config ?? (await loadHostedHarnessConfig());
15
+ const organizationSetting = options.orgId
16
+ ? await getOrgSetting(options.orgId, HOSTED_HARNESS_ORG_SETTING_KEY)
17
+ : null;
18
+ const envEnabled = isHostedHarnessEnvEnabled();
19
+ // The deployment flag is the fleet-level default. An org setting is only
20
+ // needed when a deployment has not enabled the hosted harness globally.
21
+ const organizationEnabled = envEnabled || organizationSetting?.enabled === true;
22
+ const configEnabled = isHostedHarnessConfigured(config);
23
+ return {
24
+ enabled: configEnabled && (envEnabled || organizationEnabled),
25
+ configEnabled,
26
+ envEnabled,
27
+ organizationEnabled,
28
+ runtimes: normalizeHostedHarnessRuntimes(typeof config === "object" && config !== null
29
+ ? config.runtimes
30
+ : undefined),
31
+ };
32
+ }
33
+ export function hostedHarnessStatusForClient(policy) {
34
+ return {
35
+ ...policy,
36
+ runtimes: [...policy.runtimes],
37
+ };
38
+ }
@@ -233,10 +233,10 @@ export declare class AppSyncState {
233
233
  * bounded index range scan.
234
234
  *
235
235
  * The `lastDurablePrune` throttle below is per-process, so every serverless
236
- * worker prunes on its first poll. That was survivable only once the work
237
- * itself became bounded and indexed; if concurrency is still a problem,
238
- * the next step is a `pg_try_advisory_xact_lock` so one worker prunes at a
239
- * time. Deliberately not done yet — measure before adding a lock.
236
+ * worker prunes on its first poll. Postgres workers also take a
237
+ * transaction-scoped advisory lease for each batch: only one worker deletes
238
+ * at a time, but each batch still commits independently so a killed worker
239
+ * cannot hold a long transaction open.
240
240
  */
241
241
  private pruneDurableEvents;
242
242
  persistSyncEvent(event: ChangeEvent, dedupeKey?: string, presetId?: string): Promise<void>;
@@ -42,6 +42,12 @@ const DURABLE_RETENTION_MS = 24 * 60 * 60 * 1000;
42
42
  */
43
43
  const DURABLE_PRUNE_BATCH = 10_000;
44
44
  const DURABLE_PRUNE_MAX_BATCHES = 40;
45
+ /**
46
+ * Postgres advisory-lock key for the per-database retention worker. The lock
47
+ * is transaction-scoped so a serverless worker that is killed cannot leave a
48
+ * lease behind for another worker to clear.
49
+ */
50
+ const DURABLE_PRUNE_LOCK_KEY = "agent-native:sync-events-prune";
45
51
  /**
46
52
  * How far back a cold-started process replays durable action markers.
47
53
  * Covers the gap between a separate action process writing its marker and this
@@ -455,10 +461,10 @@ export class AppSyncState {
455
461
  * bounded index range scan.
456
462
  *
457
463
  * The `lastDurablePrune` throttle below is per-process, so every serverless
458
- * worker prunes on its first poll. That was survivable only once the work
459
- * itself became bounded and indexed; if concurrency is still a problem,
460
- * the next step is a `pg_try_advisory_xact_lock` so one worker prunes at a
461
- * time. Deliberately not done yet — measure before adding a lock.
464
+ * worker prunes on its first poll. Postgres workers also take a
465
+ * transaction-scoped advisory lease for each batch: only one worker deletes
466
+ * at a time, but each batch still commits independently so a killed worker
467
+ * cannot hold a long transaction open.
462
468
  */
463
469
  async pruneDurableEvents(client) {
464
470
  const now = Date.now();
@@ -469,17 +475,43 @@ export class AppSyncState {
469
475
  let deleted = 0;
470
476
  try {
471
477
  for (let batch = 0; batch < DURABLE_PRUNE_MAX_BATCHES; batch++) {
472
- const result = await client.execute({
478
+ const runBatch = async (tx) => {
479
+ if (this.isPg()) {
480
+ const lockResult = await tx.execute({
481
+ sql: "SELECT pg_try_advisory_xact_lock(hashtextextended(?, 0::bigint)) AS acquired",
482
+ args: [DURABLE_PRUNE_LOCK_KEY],
483
+ });
484
+ const acquired = lockResult.rows[0]?.acquired;
485
+ if (acquired !== true && acquired !== "t")
486
+ return null;
487
+ }
473
488
  // `id IN (...)` rather than ctid/rowid: both are dialect-specific,
474
489
  // and the primary key is indexed on every dialect we ship.
475
- sql: `DELETE FROM sync_events WHERE id IN (
476
- SELECT id FROM sync_events WHERE created_at < ?
477
- ORDER BY created_at, id LIMIT ?
478
- )`,
479
- args: [cutoff, DURABLE_PRUNE_BATCH],
480
- });
481
- deleted += result.rowsAffected;
482
- if (result.rowsAffected < DURABLE_PRUNE_BATCH)
490
+ const result = await tx.execute({
491
+ sql: `DELETE FROM sync_events WHERE id IN (
492
+ SELECT id FROM sync_events WHERE created_at < ?
493
+ ORDER BY created_at, id LIMIT ?
494
+ )`,
495
+ args: [cutoff, DURABLE_PRUNE_BATCH],
496
+ });
497
+ return result.rowsAffected;
498
+ };
499
+ // A Postgres advisory transaction lock is only useful when the lock
500
+ // and delete share a connection and transaction. Never fall back to
501
+ // an uncoordinated delete on a transactionless client.
502
+ const rowsAffected = this.isPg()
503
+ ? client.transaction
504
+ ? await client.transaction(runBatch)
505
+ : null
506
+ : await runBatch(client);
507
+ if (rowsAffected == null) {
508
+ if (this.isPg() && !client.transaction) {
509
+ throw new Error("Postgres prune requires a database transaction");
510
+ }
511
+ break;
512
+ }
513
+ deleted += rowsAffected;
514
+ if (rowsAffected < DURABLE_PRUNE_BATCH)
483
515
  break;
484
516
  }
485
517
  this.durablePruneFailures = 0;
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
26
26
  expiresAt?: undefined;
27
27
  ttlSeconds?: undefined;
28
28
  } | {
29
- error?: undefined;
30
29
  token: string;
31
30
  expiresAt: string;
32
31
  ttlSeconds: number;
32
+ error?: undefined;
33
33
  }>>;
@@ -61,6 +61,8 @@ export interface RequestRunContext {
61
61
  model?: string;
62
62
  /** Request-authorized action names exposed to this agent run. */
63
63
  allowedActionNames?: readonly string[];
64
+ /** Hosted tools-only harness selected for this agent run. */
65
+ hostedHarnessRuntime?: "claude-code" | "codex" | "pi" | "opencode";
64
66
  /**
65
67
  * True when this run is executing inside the durable background-function
66
68
  * worker (the `_process-run` self-dispatch), not the synchronous foreground
@@ -82,6 +84,8 @@ export interface RequestRunContext {
82
84
  }>;
83
85
  /** Per-run fingerprints for large extension bodies already sent to the LLM. */
84
86
  extensionContentReads?: Record<string, string>;
87
+ /** Per-run keys for extension excerpt reads already sent to the LLM. */
88
+ extensionExcerptReads?: Record<string, true>;
85
89
  /** Per-run fingerprints for repeated tool-search calls already sent to the LLM. */
86
90
  toolSearchReads?: Record<string, {
87
91
  totalTools: number;
@@ -230,6 +230,23 @@
230
230
  container: agent-native-main / inline-size;
231
231
  }
232
232
 
233
+ /* Dispatch and Electron own the chat drawer when an app is embedded. Keep
234
+ the standard app's navigation beside its content, on the opposite edge.
235
+ Custom shells opt out with data-agent-native-shell-variant="custom". */
236
+ @media (min-width: 768px) {
237
+ .agent-layout-shell:not([data-agent-native-shell-variant="custom"]):has(
238
+ > .agent-sidebar-shell[data-agent-native-hosted-chat="true"]
239
+ )
240
+ > .agent-layout-left-drawer,
241
+ .agent-sidebar-shell[data-agent-native-hosted-chat="true"]
242
+ .agent-layout-shell:not([data-agent-native-shell-variant="custom"])
243
+ > .agent-layout-left-drawer {
244
+ order: 2;
245
+ border-inline-end: 0 !important;
246
+ border-inline-start: 1px solid hsl(var(--sidebar-border)) !important;
247
+ }
248
+ }
249
+
233
250
  @media (min-width: 768px) {
234
251
  .agent-layout-shell
235
252
  :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
@@ -727,6 +744,28 @@
727
744
  line-height: 1.4rem;
728
745
  }
729
746
 
747
+ /* Settings rows size themselves from the available content column. The full
748
+ Settings page can be narrow even on a desktop viewport when its navigation
749
+ rail and agent sidebar are both open, so viewport breakpoints are not a
750
+ reliable signal for keeping copy and controls side by side. */
751
+ .agent-native-settings-row {
752
+ container-type: inline-size;
753
+ container-name: settings-row;
754
+ }
755
+
756
+ @container settings-row (min-width: 36rem) {
757
+ .agent-native-settings-row__layout {
758
+ align-items: center;
759
+ flex-direction: row;
760
+ justify-content: space-between;
761
+ }
762
+
763
+ .agent-native-settings-row__control {
764
+ margin-inline-start: 1rem;
765
+ text-align: end;
766
+ }
767
+ }
768
+
730
769
  /* Composer toolbar: keep the model name + version readable on narrow
731
770
  chatfields. The bordered composer box is a size container; below 370px
732
771
  wide (e.g. a narrow agent sidebar) we drop the reasoning-level suffix
@@ -0,0 +1,5 @@
1
+ import { defineAgentNativeConfig } from "@agent-native/core/config";
2
+
3
+ export default defineAgentNativeConfig({
4
+ harness: true,
5
+ });
@@ -9,3 +9,6 @@ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
9
  GTM_CONTAINER_ID = "GTM-N3WSTXZ"
10
10
  NITRO_PRESET = "netlify"
11
11
  NPM_CONFIG_PRODUCTION = "false"
12
+
13
+ [context.production.environment]
14
+ AGENT_NATIVE_HOSTED_HARNESS = "true"
@@ -53,6 +53,14 @@ const CORE_SHARING_ACTIONS = [
53
53
  name: "set-feature-flag",
54
54
  specifier: "@agent-native/core/feature-flags/actions/set-feature-flag",
55
55
  },
56
+ {
57
+ name: "get-hosted-harness-config",
58
+ specifier: "@agent-native/core/hosted-harness/actions/get-hosted-harness-config",
59
+ },
60
+ {
61
+ name: "set-hosted-harness-enabled",
62
+ specifier: "@agent-native/core/hosted-harness/actions/set-hosted-harness-enabled",
63
+ },
56
64
  {
57
65
  name: "share-resource",
58
66
  specifier: "@agent-native/core/sharing/actions/share-resource",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.157.6",
3
+ "version": "0.157.8",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -185,6 +185,8 @@
185
185
  "./feature-flags/actions/get-feature-flags": "./dist/feature-flags/actions/get-feature-flags.js",
186
186
  "./feature-flags/actions/list-feature-flags": "./dist/feature-flags/actions/list-feature-flags.js",
187
187
  "./feature-flags/actions/set-feature-flag": "./dist/feature-flags/actions/set-feature-flag.js",
188
+ "./hosted-harness/actions/get-hosted-harness-config": "./dist/hosted-harness/actions/get-hosted-harness-config.js",
189
+ "./hosted-harness/actions/set-hosted-harness-enabled": "./dist/hosted-harness/actions/set-hosted-harness-enabled.js",
188
190
  "./localization": "./dist/localization/index.js",
189
191
  "./localization/actions/get-localization-preference": "./dist/localization/actions/get-localization-preference.js",
190
192
  "./localization/actions/set-localization-preference": "./dist/localization/actions/set-localization-preference.js",
@@ -423,8 +425,8 @@
423
425
  "y-protocols": "^1.0.7",
424
426
  "yjs": "^13.6.31",
425
427
  "zod": "^4.3.6",
426
- "@agent-native/toolkit": "^0.16.0",
427
- "@agent-native/recap-cli": "0.5.4"
428
+ "@agent-native/recap-cli": "0.5.4",
429
+ "@agent-native/toolkit": "^0.16.1"
428
430
  },
429
431
  "devDependencies": {
430
432
  "@ai-sdk/anthropic": "^3.0.71",
@@ -0,0 +1,5 @@
1
+ import { defineAgentNativeConfig } from "@agent-native/core/config";
2
+
3
+ export default defineAgentNativeConfig({
4
+ harness: true,
5
+ });
@@ -9,3 +9,6 @@ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
9
  GTM_CONTAINER_ID = "GTM-N3WSTXZ"
10
10
  NITRO_PRESET = "netlify"
11
11
  NPM_CONFIG_PRODUCTION = "false"
12
+
13
+ [context.production.environment]
14
+ AGENT_NATIVE_HOSTED_HARNESS = "true"