@agent-native/core 0.131.9 → 0.132.1

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 (295) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +105 -0
  3. package/corpus/core/docs/content/durable-background-runs.mdx +15 -6
  4. package/corpus/core/docs/design/durable-agent-runs.md +15 -11
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/a2a/activity.ts +127 -10
  7. package/corpus/core/src/a2a/index.ts +3 -0
  8. package/corpus/core/src/action.ts +52 -11
  9. package/corpus/core/src/agent/durable-background.ts +38 -28
  10. package/corpus/core/src/agent/harness/background.ts +12 -2
  11. package/corpus/core/src/agent/production-agent.ts +210 -43
  12. package/corpus/core/src/agent/run-store.ts +45 -3
  13. package/corpus/core/src/application-state/handlers.ts +45 -0
  14. package/corpus/core/src/application-state/index.ts +3 -0
  15. package/corpus/core/src/application-state/store.ts +28 -11
  16. package/corpus/core/src/audit/redact.ts +104 -18
  17. package/corpus/core/src/client/AgentPanel.tsx +2 -7
  18. package/corpus/core/src/client/MultiTabAssistantChat.tsx +3 -0
  19. package/corpus/core/src/client/RunStuckBanner.tsx +29 -6
  20. package/corpus/core/src/client/agent-chat.ts +4 -9
  21. package/corpus/core/src/client/application-state.ts +115 -12
  22. package/corpus/core/src/client/dynamic-suggestions.ts +4 -12
  23. package/corpus/core/src/client/guided-questions.tsx +12 -23
  24. package/corpus/core/src/db/client.ts +148 -28
  25. package/corpus/core/src/db/create-get-db.ts +39 -6
  26. package/corpus/core/src/db/runtime-diagnostics.ts +41 -6
  27. package/corpus/core/src/deploy/build.ts +26 -33
  28. package/corpus/core/src/feature-flags/store.ts +10 -5
  29. package/corpus/core/src/integrations/a2a-continuations-store.ts +11 -0
  30. package/corpus/core/src/integrations/config-store.ts +13 -0
  31. package/corpus/core/src/integrations/google-docs-poller.ts +26 -2
  32. package/corpus/core/src/mcp-client/routes.ts +33 -2
  33. package/corpus/core/src/onboarding/plugin.ts +31 -25
  34. package/corpus/core/src/org/accept-pending.ts +2 -0
  35. package/corpus/core/src/org/auto-join-domain.ts +2 -0
  36. package/corpus/core/src/org/context.ts +35 -10
  37. package/corpus/core/src/org/handlers.ts +6 -0
  38. package/corpus/core/src/org/request-org-cache.ts +71 -0
  39. package/corpus/core/src/resources/store.ts +10 -9
  40. package/corpus/core/src/scripts/runner.ts +6 -3
  41. package/corpus/core/src/secrets/storage.ts +97 -5
  42. package/corpus/core/src/server/action-change.ts +33 -0
  43. package/corpus/core/src/server/action-routes.ts +11 -9
  44. package/corpus/core/src/server/agent-teams.ts +10 -2
  45. package/corpus/core/src/server/better-auth-instance.ts +39 -12
  46. package/corpus/core/src/server/core-routes-plugin.ts +19 -2
  47. package/corpus/core/src/server/credential-provider.ts +57 -14
  48. package/corpus/core/src/server/http-response-telemetry.ts +1 -0
  49. package/corpus/core/src/server/poll.ts +95 -57
  50. package/corpus/core/src/server/voice-providers-status.ts +19 -4
  51. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -0
  52. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
  53. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +299 -0
  54. package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +34 -0
  55. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +82 -0
  56. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +2 -2
  57. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +40 -34
  58. package/corpus/templates/analytics/app/hooks/use-user-pref.ts +3 -3
  59. package/corpus/templates/analytics/app/i18n-data.ts +40 -0
  60. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +18 -10
  61. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +14 -0
  62. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +1 -0
  63. package/corpus/templates/analytics/app/routes/chart.tsx +3 -0
  64. package/corpus/templates/analytics/changelog/2026-07-30-analytics-dashboards-now-expose-native-funnel-heatmap-callou.md +6 -0
  65. package/corpus/templates/analytics/changelog/2026-07-30-analytics-now-ships-reusable-native-v2-dashboard-manifests-w.md +6 -0
  66. package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +81 -1
  67. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +457 -0
  68. package/corpus/templates/analytics/server/lib/report-chart-svg.ts +73 -2
  69. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
  70. package/corpus/templates/analytics/shared/dashboard-funnel.ts +83 -0
  71. package/corpus/templates/content/changelog/2026-07-30-long-running-delegated-requests-now-continue-reliably.md +6 -0
  72. package/corpus/templates/content/netlify.toml +3 -0
  73. package/corpus/templates/content/server/plugins/agent-chat.ts +1 -0
  74. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +2 -1
  75. package/corpus/templates/slides/actions/patch-deck.ts +25 -1
  76. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +17 -4
  77. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +9 -1
  78. package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
  79. package/corpus/templates/slides/app/context/DeckContext.tsx +11 -3
  80. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +39 -11
  81. package/corpus/templates/slides/app/pages/Index.tsx +2 -2
  82. package/corpus/templates/slides/changelog/2026-07-30-slide-previews-keep-their-aspect-ratio-isolate-embedded-styl.md +6 -0
  83. package/corpus/templates/slides/changelog/2026-07-30-slides-no-longer-lose-decks-while-organization-access-is-loa.md +6 -0
  84. package/corpus/toolkit/CHANGELOG.md +8 -0
  85. package/corpus/toolkit/package.json +1 -1
  86. package/corpus/toolkit/src/composer/runtime-adapters.tsx +16 -11
  87. package/dist/a2a/activity.d.ts +22 -4
  88. package/dist/a2a/activity.d.ts.map +1 -1
  89. package/dist/a2a/activity.js +97 -11
  90. package/dist/a2a/activity.js.map +1 -1
  91. package/dist/a2a/index.d.ts +1 -1
  92. package/dist/a2a/index.d.ts.map +1 -1
  93. package/dist/a2a/index.js +1 -1
  94. package/dist/a2a/index.js.map +1 -1
  95. package/dist/action.d.ts.map +1 -1
  96. package/dist/action.js +41 -11
  97. package/dist/action.js.map +1 -1
  98. package/dist/agent/durable-background.d.ts +13 -8
  99. package/dist/agent/durable-background.d.ts.map +1 -1
  100. package/dist/agent/durable-background.js +36 -28
  101. package/dist/agent/durable-background.js.map +1 -1
  102. package/dist/agent/harness/background.d.ts.map +1 -1
  103. package/dist/agent/harness/background.js +12 -2
  104. package/dist/agent/harness/background.js.map +1 -1
  105. package/dist/agent/production-agent.d.ts.map +1 -1
  106. package/dist/agent/production-agent.js +195 -44
  107. package/dist/agent/production-agent.js.map +1 -1
  108. package/dist/agent/run-store.d.ts +2 -0
  109. package/dist/agent/run-store.d.ts.map +1 -1
  110. package/dist/agent/run-store.js +44 -3
  111. package/dist/agent/run-store.js.map +1 -1
  112. package/dist/application-state/handlers.d.ts +15 -0
  113. package/dist/application-state/handlers.d.ts.map +1 -1
  114. package/dist/application-state/handlers.js +42 -2
  115. package/dist/application-state/handlers.js.map +1 -1
  116. package/dist/application-state/index.d.ts +2 -2
  117. package/dist/application-state/index.d.ts.map +1 -1
  118. package/dist/application-state/index.js +2 -2
  119. package/dist/application-state/index.js.map +1 -1
  120. package/dist/application-state/store.d.ts +11 -0
  121. package/dist/application-state/store.d.ts.map +1 -1
  122. package/dist/application-state/store.js +23 -10
  123. package/dist/application-state/store.js.map +1 -1
  124. package/dist/audit/redact.d.ts +25 -2
  125. package/dist/audit/redact.d.ts.map +1 -1
  126. package/dist/audit/redact.js +85 -21
  127. package/dist/audit/redact.js.map +1 -1
  128. package/dist/client/AgentPanel.d.ts.map +1 -1
  129. package/dist/client/AgentPanel.js +2 -7
  130. package/dist/client/AgentPanel.js.map +1 -1
  131. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  132. package/dist/client/MultiTabAssistantChat.js +1 -1
  133. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  134. package/dist/client/RunStuckBanner.d.ts +11 -1
  135. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  136. package/dist/client/RunStuckBanner.js +20 -7
  137. package/dist/client/RunStuckBanner.js.map +1 -1
  138. package/dist/client/agent-chat.d.ts.map +1 -1
  139. package/dist/client/agent-chat.js +4 -6
  140. package/dist/client/agent-chat.js.map +1 -1
  141. package/dist/client/application-state.d.ts +11 -0
  142. package/dist/client/application-state.d.ts.map +1 -1
  143. package/dist/client/application-state.js +87 -9
  144. package/dist/client/application-state.js.map +1 -1
  145. package/dist/client/dynamic-suggestions.d.ts.map +1 -1
  146. package/dist/client/dynamic-suggestions.js +4 -13
  147. package/dist/client/dynamic-suggestions.js.map +1 -1
  148. package/dist/client/guided-questions.d.ts.map +1 -1
  149. package/dist/client/guided-questions.js +6 -22
  150. package/dist/client/guided-questions.js.map +1 -1
  151. package/dist/collab/routes.d.ts +1 -1
  152. package/dist/collab/struct-routes.d.ts +1 -1
  153. package/dist/db/client.d.ts +57 -10
  154. package/dist/db/client.d.ts.map +1 -1
  155. package/dist/db/client.js +122 -31
  156. package/dist/db/client.js.map +1 -1
  157. package/dist/db/create-get-db.d.ts.map +1 -1
  158. package/dist/db/create-get-db.js +31 -7
  159. package/dist/db/create-get-db.js.map +1 -1
  160. package/dist/db/runtime-diagnostics.d.ts +1 -0
  161. package/dist/db/runtime-diagnostics.d.ts.map +1 -1
  162. package/dist/db/runtime-diagnostics.js +31 -6
  163. package/dist/db/runtime-diagnostics.js.map +1 -1
  164. package/dist/deploy/build.d.ts +5 -20
  165. package/dist/deploy/build.d.ts.map +1 -1
  166. package/dist/deploy/build.js +18 -30
  167. package/dist/deploy/build.js.map +1 -1
  168. package/dist/feature-flags/store.d.ts.map +1 -1
  169. package/dist/feature-flags/store.js +10 -5
  170. package/dist/feature-flags/store.js.map +1 -1
  171. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  172. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  173. package/dist/integrations/a2a-continuations-store.js +12 -0
  174. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  175. package/dist/integrations/config-store.d.ts +1 -0
  176. package/dist/integrations/config-store.d.ts.map +1 -1
  177. package/dist/integrations/config-store.js +11 -0
  178. package/dist/integrations/config-store.js.map +1 -1
  179. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  180. package/dist/integrations/google-docs-poller.js +19 -2
  181. package/dist/integrations/google-docs-poller.js.map +1 -1
  182. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  183. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  184. package/dist/mcp-client/routes.d.ts.map +1 -1
  185. package/dist/mcp-client/routes.js +30 -2
  186. package/dist/mcp-client/routes.js.map +1 -1
  187. package/dist/notifications/routes.d.ts +3 -3
  188. package/dist/observability/routes.d.ts +1 -1
  189. package/dist/onboarding/plugin.d.ts.map +1 -1
  190. package/dist/onboarding/plugin.js +12 -8
  191. package/dist/onboarding/plugin.js.map +1 -1
  192. package/dist/org/accept-pending.d.ts.map +1 -1
  193. package/dist/org/accept-pending.js +2 -0
  194. package/dist/org/accept-pending.js.map +1 -1
  195. package/dist/org/auto-join-domain.d.ts.map +1 -1
  196. package/dist/org/auto-join-domain.js +2 -0
  197. package/dist/org/auto-join-domain.js.map +1 -1
  198. package/dist/org/context.d.ts.map +1 -1
  199. package/dist/org/context.js +29 -9
  200. package/dist/org/context.js.map +1 -1
  201. package/dist/org/handlers.d.ts.map +1 -1
  202. package/dist/org/handlers.js +5 -0
  203. package/dist/org/handlers.js.map +1 -1
  204. package/dist/org/request-org-cache.d.ts +16 -0
  205. package/dist/org/request-org-cache.d.ts.map +1 -0
  206. package/dist/org/request-org-cache.js +62 -0
  207. package/dist/org/request-org-cache.js.map +1 -0
  208. package/dist/resources/store.d.ts.map +1 -1
  209. package/dist/resources/store.js +11 -9
  210. package/dist/resources/store.js.map +1 -1
  211. package/dist/scripts/runner.d.ts.map +1 -1
  212. package/dist/scripts/runner.js +3 -3
  213. package/dist/scripts/runner.js.map +1 -1
  214. package/dist/secrets/storage.d.ts.map +1 -1
  215. package/dist/secrets/storage.js +82 -5
  216. package/dist/secrets/storage.js.map +1 -1
  217. package/dist/server/action-change.d.ts +20 -0
  218. package/dist/server/action-change.d.ts.map +1 -1
  219. package/dist/server/action-change.js +29 -0
  220. package/dist/server/action-change.js.map +1 -1
  221. package/dist/server/action-routes.d.ts.map +1 -1
  222. package/dist/server/action-routes.js +7 -8
  223. package/dist/server/action-routes.js.map +1 -1
  224. package/dist/server/agent-teams.d.ts.map +1 -1
  225. package/dist/server/agent-teams.js +10 -2
  226. package/dist/server/agent-teams.js.map +1 -1
  227. package/dist/server/better-auth-instance.d.ts.map +1 -1
  228. package/dist/server/better-auth-instance.js +31 -14
  229. package/dist/server/better-auth-instance.js.map +1 -1
  230. package/dist/server/core-routes-plugin.d.ts +1 -0
  231. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  232. package/dist/server/core-routes-plugin.js +18 -4
  233. package/dist/server/core-routes-plugin.js.map +1 -1
  234. package/dist/server/credential-provider.d.ts +16 -0
  235. package/dist/server/credential-provider.d.ts.map +1 -1
  236. package/dist/server/credential-provider.js +49 -13
  237. package/dist/server/credential-provider.js.map +1 -1
  238. package/dist/server/http-response-telemetry.d.ts.map +1 -1
  239. package/dist/server/http-response-telemetry.js +1 -0
  240. package/dist/server/http-response-telemetry.js.map +1 -1
  241. package/dist/server/poll.d.ts +6 -0
  242. package/dist/server/poll.d.ts.map +1 -1
  243. package/dist/server/poll.js +84 -47
  244. package/dist/server/poll.js.map +1 -1
  245. package/dist/server/voice-providers-status.d.ts.map +1 -1
  246. package/dist/server/voice-providers-status.js +12 -3
  247. package/dist/server/voice-providers-status.js.map +1 -1
  248. package/docs/content/durable-background-runs.mdx +15 -6
  249. package/docs/design/durable-agent-runs.md +15 -11
  250. package/package.json +2 -2
  251. package/src/a2a/activity.ts +127 -10
  252. package/src/a2a/index.ts +3 -0
  253. package/src/action.ts +52 -11
  254. package/src/agent/durable-background.ts +38 -28
  255. package/src/agent/harness/background.ts +12 -2
  256. package/src/agent/production-agent.ts +210 -43
  257. package/src/agent/run-store.ts +45 -3
  258. package/src/application-state/handlers.ts +45 -0
  259. package/src/application-state/index.ts +3 -0
  260. package/src/application-state/store.ts +28 -11
  261. package/src/audit/redact.ts +104 -18
  262. package/src/client/AgentPanel.tsx +2 -7
  263. package/src/client/MultiTabAssistantChat.tsx +3 -0
  264. package/src/client/RunStuckBanner.tsx +29 -6
  265. package/src/client/agent-chat.ts +4 -9
  266. package/src/client/application-state.ts +115 -12
  267. package/src/client/dynamic-suggestions.ts +4 -12
  268. package/src/client/guided-questions.tsx +12 -23
  269. package/src/db/client.ts +148 -28
  270. package/src/db/create-get-db.ts +39 -6
  271. package/src/db/runtime-diagnostics.ts +41 -6
  272. package/src/deploy/build.ts +26 -33
  273. package/src/feature-flags/store.ts +10 -5
  274. package/src/integrations/a2a-continuations-store.ts +11 -0
  275. package/src/integrations/config-store.ts +13 -0
  276. package/src/integrations/google-docs-poller.ts +26 -2
  277. package/src/mcp-client/routes.ts +33 -2
  278. package/src/onboarding/plugin.ts +31 -25
  279. package/src/org/accept-pending.ts +2 -0
  280. package/src/org/auto-join-domain.ts +2 -0
  281. package/src/org/context.ts +35 -10
  282. package/src/org/handlers.ts +6 -0
  283. package/src/org/request-org-cache.ts +71 -0
  284. package/src/resources/store.ts +10 -9
  285. package/src/scripts/runner.ts +6 -3
  286. package/src/secrets/storage.ts +97 -5
  287. package/src/server/action-change.ts +33 -0
  288. package/src/server/action-routes.ts +11 -9
  289. package/src/server/agent-teams.ts +10 -2
  290. package/src/server/better-auth-instance.ts +39 -12
  291. package/src/server/core-routes-plugin.ts +19 -2
  292. package/src/server/credential-provider.ts +57 -14
  293. package/src/server/http-response-telemetry.ts +1 -0
  294. package/src/server/poll.ts +95 -57
  295. package/src/server/voice-providers-status.ts +19 -4
package/corpus/README.md CHANGED
@@ -28,6 +28,6 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
 
29
29
  ## Generated Counts
30
30
 
31
- - core files: 1644
31
+ - core files: 1645
32
32
  - toolkit files: 168
33
- - template files: 7226
33
+ - template files: 7235
@@ -1,5 +1,110 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.132.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 548844d: Fix agent tool calls failing against discriminated-union action schemas. Gateway-supplied empty placeholders are now stripped from nested objects and union branches (not just top-level fields), `oneOf` validation errors report only the branch the discriminator selects, and the expected-signature hint expands array items and union branches so nested enums are spelled out.
8
+
9
+ ## 0.132.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 89e5910: Enable durable agent-chat background runs by default for deployed Netlify apps, with an explicit opt-out.
14
+
15
+ ### Patch Changes
16
+
17
+ - 89e5910: Batch application-state reads. `GET /_agent-native/application-state?keys=a,b,c`
18
+ returns many keys in one request, and `readClientAppState` coalesces reads
19
+ issued in the same tick into that single call, so a page load no longer pays one
20
+ HTTP round trip and one full identity resolution per key. The response reports
21
+ absent keys in `missing` rather than as `null` values, keeping "never written"
22
+ distinguishable from "written as null or empty"; the single-key routes are
23
+ unchanged.
24
+ - 89e5910: Cut database round trips on the status endpoints a page load hits repeatedly.
25
+ - Added `prefetchSecrets(keys)`, which warms the per-request secret memo with
26
+ one batched read per scope instead of one read per key per scope, and used it
27
+ in `/_agent-native/env-status` (48 single-key `app_secrets` selects per request
28
+ → 4 batched) and `/_agent-native/voice-providers/status` (19 → 4).
29
+ - The change marker after an action now honours a per-call Plan-mode `effect`
30
+ before the action-level `readOnly` flag. A status poll shaped as a mutating
31
+ action — `manage-agent-engine` with `action: "list"`, polled every few seconds
32
+ — no longer bumps the `"action"` change version, so queries keyed on it stop
33
+ refetching on an idle page.
34
+ - The default database schema health probe runs its table checks in parallel and
35
+ memoizes a clean result for a few seconds. A probe reporting a missing table or
36
+ an unreadable database is never memoized.
37
+
38
+ - 89e5910: Record tool arguments and result summaries in delegated-run traces. The A2A
39
+ agent-activity snapshot and the agent-team / harness background transcripts now
40
+ carry each tool call's arguments and a result preview in redacted, size-capped
41
+ form, so a delegated run that loops on the same tool is diagnosable from what
42
+ was recorded instead of needing a fresh repro. Captures reuse the audit
43
+ redaction helper (credential-looking keys and values become `[redacted]`),
44
+ oversized values keep an explicit `…(N more chars)` / `_auditTruncated` marker,
45
+ and a shared per-snapshot payload budget keeps the activity part inside its
46
+ wire limit.
47
+ - 89e5910: Share one Postgres connection pool per URL across the whole process instead of
48
+ building a separate one for the `getDbExec` singleton, Better Auth, and every
49
+ `createGetDb` store. Against a remote database that removed five redundant
50
+ first-connect round trips per process, and it let the pool cap rise so a
51
+ request's concurrent reads no longer serialize behind a single connection.
52
+ Secret reads are now memoized per request, keyed on scope and scope id, so the
53
+ user/org/workspace credential waterfall is not re-walked on every lookup.
54
+ Onboarding step status, resource inheritance layers, and feature-flag rules now
55
+ resolve their independent reads concurrently.
56
+ - 89e5910: Give delegated agent turns their app's actions as native tools in dev, so asking
57
+ a sibling app a question actually returns an answer.
58
+
59
+ In dev the interactive surface deliberately omits template actions from the tool
60
+ registry and lets the agent reach them through `bash`, which sidesteps the
61
+ degenerate empty-object tool call some models emit for complex schemas. That is
62
+ a reasonable trade for a person, who sees the bad call and rephrases. It is the
63
+ wrong trade for a delegated turn. An A2A caller, or an external host calling
64
+ `ask_app` over MCP, has nobody to intervene: with no native action the receiving
65
+ agent shells out, the call runs long, and the caller records "Interrupted before
66
+ this tool returned a result" — after which callers commonly fall back to
67
+ composing their own queries against a schema they do not own.
68
+
69
+ Both delegated surfaces now keep template actions native even in dev. A rejected
70
+ `{}` call returns a schema error the model can correct on its next step, which
71
+ is strictly better than a shell loop no caller can see or recover from.
72
+
73
+ - 89e5910: Stop paying for background sweeps and no-change polls that find nothing.
74
+
75
+ A workspace runs one server per app, so every recurring sweep multiplies by app
76
+ count. Several of them queried unconditionally: the 20-second unclaimed-run
77
+ sweep issued two `agent_runs` scans back to back, the A2A continuation retry ran
78
+ two blind `UPDATE`s before ever checking whether anything was due, the MCP config
79
+ refresh scanned the whole settings table every minute to diff a signature that
80
+ had not moved since boot, and the Google Docs poller re-read its config every 30
81
+ seconds even on deployments where the integration was never enabled. On local
82
+ SQLite that was free; on a remote or metered database each one is a network round
83
+ trip, forever, per app.
84
+
85
+ Each of those now leads with a cheap existence probe or an in-process change
86
+ signal, so the idle case costs one round trip instead of several and the work
87
+ still runs the moment there is any. The poll route gets the same treatment: its
88
+ legacy watermark scan read `application_state` four separate times per check,
89
+ and now reads `MAX(updated_at)` once and only fans out when that advances — a
90
+ cost that repeated per app per connected client.
91
+
92
+ Detection latency is unchanged: every probe is a strict superset of the predicate
93
+ it guards, and the negative caches are all narrower than the staleness window
94
+ they sit in front of.
95
+
96
+ - 89e5910: Cut one database round trip from every authenticated request. The membership
97
+ and `active-org-id` reads behind org resolution now overlap instead of queueing,
98
+ and `resolveOrgIdForEmail` memoizes its `org_members` read per request (keyed on
99
+ the AsyncLocalStorage request context and the email) so credential lookups,
100
+ agent runs, A2A, MCP, and adapter-authenticated action calls — none of which
101
+ carry an h3 event — stop each paying their own lookup.
102
+ - 89e5910: Refresh derived database consumers after pool recycling, redact embedded
103
+ credentials from captured tool results, preserve multiline A2A previews, and
104
+ retry MCP configuration refreshes after transient failures.
105
+ - Updated dependencies [89e5910]
106
+ - @agent-native/toolkit@0.12.1
107
+
3
108
  ## 0.131.9
4
109
 
5
110
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Durable Background Runs"
3
- description: "Long agent-chat turns can run on a separate 15-minute Netlify background function instead of the synchronous request, so multi-step work finishes server-side without the client babysitting continuations. Opt-in per app; a foreground circuit-breaker keeps chat working even if the worker never starts."
3
+ description: "Long agent-chat turns can run on a separate 15-minute Netlify background function instead of the synchronous request, so multi-step work finishes server-side without the client babysitting continuations. Enabled by default on deployed Netlify apps with an explicit opt-out; a foreground circuit-breaker keeps chat working even if the worker never starts."
4
4
  ---
5
5
 
6
6
  # Durable Background Runs
@@ -10,7 +10,8 @@ description: "Long agent-chat turns can run on a separate 15-minute Netlify back
10
10
  **Who is this for:** anyone deploying an agent-native app who wants long,
11
11
  multi-step agent turns to complete server-side, and anyone wondering what the
12
12
  `AGENT_CHAT_DURABLE_BACKGROUND` flag and the second Netlify function do. This
13
- is opt-in and entirely inside the framework there is no app code to write.
13
+ is enabled by default on deployed Netlify apps and entirely inside the
14
+ framework — there is no app code to write.
14
15
 
15
16
  </Callout>
16
17
 
@@ -108,14 +109,17 @@ normal API calls always run synchronously on `server`.
108
109
  The foreground chat POST decides **per turn**. It dispatches to the background
109
110
  function only when all three hold:
110
111
 
111
- - `AGENT_CHAT_DURABLE_BACKGROUND` is truthy (`true` / `1` / `yes` / `on`),
112
+ - the app is deployed on Netlify and `AGENT_CHAT_DURABLE_BACKGROUND` is not
113
+ explicitly falsy (`false` / `0` / `no` / `off`), or a non-Netlify hosted app
114
+ explicitly opts in with a truthy value (`true` / `1` / `yes` / `on`),
112
115
  - the app is running hosted (on the platform, not local dev), and
113
116
  - `A2A_SECRET` is set (the dispatch is an HMAC-signed self-call; without the
114
117
  secret it cannot be signed, so the turn stays inline).
115
118
 
116
- If any is missing, the turn runs inline exactly as before. The flag is read at
119
+ If the app is local, `A2A_SECRET` is missing, or the flag is explicitly
120
+ disabled, the turn runs inline exactly as before. The setting is read at
117
121
  **both build time** (to decide whether to emit the background function) and
118
- **runtime** (to decide whether to dispatch), so enabling it requires a redeploy.
122
+ **runtime** (to decide whether to dispatch), so changing it requires a redeploy.
119
123
 
120
124
  ## The lifecycle and the circuit-breaker {#lifecycle}
121
125
 
@@ -190,7 +194,12 @@ one long invocation, not purely additive.
190
194
 
191
195
  <Callout id="doc-block-gjoj2d" tone="info">
192
196
 
193
- Durable runs are opt-in per app and default OFF. Enable with AGENT_CHAT_DURABLE_BACKGROUND=true (plus A2A_SECRET) and redeploy. Verify a turn actually used the worker by checking that its run reaches dispatch_mode=background-processing rather than falling back to inline recovery.
197
+ Durable runs are enabled by default for deployed Netlify apps. Set
198
+ `AGENT_CHAT_DURABLE_BACKGROUND=false` to opt out, or set it to `true` on another
199
+ host. `A2A_SECRET` is still required. Redeploy after changing the setting, and
200
+ verify a turn actually used the worker by checking that its run reaches
201
+ `dispatch_mode=background-processing` rather than falling back to inline
202
+ recovery.
194
203
 
195
204
  </Callout>
196
205
 
@@ -200,7 +200,8 @@ itself checkpoint).
200
200
 
201
201
  > Status: **Phase 0 shipped. Phase 1 + Phase 2 implemented** (the host-agnostic
202
202
  > durable-background worker and the Netlify 15-min `-background` optimization),
203
- > behind `AGENT_CHAT_DURABLE_BACKGROUND`, off by default. Internal per-step
203
+ > default-on for deployed Netlify apps with an explicit opt-out via
204
+ > `AGENT_CHAT_DURABLE_BACKGROUND=false`. Internal per-step
204
205
  > checkpointing (the Option A core of Phase 1) is recommended-not-yet-built; the
205
206
  > worker today gets its durability from the long single invocation plus
206
207
  > server-chained continuations rather than per-step idempotent checkpoints. See
@@ -251,13 +252,14 @@ checkpointed and durable runs remove the ceiling itself.
251
252
 
252
253
  # Final layered architecture
253
254
 
254
- Status: implemented (flagged, off by default)
255
+ Status: implemented (default-on for deployed Netlify, explicit opt-out)
255
256
  Owner: core / run-manager + deploy
256
257
 
257
- Durable background runs ship as **two layers**. Both are gated behind
258
- `AGENT_CHAT_DURABLE_BACKGROUND` and default off; when off, the agent-chat run
259
- path and the deploy output are byte-for-byte the pre-existing synchronous
260
- behavior.
258
+ Durable background runs ship as **two layers**. Deployed Netlify apps enable the
259
+ path by default and can opt out with an explicit falsy
260
+ `AGENT_CHAT_DURABLE_BACKGROUND` value. Other hosted platforms retain explicit
261
+ opt-in. When off, the agent-chat run path and deploy output are byte-for-byte
262
+ the pre-existing synchronous behavior.
261
263
 
262
264
  ### Layer 1 (portable baseline) — host-agnostic durable execution
263
265
 
@@ -600,8 +602,9 @@ Already strong; make the new claim match:
600
602
 
601
603
  > Status: \*\*Slices 0–1 implemented and the Slice-3 background-aware stale window
602
604
  >
603
- > - background→background continuation chaining are implemented\*\*, all behind
604
- > `AGENT_CHAT_DURABLE_BACKGROUND` (off by default). The host-agnostic baseline
605
+ > - background→background continuation chaining are implemented\*\*, default-on
606
+ > for deployed Netlify apps with `AGENT_CHAT_DURABLE_BACKGROUND=false` as the
607
+ > opt-out. The host-agnostic baseline
605
608
  > (Layer 1) carries the run on any host; the Netlify `-background` emit (Layer 2)
606
609
  > is the deploy-time optimization. Slice 2's richer reconnect-first client UX and
607
610
  > the internal per-step checkpointing (Option A) remain follow-ups; Slice 4
@@ -618,9 +621,10 @@ just writes a run event. Dispatch to it from a temporary test route via
618
621
  stub writes an event to `agent_run_events` from the background function, visible
619
622
  via `GET /runs/:id/events`. This de-risks the only genuinely new infra.
620
623
 
621
- **Slice 1 — route the real chat loop through the background function (flagged).**
622
- Behind `AGENT_CHAT_DURABLE_BACKGROUND` (off by default; hosted + `A2A_SECRET`
623
- only): foreground handler inserts the run row, dispatches, returns the SSE
624
+ **Slice 1 — route the real chat loop through the background function.** On
625
+ deployed Netlify it is enabled by default; `AGENT_CHAT_DURABLE_BACKGROUND=false`
626
+ opts out. Other hosted platforms require explicit opt-in, and all hosts require
627
+ `A2A_SECRET`: the foreground handler inserts the run row, dispatches, returns the SSE
624
628
  stream from `subscribeToRun`. The background `_process-run` claims the run and
625
629
  calls the same `startRun` + `runAgentLoop` the inline path uses, with
626
630
  `softTimeoutMs ≈ 13min` (new `backgroundFunction` option in
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.131.9",
3
+ "version": "0.132.1",
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": {
@@ -1,16 +1,27 @@
1
1
  import { sanitizeToolErrorText } from "../agent/tool-error-redaction.js";
2
2
  import type { AgentChatEvent } from "../agent/types.js";
3
+ import { redactArgsToJson, redactTextToSummary } from "../audit/redact.js";
3
4
  import type { DataPart, Part } from "./types.js";
4
5
 
5
6
  export const A2A_AGENT_ACTIVITY_KIND = "agent-native/agent-activity";
6
7
  export const A2A_AGENT_ACTIVITY_VERSION = 1;
7
8
  export const MAX_A2A_ACTIVITY_REASONING_CHARS = 32_768;
8
9
  export const MAX_A2A_ACTIVITY_RESPONSE_CHARS = 32_768;
9
- export const MAX_A2A_ACTIVITY_TOTAL_CHARS = 98_304;
10
10
  export const MAX_A2A_ACTIVITY_REASONING_SEGMENTS = 128;
11
11
  export const MAX_A2A_ACTIVITY_TOOL_CALLS = 64;
12
12
  export const MAX_A2A_ACTIVITY_TOOL_NAME_CHARS = 96;
13
13
  export const MAX_A2A_ACTIVITY_TOOL_ID_CHARS = 128;
14
+ export const MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS = 1024;
15
+ export const MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS = 512;
16
+ /**
17
+ * Shared ceiling for every recorded tool input/result across the snapshot. The
18
+ * per-call caps alone allow 64 × 1536 chars, which would push a busy run past
19
+ * `MAX_A2A_ACTIVITY_TOTAL_CHARS` and make `parseA2AAgentActivityPart` reject
20
+ * the whole snapshot — trading missing arguments for a missing trace.
21
+ */
22
+ export const MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS = 16_384;
23
+ export const MAX_A2A_ACTIVITY_TOTAL_CHARS =
24
+ 98_304 + MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS;
14
25
 
15
26
  export type A2AAgentActivityPhase =
16
27
  | "reasoning"
@@ -25,6 +36,13 @@ export interface A2AAgentActivityToolCall {
25
36
  name: string;
26
37
  id?: string;
27
38
  status: A2AAgentActivityToolStatus;
39
+ /**
40
+ * Redacted, size-capped JSON of the call's arguments. Absent when the call
41
+ * had none, or when the snapshot's shared payload budget was already spent.
42
+ */
43
+ input?: string;
44
+ /** Redacted, size-capped head of the tool result (`tool_done` only). */
45
+ result?: string;
28
46
  }
29
47
 
30
48
  export interface A2AAgentActivitySnapshot extends Record<string, unknown> {
@@ -68,9 +86,11 @@ export function createA2AAgentActivityState(
68
86
  }
69
87
 
70
88
  /**
71
- * Converts internal loop events into a bounded activity snapshot. It carries
72
- * only reasoning text already emitted to the local chat, never tool inputs or
73
- * results.
89
+ * Converts internal loop events into a bounded activity snapshot. Reasoning
90
+ * text is carried verbatim (it was already emitted to the local chat); tool
91
+ * arguments and results are carried only in redacted, size-capped form so the
92
+ * delegated run stays diagnosable without the snapshot becoming a secondary
93
+ * store of secrets or payloads.
74
94
  */
75
95
  export function applyA2AAgentActivityEvent(
76
96
  state: A2AAgentActivityState,
@@ -91,14 +111,26 @@ export function applyA2AAgentActivityEvent(
91
111
  );
92
112
  changed = true;
93
113
  break;
94
- case "tool_start":
114
+ case "tool_start": {
95
115
  next.activePhase = "tool";
96
- next.toolCalls = appendToolCall(next.toolCalls, toolFromEvent(event));
116
+ const input = captureToolInput(
117
+ event.input,
118
+ remainingPayloadBudget(next.toolCalls),
119
+ );
120
+ next.toolCalls = appendToolCall(next.toolCalls, {
121
+ ...toolFromEvent(event),
122
+ ...(input ? { input } : {}),
123
+ });
97
124
  changed = true;
98
125
  break;
126
+ }
99
127
  case "tool_done":
100
128
  next.activePhase = "tool";
101
- next.toolCalls = settleToolCall(next.toolCalls, toolFromEvent(event));
129
+ next.toolCalls = settleToolCall(
130
+ next.toolCalls,
131
+ toolFromEvent(event),
132
+ event,
133
+ );
102
134
  changed = true;
103
135
  break;
104
136
  case "text":
@@ -203,6 +235,49 @@ function toolFromEvent(
203
235
  };
204
236
  }
205
237
 
238
+ function payloadChars(tool: A2AAgentActivityToolCall): number {
239
+ return (tool.input?.length ?? 0) + (tool.result?.length ?? 0);
240
+ }
241
+
242
+ function remainingPayloadBudget(
243
+ current: A2AAgentActivityToolCall[],
244
+ excludeIndex = -1,
245
+ ): number {
246
+ const used = current.reduce(
247
+ (total, tool, index) =>
248
+ index === excludeIndex ? total : total + payloadChars(tool),
249
+ 0,
250
+ );
251
+ return Math.max(0, MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS - used);
252
+ }
253
+
254
+ /**
255
+ * Redacted, capped JSON of the arguments, or `undefined` when there is nothing
256
+ * to record or the shared budget cannot fit a whole (still-parseable) capture.
257
+ * A partial JSON string would be worse than none — the reader could not tell a
258
+ * clipped object from a different one.
259
+ */
260
+ function captureToolInput(input: unknown, budget: number): string | undefined {
261
+ const cap = Math.min(MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS, budget);
262
+ if (cap < MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS / 8) return undefined;
263
+ const json = redactArgsToJson(input, { maxJson: cap, maxString: 256 });
264
+ // JSON.stringify escapes control characters, so the result is already safe
265
+ // for the snapshot without a `sanitizeText` pass — which would rewrite
266
+ // `"token":"[redacted]"` into unparseable JSON.
267
+ if (!json || json === "{}" || json.length > cap) return undefined;
268
+ return json;
269
+ }
270
+
271
+ function captureToolResult(
272
+ result: string | undefined,
273
+ budget: number,
274
+ ): string | undefined {
275
+ const cap = Math.min(MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS, budget);
276
+ if (!result || cap <= 0) return undefined;
277
+ const summary = redactTextToSummary(result, cap);
278
+ return summary ? sanitizeText(summary, cap) || undefined : undefined;
279
+ }
280
+
206
281
  function appendBoundedSegment(
207
282
  current: string[],
208
283
  addition: string,
@@ -244,6 +319,7 @@ function appendToolCall(
244
319
  function settleToolCall(
245
320
  current: A2AAgentActivityToolCall[],
246
321
  tool: A2AAgentActivityToolCall,
322
+ event: Extract<AgentChatEvent, { type: "tool_done" }>,
247
323
  ): A2AAgentActivityToolCall[] {
248
324
  for (let index = current.length - 1; index >= 0; index -= 1) {
249
325
  const existing = current[index];
@@ -251,12 +327,32 @@ function settleToolCall(
251
327
  (tool.id && tool.id === existing.id) ||
252
328
  (!tool.id && tool.name === existing.name)
253
329
  ) {
330
+ // The matching `tool_start` already paid for its input; reuse it rather
331
+ // than re-capturing (and re-charging) the same arguments.
332
+ let budget = remainingPayloadBudget(current, index);
333
+ const input =
334
+ existing.input ?? captureToolInput(event.input, budget) ?? undefined;
335
+ budget -= input?.length ?? 0;
336
+ const result = captureToolResult(event.result, budget);
337
+ const settled: A2AAgentActivityToolCall = {
338
+ ...tool,
339
+ ...(input ? { input } : {}),
340
+ ...(result ? { result } : {}),
341
+ };
254
342
  return current.map((value, itemIndex) =>
255
- itemIndex === index ? tool : value,
343
+ itemIndex === index ? settled : value,
256
344
  );
257
345
  }
258
346
  }
259
- return appendToolCall(current, tool);
347
+ let budget = remainingPayloadBudget(current);
348
+ const input = captureToolInput(event.input, budget);
349
+ budget -= input?.length ?? 0;
350
+ const result = captureToolResult(event.result, budget);
351
+ return appendToolCall(current, {
352
+ ...tool,
353
+ ...(input ? { input } : {}),
354
+ ...(result ? { result } : {}),
355
+ });
260
356
  }
261
357
 
262
358
  function sanitizeText(value: string, maxChars: number): string {
@@ -320,12 +416,31 @@ function isSafeToolCall(value: unknown): value is A2AAgentActivityToolCall {
320
416
  if (!isRecord(value) || !isSafeToolName(value.name)) return false;
321
417
  return (
322
418
  (value.id === undefined || isSafeToolId(value.id)) &&
419
+ (value.input === undefined ||
420
+ isSafeCapturedText(value.input, MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS)) &&
421
+ (value.result === undefined ||
422
+ isSafeCapturedText(value.result, MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS)) &&
323
423
  (value.status === "running" ||
324
424
  value.status === "completed" ||
325
425
  value.status === "failed")
326
426
  );
327
427
  }
328
428
 
429
+ /**
430
+ * Captured input/result are producer-side redacted strings. Unlike reasoning
431
+ * text they are NOT re-sanitized on read: `sanitizeToolErrorText` rewrites
432
+ * `"token":"…"` into unparseable JSON, so a round-trip equality check would
433
+ * reject every legitimate capture. Bound the length and reject raw control
434
+ * characters instead.
435
+ */
436
+ function isSafeCapturedText(value: unknown, maxChars: number): value is string {
437
+ return (
438
+ typeof value === "string" &&
439
+ value.length <= maxChars &&
440
+ !/[\u0000-\u0008\u000b-\u001f\u007f]/.test(value)
441
+ );
442
+ }
443
+
329
444
  function isSafeText(value: unknown, maxChars: number): value is string {
330
445
  return (
331
446
  typeof value === "string" &&
@@ -365,7 +480,9 @@ function activityCharacterCount(data: Record<string, unknown>): number {
365
480
  return (
366
481
  total +
367
482
  (typeof tool.name === "string" ? tool.name.length : 0) +
368
- (typeof tool.id === "string" ? tool.id.length : 0)
483
+ (typeof tool.id === "string" ? tool.id.length : 0) +
484
+ (typeof tool.input === "string" ? tool.input.length : 0) +
485
+ (typeof tool.result === "string" ? tool.result.length : 0)
369
486
  );
370
487
  }, 0)
371
488
  : 0;
@@ -11,7 +11,10 @@ export {
11
11
  MAX_A2A_ACTIVITY_TOOL_CALLS,
12
12
  MAX_A2A_ACTIVITY_TOTAL_CHARS,
13
13
  MAX_A2A_ACTIVITY_TOOL_ID_CHARS,
14
+ MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS,
14
15
  MAX_A2A_ACTIVITY_TOOL_NAME_CHARS,
16
+ MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS,
17
+ MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS,
15
18
  applyA2AAgentActivityEvent,
16
19
  buildA2AAgentActivityPart,
17
20
  buildA2AAgentActivitySnapshot,
@@ -8,6 +8,7 @@ import type {
8
8
  ActionTool,
9
9
  AgentChatAttachment,
10
10
  AgentChatEvent,
11
+ AgentNativeJsonSchema,
11
12
  } from "./agent/types.js";
12
13
  import { normalizeAuditConfig, resolveAuditAttach } from "./audit/config.js";
13
14
  import type { ActionAuditConfig } from "./audit/types.js";
@@ -1445,6 +1446,52 @@ function coerceGatewayStringifiedArgs(
1445
1446
  return out ?? args;
1446
1447
  }
1447
1448
 
1449
+ // The enums and required members that actually explain a rejection are usually
1450
+ // nested inside `items`/`oneOf` (a discriminated union of operations), not on
1451
+ // the top-level property, so rendering only the top level prints `operations*:
1452
+ // array` — true and useless. Bounded depth keeps a deep schema from crowding out
1453
+ // the validation errors it is meant to explain.
1454
+ const MAX_SIGNATURE_DEPTH = 4;
1455
+ const MAX_SIGNATURE_LENGTH = 1200;
1456
+
1457
+ function describeSchemaType(
1458
+ spec: AgentNativeJsonSchema | undefined,
1459
+ depth: number,
1460
+ ): string {
1461
+ if (!spec) return "any";
1462
+ if (spec.const !== undefined) return JSON.stringify(spec.const);
1463
+ if (Array.isArray(spec.enum)) {
1464
+ return spec.enum.map((value) => JSON.stringify(value)).join("|");
1465
+ }
1466
+
1467
+ const branches = spec.oneOf ?? spec.anyOf;
1468
+ if (branches?.length) {
1469
+ if (depth >= MAX_SIGNATURE_DEPTH) return "object";
1470
+ return branches
1471
+ .map((branch) => describeSchemaType(branch, depth))
1472
+ .join(" | ");
1473
+ }
1474
+
1475
+ if (spec.properties && Object.keys(spec.properties).length > 0) {
1476
+ if (depth >= MAX_SIGNATURE_DEPTH) return "object";
1477
+ const required = new Set(spec.required ?? []);
1478
+ const members = Object.entries(spec.properties)
1479
+ .map(
1480
+ ([key, value]) =>
1481
+ `${key}${required.has(key) ? "*" : "?"}: ${describeSchemaType(value, depth + 1)}`,
1482
+ )
1483
+ .join(", ");
1484
+ return `{ ${members} }`;
1485
+ }
1486
+
1487
+ if (spec.items) {
1488
+ if (depth >= MAX_SIGNATURE_DEPTH) return "array";
1489
+ return `array<${describeSchemaType(spec.items, depth + 1)}>`;
1490
+ }
1491
+
1492
+ return Array.isArray(spec.type) ? spec.type.join("|") : (spec.type ?? "any");
1493
+ }
1494
+
1448
1495
  /**
1449
1496
  * Compact signature of an action's parameters, e.g.
1450
1497
  * `{ deckId*: string, operation*: "edit"|"replace", slideId?: string }` where
@@ -1469,19 +1516,13 @@ export function describeToolParameterSignature(
1469
1516
  (key) => !only?.length || only.includes(key),
1470
1517
  );
1471
1518
  const sig = (keys.length ? keys : Object.keys(properties))
1472
- .map((key) => {
1473
- const spec = properties[key];
1474
- const mark = required.has(key) ? "*" : "?";
1475
- const type = Array.isArray(spec.enum)
1476
- ? spec.enum.map((value) => JSON.stringify(value)).join("|")
1477
- : Array.isArray(spec.type)
1478
- ? spec.type.join("|")
1479
- : (spec.type ?? "any");
1480
- return `${key}${mark}: ${type}`;
1481
- })
1519
+ .map(
1520
+ (key) =>
1521
+ `${key}${required.has(key) ? "*" : "?"}: ${describeSchemaType(properties[key], 1)}`,
1522
+ )
1482
1523
  .join(", ");
1483
1524
  if (!sig) return null;
1484
- return `{ ${sig.length > 600 ? `${sig.slice(0, 600)}…` : sig} }`;
1525
+ return `{ ${sig.length > MAX_SIGNATURE_LENGTH ? `${sig.slice(0, MAX_SIGNATURE_LENGTH)}…` : sig} }`;
1485
1526
  }
1486
1527
 
1487
1528
  /**