@agent-native/core 0.7.7 → 0.7.11

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 (338) hide show
  1. package/dist/agent/engine/ai-sdk-engine.d.ts +14 -2
  2. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  3. package/dist/agent/engine/ai-sdk-engine.js +70 -54
  4. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  5. package/dist/agent/engine/anthropic-engine.d.ts +1 -6
  6. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  7. package/dist/agent/engine/anthropic-engine.js +3 -14
  8. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  9. package/dist/agent/engine/builtin.d.ts.map +1 -1
  10. package/dist/agent/engine/builtin.js +3 -0
  11. package/dist/agent/engine/builtin.js.map +1 -1
  12. package/dist/agent/engine/translate-ai-sdk.d.ts +35 -10
  13. package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
  14. package/dist/agent/engine/translate-ai-sdk.js +190 -91
  15. package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
  16. package/dist/agent/engine/types.d.ts +10 -1
  17. package/dist/agent/engine/types.d.ts.map +1 -1
  18. package/dist/agent/production-agent.d.ts +15 -1
  19. package/dist/agent/production-agent.d.ts.map +1 -1
  20. package/dist/agent/production-agent.js +78 -21
  21. package/dist/agent/production-agent.js.map +1 -1
  22. package/dist/agent/thread-data-builder.js +1 -1
  23. package/dist/agent/thread-data-builder.js.map +1 -1
  24. package/dist/agent/types.d.ts +4 -0
  25. package/dist/agent/types.d.ts.map +1 -1
  26. package/dist/application-state/script-helpers.d.ts +12 -5
  27. package/dist/application-state/script-helpers.d.ts.map +1 -1
  28. package/dist/application-state/script-helpers.js +41 -20
  29. package/dist/application-state/script-helpers.js.map +1 -1
  30. package/dist/catalog.json +15 -0
  31. package/dist/chat-threads/store.d.ts.map +1 -1
  32. package/dist/chat-threads/store.js +7 -5
  33. package/dist/chat-threads/store.js.map +1 -1
  34. package/dist/checkpoints/index.d.ts +3 -0
  35. package/dist/checkpoints/index.d.ts.map +1 -0
  36. package/dist/checkpoints/index.js +3 -0
  37. package/dist/checkpoints/index.js.map +1 -0
  38. package/dist/checkpoints/service.d.ts +6 -0
  39. package/dist/checkpoints/service.d.ts.map +1 -0
  40. package/dist/checkpoints/service.js +107 -0
  41. package/dist/checkpoints/service.js.map +1 -0
  42. package/dist/checkpoints/store.d.ts +27 -0
  43. package/dist/checkpoints/store.d.ts.map +1 -0
  44. package/dist/checkpoints/store.js +92 -0
  45. package/dist/checkpoints/store.js.map +1 -0
  46. package/dist/cli/create.d.ts.map +1 -1
  47. package/dist/cli/create.js +85 -1
  48. package/dist/cli/create.js.map +1 -1
  49. package/dist/cli/index.js +46 -3
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/cli/templates-meta.d.ts.map +1 -1
  52. package/dist/cli/templates-meta.js +33 -0
  53. package/dist/cli/templates-meta.js.map +1 -1
  54. package/dist/client/AgentPanel.d.ts.map +1 -1
  55. package/dist/client/AgentPanel.js +3 -1
  56. package/dist/client/AgentPanel.js.map +1 -1
  57. package/dist/client/AssistantChat.d.ts +15 -0
  58. package/dist/client/AssistantChat.d.ts.map +1 -1
  59. package/dist/client/AssistantChat.js +145 -67
  60. package/dist/client/AssistantChat.js.map +1 -1
  61. package/dist/client/CommandMenu.d.ts.map +1 -1
  62. package/dist/client/CommandMenu.js +9 -5
  63. package/dist/client/CommandMenu.js.map +1 -1
  64. package/dist/client/ConnectBuilderCard.js +1 -1
  65. package/dist/client/ConnectBuilderCard.js.map +1 -1
  66. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  67. package/dist/client/MultiTabAssistantChat.js +78 -4
  68. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  69. package/dist/client/agent-chat-adapter.d.ts +6 -0
  70. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  71. package/dist/client/agent-chat-adapter.js +4 -0
  72. package/dist/client/agent-chat-adapter.js.map +1 -1
  73. package/dist/client/composer/TiptapComposer.d.ts +12 -1
  74. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  75. package/dist/client/composer/TiptapComposer.js +71 -3
  76. package/dist/client/composer/TiptapComposer.js.map +1 -1
  77. package/dist/client/notifications/NotificationsBell.d.ts +23 -0
  78. package/dist/client/notifications/NotificationsBell.d.ts.map +1 -0
  79. package/dist/client/notifications/NotificationsBell.js +165 -0
  80. package/dist/client/notifications/NotificationsBell.js.map +1 -0
  81. package/dist/client/notifications/index.d.ts +2 -0
  82. package/dist/client/notifications/index.d.ts.map +1 -0
  83. package/dist/client/notifications/index.js +2 -0
  84. package/dist/client/notifications/index.js.map +1 -0
  85. package/dist/client/onboarding/OnboardingPanel.js +6 -3
  86. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  87. package/dist/client/progress/RunsTray.d.ts +18 -0
  88. package/dist/client/progress/RunsTray.d.ts.map +1 -0
  89. package/dist/client/progress/RunsTray.js +70 -0
  90. package/dist/client/progress/RunsTray.js.map +1 -0
  91. package/dist/client/progress/index.d.ts +2 -0
  92. package/dist/client/progress/index.d.ts.map +1 -0
  93. package/dist/client/progress/index.js +2 -0
  94. package/dist/client/progress/index.js.map +1 -0
  95. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  96. package/dist/client/resources/ResourcesPanel.js +19 -4
  97. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  98. package/dist/client/settings/AutomationsSection.d.ts +2 -0
  99. package/dist/client/settings/AutomationsSection.d.ts.map +1 -0
  100. package/dist/client/settings/AutomationsSection.js +214 -0
  101. package/dist/client/settings/AutomationsSection.js.map +1 -0
  102. package/dist/client/settings/ComingSoonSection.d.ts.map +1 -1
  103. package/dist/client/settings/ComingSoonSection.js +2 -1
  104. package/dist/client/settings/ComingSoonSection.js.map +1 -1
  105. package/dist/client/settings/LLMSection.d.ts.map +1 -1
  106. package/dist/client/settings/LLMSection.js +137 -10
  107. package/dist/client/settings/LLMSection.js.map +1 -1
  108. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  109. package/dist/client/settings/SecretsSection.js +122 -3
  110. package/dist/client/settings/SecretsSection.js.map +1 -1
  111. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  112. package/dist/client/settings/SettingsPanel.js +140 -11
  113. package/dist/client/settings/SettingsPanel.js.map +1 -1
  114. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  115. package/dist/client/settings/VoiceTranscriptionSection.js +2 -2
  116. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  117. package/dist/client/use-pausing-interval.d.ts +11 -0
  118. package/dist/client/use-pausing-interval.d.ts.map +1 -0
  119. package/dist/client/use-pausing-interval.js +49 -0
  120. package/dist/client/use-pausing-interval.js.map +1 -0
  121. package/dist/db/client.d.ts +26 -0
  122. package/dist/db/client.d.ts.map +1 -1
  123. package/dist/db/client.js +84 -2
  124. package/dist/db/client.js.map +1 -1
  125. package/dist/db/drizzle-config.d.ts +33 -0
  126. package/dist/db/drizzle-config.d.ts.map +1 -0
  127. package/dist/db/drizzle-config.js +132 -0
  128. package/dist/db/drizzle-config.js.map +1 -0
  129. package/dist/db/migrations.d.ts.map +1 -1
  130. package/dist/db/migrations.js +11 -6
  131. package/dist/db/migrations.js.map +1 -1
  132. package/dist/deploy/build.js +2 -1
  133. package/dist/deploy/build.js.map +1 -1
  134. package/dist/event-bus/bus.d.ts +20 -0
  135. package/dist/event-bus/bus.d.ts.map +1 -0
  136. package/dist/event-bus/bus.js +108 -0
  137. package/dist/event-bus/bus.js.map +1 -0
  138. package/dist/event-bus/index.d.ts +4 -0
  139. package/dist/event-bus/index.d.ts.map +1 -0
  140. package/dist/event-bus/index.js +3 -0
  141. package/dist/event-bus/index.js.map +1 -0
  142. package/dist/event-bus/registry.d.ts +22 -0
  143. package/dist/event-bus/registry.d.ts.map +1 -0
  144. package/dist/event-bus/registry.js +63 -0
  145. package/dist/event-bus/registry.js.map +1 -0
  146. package/dist/event-bus/types.d.ts +27 -0
  147. package/dist/event-bus/types.d.ts.map +1 -0
  148. package/dist/event-bus/types.js +2 -0
  149. package/dist/event-bus/types.js.map +1 -0
  150. package/dist/integrations/config-store.d.ts.map +1 -1
  151. package/dist/integrations/config-store.js +16 -12
  152. package/dist/integrations/config-store.js.map +1 -1
  153. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  154. package/dist/integrations/google-docs-poller.js +5 -1
  155. package/dist/integrations/google-docs-poller.js.map +1 -1
  156. package/dist/jobs/scheduler.d.ts.map +1 -1
  157. package/dist/jobs/scheduler.js +7 -3
  158. package/dist/jobs/scheduler.js.map +1 -1
  159. package/dist/notifications/actions.d.ts +10 -0
  160. package/dist/notifications/actions.d.ts.map +1 -0
  161. package/dist/notifications/actions.js +114 -0
  162. package/dist/notifications/actions.js.map +1 -0
  163. package/dist/notifications/channels.d.ts +15 -0
  164. package/dist/notifications/channels.d.ts.map +1 -0
  165. package/dist/notifications/channels.js +97 -0
  166. package/dist/notifications/channels.js.map +1 -0
  167. package/dist/notifications/index.d.ts +4 -0
  168. package/dist/notifications/index.d.ts.map +1 -0
  169. package/dist/notifications/index.js +3 -0
  170. package/dist/notifications/index.js.map +1 -0
  171. package/dist/notifications/registry.d.ts +9 -0
  172. package/dist/notifications/registry.d.ts.map +1 -0
  173. package/dist/notifications/registry.js +146 -0
  174. package/dist/notifications/registry.js.map +1 -0
  175. package/dist/notifications/routes.d.ts +34 -0
  176. package/dist/notifications/routes.d.ts.map +1 -0
  177. package/dist/notifications/routes.js +69 -0
  178. package/dist/notifications/routes.js.map +1 -0
  179. package/dist/notifications/store.d.ts +25 -0
  180. package/dist/notifications/store.d.ts.map +1 -0
  181. package/dist/notifications/store.js +158 -0
  182. package/dist/notifications/store.js.map +1 -0
  183. package/dist/notifications/types.d.ts +43 -0
  184. package/dist/notifications/types.d.ts.map +1 -0
  185. package/dist/notifications/types.js +2 -0
  186. package/dist/notifications/types.js.map +1 -0
  187. package/dist/org/handlers.d.ts.map +1 -1
  188. package/dist/org/handlers.js +7 -26
  189. package/dist/org/handlers.js.map +1 -1
  190. package/dist/progress/actions.d.ts +8 -0
  191. package/dist/progress/actions.d.ts.map +1 -0
  192. package/dist/progress/actions.js +158 -0
  193. package/dist/progress/actions.js.map +1 -0
  194. package/dist/progress/index.d.ts +3 -0
  195. package/dist/progress/index.d.ts.map +1 -0
  196. package/dist/progress/index.js +2 -0
  197. package/dist/progress/index.js.map +1 -0
  198. package/dist/progress/registry.d.ts +22 -0
  199. package/dist/progress/registry.d.ts.map +1 -0
  200. package/dist/progress/registry.js +98 -0
  201. package/dist/progress/registry.js.map +1 -0
  202. package/dist/progress/routes.d.ts +21 -0
  203. package/dist/progress/routes.d.ts.map +1 -0
  204. package/dist/progress/routes.js +59 -0
  205. package/dist/progress/routes.js.map +1 -0
  206. package/dist/progress/store.d.ts +7 -0
  207. package/dist/progress/store.d.ts.map +1 -0
  208. package/dist/progress/store.js +195 -0
  209. package/dist/progress/store.js.map +1 -0
  210. package/dist/progress/types.d.ts +49 -0
  211. package/dist/progress/types.d.ts.map +1 -0
  212. package/dist/progress/types.js +7 -0
  213. package/dist/progress/types.js.map +1 -0
  214. package/dist/resources/store.d.ts.map +1 -1
  215. package/dist/resources/store.js +19 -15
  216. package/dist/resources/store.js.map +1 -1
  217. package/dist/secrets/index.d.ts +3 -2
  218. package/dist/secrets/index.d.ts.map +1 -1
  219. package/dist/secrets/index.js +3 -2
  220. package/dist/secrets/index.js.map +1 -1
  221. package/dist/secrets/routes.d.ts +41 -2
  222. package/dist/secrets/routes.d.ts.map +1 -1
  223. package/dist/secrets/routes.js +167 -1
  224. package/dist/secrets/routes.js.map +1 -1
  225. package/dist/secrets/schema.d.ts +39 -1
  226. package/dist/secrets/schema.d.ts.map +1 -1
  227. package/dist/secrets/schema.js +6 -0
  228. package/dist/secrets/schema.js.map +1 -1
  229. package/dist/secrets/storage.d.ts +26 -0
  230. package/dist/secrets/storage.d.ts.map +1 -1
  231. package/dist/secrets/storage.js +111 -5
  232. package/dist/secrets/storage.js.map +1 -1
  233. package/dist/secrets/substitution.d.ts +39 -0
  234. package/dist/secrets/substitution.d.ts.map +1 -0
  235. package/dist/secrets/substitution.js +93 -0
  236. package/dist/secrets/substitution.js.map +1 -0
  237. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  238. package/dist/server/agent-chat-plugin.js +1657 -1410
  239. package/dist/server/agent-chat-plugin.js.map +1 -1
  240. package/dist/server/auth.d.ts +11 -0
  241. package/dist/server/auth.d.ts.map +1 -1
  242. package/dist/server/auth.js +74 -21
  243. package/dist/server/auth.js.map +1 -1
  244. package/dist/server/better-auth-instance.d.ts.map +1 -1
  245. package/dist/server/better-auth-instance.js +34 -16
  246. package/dist/server/better-auth-instance.js.map +1 -1
  247. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  248. package/dist/server/core-routes-plugin.js +115 -1
  249. package/dist/server/core-routes-plugin.js.map +1 -1
  250. package/dist/server/email-templates.d.ts +43 -0
  251. package/dist/server/email-templates.d.ts.map +1 -0
  252. package/dist/server/email-templates.js +86 -0
  253. package/dist/server/email-templates.js.map +1 -0
  254. package/dist/server/framework-request-handler.d.ts +15 -0
  255. package/dist/server/framework-request-handler.d.ts.map +1 -1
  256. package/dist/server/framework-request-handler.js +64 -1
  257. package/dist/server/framework-request-handler.js.map +1 -1
  258. package/dist/server/onboarding-html.d.ts +11 -0
  259. package/dist/server/onboarding-html.d.ts.map +1 -1
  260. package/dist/server/onboarding-html.js +275 -16
  261. package/dist/server/onboarding-html.js.map +1 -1
  262. package/dist/server/schema-prompt.d.ts.map +1 -1
  263. package/dist/server/schema-prompt.js +5 -0
  264. package/dist/server/schema-prompt.js.map +1 -1
  265. package/dist/shared/index.d.ts +1 -0
  266. package/dist/shared/index.d.ts.map +1 -1
  267. package/dist/shared/index.js +1 -0
  268. package/dist/shared/index.js.map +1 -1
  269. package/dist/shared/truncate.d.ts +8 -0
  270. package/dist/shared/truncate.d.ts.map +1 -0
  271. package/dist/shared/truncate.js +12 -0
  272. package/dist/shared/truncate.js.map +1 -0
  273. package/dist/templates/default/.agents/skills/agent-engines/SKILL.md +60 -4
  274. package/dist/templates/default/.agents/skills/notifications/SKILL.md +95 -0
  275. package/dist/templates/default/.agents/skills/progress/SKILL.md +97 -0
  276. package/dist/templates/default/AGENTS.md +12 -10
  277. package/dist/templates/default/package.json +10 -10
  278. package/dist/templates/workspace-core/package.json +5 -5
  279. package/dist/templates/workspace-root/package.json +1 -1
  280. package/dist/templates/workspace-root/tsconfig.base.json +1 -2
  281. package/dist/tools/fetch-tool.d.ts +22 -0
  282. package/dist/tools/fetch-tool.d.ts.map +1 -0
  283. package/dist/tools/fetch-tool.js +156 -0
  284. package/dist/tools/fetch-tool.js.map +1 -0
  285. package/dist/tracking/index.d.ts +4 -0
  286. package/dist/tracking/index.d.ts.map +1 -0
  287. package/dist/tracking/index.js +3 -0
  288. package/dist/tracking/index.js.map +1 -0
  289. package/dist/tracking/providers.d.ts +15 -0
  290. package/dist/tracking/providers.d.ts.map +1 -0
  291. package/dist/tracking/providers.js +195 -0
  292. package/dist/tracking/providers.js.map +1 -0
  293. package/dist/tracking/registry.d.ts +10 -0
  294. package/dist/tracking/registry.d.ts.map +1 -0
  295. package/dist/tracking/registry.js +75 -0
  296. package/dist/tracking/registry.js.map +1 -0
  297. package/dist/tracking/types.d.ts +13 -0
  298. package/dist/tracking/types.d.ts.map +1 -0
  299. package/dist/tracking/types.js +2 -0
  300. package/dist/tracking/types.js.map +1 -0
  301. package/dist/triggers/actions.d.ts +10 -0
  302. package/dist/triggers/actions.d.ts.map +1 -0
  303. package/dist/triggers/actions.js +277 -0
  304. package/dist/triggers/actions.js.map +1 -0
  305. package/dist/triggers/condition-evaluator.d.ts +15 -0
  306. package/dist/triggers/condition-evaluator.d.ts.map +1 -0
  307. package/dist/triggers/condition-evaluator.js +107 -0
  308. package/dist/triggers/condition-evaluator.js.map +1 -0
  309. package/dist/triggers/dispatcher.d.ts +32 -0
  310. package/dist/triggers/dispatcher.d.ts.map +1 -0
  311. package/dist/triggers/dispatcher.js +291 -0
  312. package/dist/triggers/dispatcher.js.map +1 -0
  313. package/dist/triggers/index.d.ts +5 -0
  314. package/dist/triggers/index.d.ts.map +1 -0
  315. package/dist/triggers/index.js +4 -0
  316. package/dist/triggers/index.js.map +1 -0
  317. package/dist/triggers/types.d.ts +35 -0
  318. package/dist/triggers/types.d.ts.map +1 -0
  319. package/dist/triggers/types.js +9 -0
  320. package/dist/triggers/types.js.map +1 -0
  321. package/dist/vite/client.d.ts.map +1 -1
  322. package/dist/vite/client.js +66 -16
  323. package/dist/vite/client.js.map +1 -1
  324. package/docs/content/automations.md +239 -0
  325. package/docs/content/multi-tenancy.md +88 -0
  326. package/docs/content/notifications.md +199 -0
  327. package/docs/content/progress.md +176 -0
  328. package/docs/content/tracking.md +168 -0
  329. package/package.json +54 -35
  330. package/src/templates/default/.agents/skills/agent-engines/SKILL.md +60 -4
  331. package/src/templates/default/.agents/skills/notifications/SKILL.md +95 -0
  332. package/src/templates/default/.agents/skills/progress/SKILL.md +97 -0
  333. package/src/templates/default/AGENTS.md +12 -10
  334. package/src/templates/default/package.json +10 -10
  335. package/src/templates/workspace-core/package.json +5 -5
  336. package/src/templates/workspace-root/package.json +1 -1
  337. package/src/templates/workspace-root/tsconfig.base.json +1 -2
  338. package/tsconfig.base.json +1 -1
@@ -0,0 +1,176 @@
1
+ ---
2
+ title: "Progress"
3
+ description: "Live progress signal for long-running agent tasks — start, update, complete"
4
+ ---
5
+
6
+ # Progress
7
+
8
+ Long agent tasks shouldn't hide behind a spinner. `progress_runs` gives the agent a way to announce _"I'm working on this, I'm 45% done, here's the current step"_ — which the UI renders as a floating runs tray with a percent bar.
9
+
10
+ ```ts
11
+ import {
12
+ startRun,
13
+ updateRunProgress,
14
+ completeRun,
15
+ } from "@agent-native/core/progress";
16
+
17
+ const run = await startRun({
18
+ owner: "steve@builder.io",
19
+ title: "Triage 128 unread emails",
20
+ step: "Fetching inbox",
21
+ });
22
+
23
+ for (let i = 1; i <= total; i++) {
24
+ await updateRunProgress(run.id, run.owner, {
25
+ percent: Math.round((i / total) * 100),
26
+ step: `Classifying ${i}/${total}`,
27
+ });
28
+ }
29
+
30
+ await completeRun(run.id, run.owner, "succeeded");
31
+ ```
32
+
33
+ Separate concern from [notifications](/docs/notifications): notifications fire once (_"X happened"_), progress is continuous state (_"X is 45% done"_). The two compose — `completeRun` followed by `notify(..., severity: "info")` tells the user when the work finishes even if they weren't watching the tray.
34
+
35
+ ## The lifecycle {#lifecycle}
36
+
37
+ | Status | Transition |
38
+ | ----------- | --------------------------- |
39
+ | `running` | Initial — set by `startRun` |
40
+ | `succeeded` | Happy-path terminal |
41
+ | `failed` | Error terminal |
42
+ | `cancelled` | User interrupted |
43
+
44
+ Terminal statuses set `completed_at`. The UI tray shows only `running` rows; completed rows stay in the database for `list-runs` queries.
45
+
46
+ ## API {#api}
47
+
48
+ ### `startRun(input)` {#start}
49
+
50
+ Create a run. Returns the full `AgentRun` with a generated id.
51
+
52
+ ```ts
53
+ const run = await startRun({
54
+ owner: "steve@builder.io",
55
+ title: "Ingest 1M rows",
56
+ step: "Opening CSV",
57
+ metadata: { jobId: "abc123", artifactPath: "s3://..." },
58
+ });
59
+ ```
60
+
61
+ Emits `run.progress.started` on the event bus.
62
+
63
+ ### `updateRunProgress(id, owner, input)` {#update}
64
+
65
+ Patch any field of a running run. Any omitted field stays unchanged.
66
+
67
+ ```ts
68
+ await updateRunProgress(run.id, run.owner, {
69
+ percent: 75,
70
+ step: "Writing to target DB",
71
+ });
72
+ ```
73
+
74
+ Emits `run.progress.updated` on the event bus. Returns the updated `AgentRun`, or `null` if the run doesn't exist or isn't owned by the caller.
75
+
76
+ ### `completeRun(id, owner, status, extras?)` {#complete}
77
+
78
+ Transition to a terminal status. `succeeded` implicitly sets `percent=100`.
79
+
80
+ ```ts
81
+ await completeRun(run.id, run.owner, "succeeded", {
82
+ step: "All 1M rows ingested",
83
+ metadata: { totalDurationMs: 98_123 },
84
+ });
85
+ ```
86
+
87
+ Also emits `run.progress.updated` with the terminal status.
88
+
89
+ ### Listing {#list}
90
+
91
+ ```ts
92
+ import { listRuns, getRun, deleteRun } from "@agent-native/core/progress";
93
+
94
+ const active = await listRuns("steve@builder.io", { activeOnly: true });
95
+ const run = await getRun("run-id", "steve@builder.io");
96
+ await deleteRun("run-id", "steve@builder.io");
97
+ ```
98
+
99
+ ## HTTP API {#http}
100
+
101
+ Mounted at `/_agent-native/runs/*` by the core-routes plugin. **Read-only over HTTP** — writes go through the agent tools since the agent is the canonical writer. All routes are owner-scoped.
102
+
103
+ | Method | Path |
104
+ | -------- | --------------------------------- |
105
+ | `GET` | `/_agent-native/runs?active=true` |
106
+ | `GET` | `/_agent-native/runs/:id` |
107
+ | `DELETE` | `/_agent-native/runs/:id` |
108
+
109
+ ## UI component {#ui}
110
+
111
+ ```tsx
112
+ import { RunsTray } from "@agent-native/core/client/progress";
113
+
114
+ export function HeaderBar() {
115
+ return (
116
+ <header className="flex items-center gap-2">
117
+ {/* … */}
118
+ <RunsTray />
119
+ </header>
120
+ );
121
+ }
122
+ ```
123
+
124
+ Inline header widget — mount it next to the notifications bell. Shows a spinner icon + count badge when runs are active; click opens a dropdown with one live percent bar per run. Hides the trigger entirely when no active runs. Polls `/_agent-native/runs?active=true` every `pollMs` (default 3 s). Uses shadcn semantic tokens, adapts to light and dark themes.
125
+
126
+ ## Agent tools {#agent-tools}
127
+
128
+ Four native tools are registered in every template:
129
+
130
+ | Tool | Purpose |
131
+ | --------------------- | --------------------------------------------------------------- |
132
+ | `start-run` | Call at the top of a long task. Returns a runId. |
133
+ | `update-run-progress` | Call periodically during the task with `percent` and/or `step`. |
134
+ | `complete-run` | Terminal — one of `succeeded`, `failed`, `cancelled`. |
135
+ | `list-runs` | Inspect recent runs (filter by `active=true`). |
136
+
137
+ ### When to start a run {#when-to-start}
138
+
139
+ - Use for anything > ~5 seconds. A spinner with no context feels frozen.
140
+ - Update at natural checkpoints, not every iteration. Every 5–10% is plenty.
141
+ - **Always** call `complete-run`, including in error paths. An orphan `running` row is worse than no row.
142
+ - Pair with `notify` on completion so the user sees the outcome when they're not actively watching the tray.
143
+
144
+ ## Event bus {#event-bus}
145
+
146
+ Two events emit on the [event bus](/docs/automations#event-bus):
147
+
148
+ | Event | Payload |
149
+ | ---------------------- | ---------------------------------- |
150
+ | `run.progress.started` | `{ runId, title, step? }` |
151
+ | `run.progress.updated` | `{ runId, percent, step, status }` |
152
+
153
+ [Automations](/docs/automations) can subscribe to these — for example, _"if a run takes longer than 5 minutes, notify me"_:
154
+
155
+ ```yaml
156
+ ---
157
+ triggerType: event
158
+ event: run.progress.updated
159
+ condition: "status is running and (now - started) > 5 minutes"
160
+ mode: agentic
161
+ ---
162
+ Notify me that run {{runId}} has been running for a long time.
163
+ ```
164
+
165
+ ## How it works {#internals}
166
+
167
+ - **Owner scoping** — every row has an `owner` column; every query filters on it. Users see only their own runs.
168
+ - **Poll integration** — every mutation calls `recordChange()` so templates using [`useDbSync`](/docs/client) auto-invalidate without any extra wiring.
169
+ - **Table name** — the framework also has an `agent_runs` table for internal agent-chat turn lifecycle tracking. The progress primitive uses `progress_runs` to keep the two concerns separate.
170
+ - **Percent clamping** — values are clamped to `[0, 100]` and rounded to an integer on write.
171
+
172
+ ## What's next
173
+
174
+ - [**Notifications**](/docs/notifications) — pair with `complete-run` to tell the user when work finishes
175
+ - [**Automations**](/docs/automations) — watchdog slow runs via `run.progress.updated`
176
+ - [**Client**](/docs/client) — `useDbSync` for real-time cache invalidation
@@ -0,0 +1,168 @@
1
+ ---
2
+ title: "Analytics Tracking"
3
+ description: "Server-side analytics with pluggable providers — PostHog, Mixpanel, Amplitude, or custom webhook"
4
+ ---
5
+
6
+ # Analytics Tracking
7
+
8
+ One function, multiple destinations. Call `track()` from any server-side code — actions, plugins, server routes — and the event fans out to every registered analytics provider. No SDK dependencies, no client-side scripts, no blocking.
9
+
10
+ ```ts
11
+ import { track } from "@agent-native/core/tracking";
12
+
13
+ track(
14
+ "order.completed",
15
+ { total: 49.99, items: 3 },
16
+ { userId: "steve@builder.io" },
17
+ );
18
+ ```
19
+
20
+ ## Built-in providers {#built-in}
21
+
22
+ Set an env var and the provider auto-registers at server startup. No code changes required.
23
+
24
+ | Provider | Env vars |
25
+ | --------- | ----------------------------------------------------------------------------------------------- |
26
+ | PostHog | `POSTHOG_API_KEY` (required), `POSTHOG_HOST` (optional, defaults to `https://us.i.posthog.com`) |
27
+ | Mixpanel | `MIXPANEL_TOKEN` |
28
+ | Amplitude | `AMPLITUDE_API_KEY` |
29
+ | Webhook | `TRACKING_WEBHOOK_URL` (required), `TRACKING_WEBHOOK_AUTH` (optional `Authorization` header) |
30
+
31
+ Multiple providers can be active simultaneously. Every event goes to all of them.
32
+
33
+ ## API {#api}
34
+
35
+ ### `track(name, properties?, meta?)` {#track}
36
+
37
+ Fire an analytics event. Fans out to all registered providers.
38
+
39
+ ```ts
40
+ import { track } from "@agent-native/core/tracking";
41
+
42
+ track(
43
+ "meal.logged",
44
+ { mealName: "Salad", calories: 350 },
45
+ { userId: "steve@builder.io" },
46
+ );
47
+ ```
48
+
49
+ ### `identify(userId, traits?)` {#identify}
50
+
51
+ Identify a user with traits. Forwarded to providers that support it (PostHog, Mixpanel, Amplitude, webhook).
52
+
53
+ ```ts
54
+ import { identify } from "@agent-native/core/tracking";
55
+
56
+ identify("steve@builder.io", { plan: "pro", company: "Builder.io" });
57
+ ```
58
+
59
+ ### `registerTrackingProvider(provider)` {#register}
60
+
61
+ Register a custom provider for any analytics backend.
62
+
63
+ ```ts
64
+ import { registerTrackingProvider } from "@agent-native/core/tracking";
65
+
66
+ registerTrackingProvider({
67
+ name: "my-analytics",
68
+ track(event) {
69
+ // Send event to your backend
70
+ fetch("https://analytics.example.com/events", {
71
+ method: "POST",
72
+ headers: { "Content-Type": "application/json" },
73
+ body: JSON.stringify(event),
74
+ }).catch(() => {});
75
+ },
76
+ identify(userId, traits) {
77
+ // Optional — link user identity to future events
78
+ },
79
+ flush() {
80
+ // Optional — called on graceful shutdown
81
+ },
82
+ });
83
+ ```
84
+
85
+ ### `flushTracking()` {#flush}
86
+
87
+ Flush all providers. Call before process exit to ensure pending events are sent.
88
+
89
+ ```ts
90
+ import { flushTracking } from "@agent-native/core/tracking";
91
+
92
+ await flushTracking();
93
+ ```
94
+
95
+ ### `unregisterTrackingProvider(name)` {#unregister}
96
+
97
+ Remove a provider by name. Returns `true` if the provider was found and removed.
98
+
99
+ ### `listTrackingProviders()` {#list}
100
+
101
+ Returns the names of all registered providers.
102
+
103
+ ## The TrackingProvider interface {#provider-interface}
104
+
105
+ ```ts
106
+ interface TrackingProvider {
107
+ name: string;
108
+ track(event: TrackingEvent): void | Promise<void>;
109
+ identify?(
110
+ userId: string,
111
+ traits?: Record<string, unknown>,
112
+ ): void | Promise<void>;
113
+ flush?(): void | Promise<void>;
114
+ }
115
+
116
+ interface TrackingEvent {
117
+ name: string;
118
+ properties?: Record<string, unknown>;
119
+ timestamp?: string;
120
+ userId?: string;
121
+ }
122
+ ```
123
+
124
+ Only `name` and `track` are required. `identify` and `flush` are optional — implement them if your backend supports user identity and batched delivery.
125
+
126
+ ## How it works {#internals}
127
+
128
+ - **Batched HTTP** — built-in providers enqueue events and flush every 10 seconds or when 50 events accumulate, whichever comes first. This minimizes outbound requests without losing data.
129
+ - **No SDK dependencies** — all built-in providers use raw `fetch()`. No PostHog SDK, no Mixpanel SDK, no Amplitude SDK. Keeps the framework lightweight.
130
+ - **Best-effort delivery** — provider errors are caught and logged. A failing analytics integration never crashes the caller or blocks request handling.
131
+ - **Global singleton** — the registry uses a `Symbol.for` key on `globalThis` so multiple ESM graph instances (dev-mode Vite + Nitro, symlinks) share one provider set.
132
+
133
+ ## Using track() in templates {#templates}
134
+
135
+ Call `track()` from action handlers to record user or agent activity:
136
+
137
+ ```ts
138
+ // actions/create-project.ts
139
+ import { defineAction } from "@agent-native/core";
140
+ import { track } from "@agent-native/core/tracking";
141
+ import { z } from "zod";
142
+
143
+ export default defineAction({
144
+ description: "Create a new project.",
145
+ schema: z.object({
146
+ name: z.string(),
147
+ template: z.string().optional(),
148
+ }),
149
+ run: async ({ name, template }, ctx) => {
150
+ const project = await db
151
+ .insert(projects)
152
+ .values({ name, template })
153
+ .returning();
154
+
155
+ track("project.created", { name, template }, { userId: ctx.userEmail });
156
+
157
+ return { ok: true, projectId: project[0].id };
158
+ },
159
+ });
160
+ ```
161
+
162
+ Track calls are fire-and-forget — they return immediately and never block the action response.
163
+
164
+ ## What's next
165
+
166
+ - [**Actions**](/docs/actions) — where most tracking calls originate
167
+ - [**Server Plugins**](/docs/server) — `registerBuiltinProviders()` runs in the core-routes plugin at startup
168
+ - [**Secrets**](/docs/security) — manage API keys for tracking providers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.7.7",
3
+ "version": "0.7.11",
4
4
  "type": "module",
5
5
  "description": "Framework for agent-native application development — where AI agents and UI share state via files",
6
6
  "license": "MIT",
@@ -24,6 +24,7 @@
24
24
  "./server/request-context": "./dist/server/request-context.js",
25
25
  "./db": "./dist/db/index.js",
26
26
  "./db/schema": "./dist/db/schema.js",
27
+ "./db/drizzle-config": "./dist/db/drizzle-config.js",
27
28
  "./client": "./dist/client/index.js",
28
29
  "./client/onboarding": "./dist/client/onboarding/index.js",
29
30
  "./onboarding": "./dist/onboarding/index.js",
@@ -32,6 +33,8 @@
32
33
  "./application-state": "./dist/application-state/index.js",
33
34
  "./settings": "./dist/settings/index.js",
34
35
  "./credentials": "./dist/credentials/index.js",
36
+ "./event-bus": "./dist/event-bus/index.js",
37
+ "./fetch-tool": "./dist/tools/fetch-tool.js",
35
38
  "./file-upload": "./dist/file-upload/index.js",
36
39
  "./resources": "./dist/resources/index.js",
37
40
  "./resources/store": "./dist/resources/store.js",
@@ -52,10 +55,17 @@
52
55
  "./a2a": "./dist/a2a/index.js",
53
56
  "./mcp": "./dist/mcp/index.js",
54
57
  "./mcp-client": "./dist/mcp-client/index.js",
58
+ "./tracking": "./dist/tracking/index.js",
59
+ "./notifications": "./dist/notifications/index.js",
60
+ "./client/notifications": "./dist/client/notifications/index.js",
61
+ "./progress": "./dist/progress/index.js",
62
+ "./client/progress": "./dist/client/progress/index.js",
63
+ "./triggers": "./dist/triggers/index.js",
55
64
  "./terminal": "./dist/client/terminal/index.js",
56
65
  "./terminal/server": "./dist/terminal/index.js",
57
66
  "./tailwind": "./dist/tailwind.preset.js",
58
67
  "./styles/agent-native.css": "./dist/styles/agent-native.css",
68
+ "./agent/engine": "./dist/agent/engine/index.js",
59
69
  "./tsconfig.base.json": "./tsconfig.base.json"
60
70
  },
61
71
  "files": [
@@ -65,7 +75,7 @@
65
75
  "src/templates"
66
76
  ],
67
77
  "scripts": {
68
- "build": "tsc && rm -rf dist/templates && cp -r src/templates dist/templates && mkdir -p dist/styles && cp src/styles/*.css dist/styles/",
78
+ "build": "tsc && node scripts/finalize-build.mjs",
69
79
  "dev": "tsc --watch",
70
80
  "typecheck": "tsc --noEmit",
71
81
  "test": "vitest --run",
@@ -74,7 +84,7 @@
74
84
  "release": "npm version patch && npm publish --access public"
75
85
  },
76
86
  "dependencies": {
77
- "@anthropic-ai/sdk": "^0.80.0",
87
+ "@anthropic-ai/sdk": "^0.90.0",
78
88
  "@clack/prompts": "^1.2.0",
79
89
  "@libsql/client": "^0.15.0",
80
90
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -104,45 +114,47 @@
104
114
  "isbot": "^5",
105
115
  "jose": "^6.2.2",
106
116
  "minimatch": "^10.0.0",
107
- "nanoid": "^4.0.2",
108
- "nitro": "3.0.260311-beta",
117
+ "nanoid": "^5.1.9",
118
+ "nitro": "3.0.260415-beta",
109
119
  "p-limit": "^7.3.0",
110
120
  "react-markdown": "^10.1.0",
111
121
  "react-router": "^7.13.1",
112
122
  "remark-gfm": "^4.0.1",
113
123
  "shiki": "^4.0.2",
114
- "tailwind-merge": "^2.6.0",
124
+ "tailwind-merge": "^3.5.0",
115
125
  "tiptap-markdown": "^0.9.0",
116
126
  "y-protocols": "^1.0.7",
117
127
  "yjs": "^13.6.30",
118
- "zod": "^3.24.0"
128
+ "zod": "^4.3.6"
119
129
  },
120
130
  "peerDependencies": {
121
- "@ai-sdk/anthropic": ">=1",
122
- "@ai-sdk/cohere": ">=1",
123
- "@ai-sdk/google": ">=1",
124
- "@ai-sdk/groq": ">=1",
125
- "@ai-sdk/mistral": ">=1",
126
- "@ai-sdk/openai": ">=1",
131
+ "@ai-sdk/anthropic": ">=3",
132
+ "@ai-sdk/cohere": ">=3",
133
+ "@ai-sdk/google": ">=3",
134
+ "@ai-sdk/groq": ">=3",
135
+ "@ai-sdk/mistral": ">=3",
136
+ "@ai-sdk/openai": ">=3",
127
137
  "@assistant-ui/react": ">=0.12",
128
138
  "@assistant-ui/react-markdown": ">=0.12",
139
+ "@openrouter/ai-sdk-provider": ">=2",
129
140
  "@supabase/supabase-js": ">=2",
130
141
  "@tabler/icons-react": ">=3",
142
+ "@tailwindcss/vite": ">=4",
131
143
  "@tanstack/react-query": ">=5",
132
144
  "@vitejs/plugin-react-swc": ">=4",
133
- "@xterm/addon-fit": ">=0.10",
134
- "@xterm/addon-web-links": ">=0.11",
135
- "@xterm/xterm": ">=5",
136
- "ai": ">=4",
145
+ "@xterm/addon-fit": ">=0.11",
146
+ "@xterm/addon-web-links": ">=0.12",
147
+ "@xterm/xterm": ">=6",
148
+ "ai": ">=6",
149
+ "ai-sdk-ollama": ">=3",
137
150
  "convex": ">=1",
151
+ "drizzle-kit": ">=0.31",
138
152
  "node-pty": ">=1",
139
- "ollama-ai-provider": ">=1",
140
153
  "postgres": ">=3",
141
154
  "react": ">=18",
142
155
  "react-dom": ">=18",
143
156
  "react-router": ">=7",
144
157
  "tailwindcss": ">=4",
145
- "@tailwindcss/vite": ">=4",
146
158
  "typescript": ">=5",
147
159
  "vite": ">=5",
148
160
  "ws": ">=8"
@@ -157,6 +169,9 @@
157
169
  "@ai-sdk/openai": {
158
170
  "optional": true
159
171
  },
172
+ "@openrouter/ai-sdk-provider": {
173
+ "optional": true
174
+ },
160
175
  "@ai-sdk/google": {
161
176
  "optional": true
162
177
  },
@@ -169,7 +184,7 @@
169
184
  "@ai-sdk/cohere": {
170
185
  "optional": true
171
186
  },
172
- "ollama-ai-provider": {
187
+ "ai-sdk-ollama": {
173
188
  "optional": true
174
189
  },
175
190
  "@tabler/icons-react": {
@@ -199,6 +214,9 @@
199
214
  "convex": {
200
215
  "optional": true
201
216
  },
217
+ "drizzle-kit": {
218
+ "optional": true
219
+ },
202
220
  "@xterm/xterm": {
203
221
  "optional": true
204
222
  },
@@ -219,39 +237,40 @@
219
237
  }
220
238
  },
221
239
  "devDependencies": {
222
- "@ai-sdk/anthropic": "^1.2.12",
223
- "@ai-sdk/google": "^1.2.22",
224
- "@ai-sdk/groq": "^1.2.9",
225
- "@ai-sdk/openai": "^1.3.24",
240
+ "@ai-sdk/anthropic": "^3.0.71",
241
+ "@ai-sdk/google": "^3.0.64",
242
+ "@ai-sdk/groq": "^3.0.35",
243
+ "@ai-sdk/openai": "^3.0.53",
226
244
  "@assistant-ui/react": "^0.12.19",
227
245
  "@assistant-ui/react-markdown": "^0.12.6",
228
246
  "@react-router/dev": "^7.13.1",
229
247
  "@react-router/fs-routes": "^7.13.1",
230
248
  "@supabase/supabase-js": "^2.49.0",
231
249
  "@tabler/icons-react": "^3.40.0",
232
- "@tanstack/react-query": "^5.84.2",
250
+ "@tailwindcss/vite": "catalog:",
251
+ "@tanstack/react-query": "^5.99.2",
233
252
  "@types/better-sqlite3": "^7.6.13",
234
253
  "@types/diff-match-patch": "^1.0.36",
235
254
  "@types/express": "^5.0.6",
236
255
  "@types/node": "^24.2.1",
237
- "@types/react": "^18.3.23",
256
+ "@types/react": "^19.2.14",
238
257
  "@types/ws": "^8.18.1",
239
258
  "@vitejs/plugin-react-swc": "^4.0.0",
240
- "@xterm/addon-fit": "^0.10.0",
241
- "@xterm/addon-web-links": "^0.11.0",
242
- "@xterm/xterm": "^5.5.0",
243
- "ai": "^4.3.19",
259
+ "@xterm/addon-fit": "^0.11.0",
260
+ "@xterm/addon-web-links": "^0.12.0",
261
+ "@xterm/xterm": "^6.0.0",
262
+ "ai": "^6.0.168",
244
263
  "autoprefixer": "^10.4.21",
264
+ "drizzle-kit": "^0.31.10",
245
265
  "express": "^5.2.1",
246
266
  "firebase-admin": "^13.0.0",
247
267
  "node-pty": "^1.1.0",
248
- "react": "^18.3.1",
268
+ "react": "^19.2.5",
249
269
  "react-router": "^7.13.1",
250
270
  "tailwindcss": "catalog:",
251
- "@tailwindcss/vite": "catalog:",
252
- "typescript": "^5.9.2",
253
- "vite": "^8.0.0",
254
- "vitest": "^3.2.4",
271
+ "typescript": "^6.0.3",
272
+ "vite": "catalog:",
273
+ "vitest": "^4.1.5",
255
274
  "ws": "^8.18.0"
256
275
  }
257
276
  }
@@ -59,6 +59,7 @@ Returns `{ ok, latencyMs, response, capabilities }`. If `ok: false`, the error m
59
59
  | `anthropic` | Anthropic Claude SDK | `ANTHROPIC_API_KEY` |
60
60
  | `ai-sdk:anthropic` | Claude via Vercel AI SDK | `ANTHROPIC_API_KEY` |
61
61
  | `ai-sdk:openai` | OpenAI via Vercel AI SDK | `OPENAI_API_KEY` |
62
+ | `ai-sdk:openrouter` | 300+ models (Anthropic, OpenAI, Google, Meta, …) routed through OpenRouter | `OPENROUTER_API_KEY` |
62
63
  | `ai-sdk:google` | Google Gemini via Vercel AI SDK | `GOOGLE_GENERATIVE_AI_API_KEY` |
63
64
  | `ai-sdk:groq` | Groq LPU via Vercel AI SDK | `GROQ_API_KEY` |
64
65
  | `ai-sdk:mistral` | Mistral via Vercel AI SDK | `MISTRAL_API_KEY` |
@@ -86,13 +87,41 @@ When using the `anthropic` engine (or `ai-sdk:anthropic`):
86
87
 
87
88
  These features are silently ignored when a non-Anthropic engine is active (capability-gated, no breakage).
88
89
 
90
+ ## Using OpenRouter
91
+
92
+ `ai-sdk:openrouter` gives access to 300+ models from many providers through a single API. Model IDs use the `vendor/model` form:
93
+
94
+ ```
95
+ set-agent-engine --engine "ai-sdk:openrouter" --model "anthropic/claude-sonnet-4.5"
96
+ set-agent-engine --engine "ai-sdk:openrouter" --model "openai/gpt-4o"
97
+ set-agent-engine --engine "ai-sdk:openrouter" --model "google/gemini-2.5-pro"
98
+ ```
99
+
100
+ Any `vendor/model` string from [openrouter.ai/models](https://openrouter.ai/models) works — the `supportedModels` list in the registry is a UI hint, not an allow-list.
101
+
102
+ **App attribution** (optional): pass `appName` / `appUrl` in the engine config to set the `X-OpenRouter-Title` / `HTTP-Referer` headers — useful to see your app on the OpenRouter dashboard and leaderboards:
103
+
104
+ ```ts
105
+ createAISDKEngine("openrouter", {
106
+ apiKey: process.env.OPENROUTER_API_KEY,
107
+ appName: "My App",
108
+ appUrl: "https://myapp.example",
109
+ });
110
+ ```
111
+
89
112
  ## Registering a Custom Engine
90
113
 
91
- Register custom engines in a server plugin at startup:
114
+ Register custom engines in a server plugin at startup. Import from the
115
+ `@agent-native/core/agent/engine` subpath:
92
116
 
93
117
  ```ts
94
118
  // server/plugins/my-engine.ts
95
- import { registerAgentEngine } from "@agent-native/core/server";
119
+ import {
120
+ registerAgentEngine,
121
+ type AgentEngine,
122
+ type EngineEvent,
123
+ type EngineStreamOptions,
124
+ } from "@agent-native/core/agent/engine";
96
125
 
97
126
  registerAgentEngine({
98
127
  name: "my-engine",
@@ -108,11 +137,37 @@ registerAgentEngine({
108
137
  defaultModel: "my-model-v1",
109
138
  supportedModels: ["my-model-v1", "my-model-v2"],
110
139
  requiredEnvVars: ["MY_ENGINE_API_KEY"],
111
- create: (config) => new MyEngine(config),
140
+ create: (config): AgentEngine => ({
141
+ name: "my-engine",
142
+ label: "My Custom Engine",
143
+ defaultModel: "my-model-v1",
144
+ supportedModels: ["my-model-v1", "my-model-v2"],
145
+ capabilities: {
146
+ /* same shape as above */
147
+ } as any,
148
+ async *stream(opts: EngineStreamOptions): AsyncIterable<EngineEvent> {
149
+ // yield text-delta / thinking-delta / tool-call / usage events
150
+ // as they arrive, then:
151
+ yield { type: "assistant-content", parts: /* final content parts */ [] };
152
+ yield { type: "stop", reason: "end_turn" };
153
+ },
154
+ }),
112
155
  });
113
156
  ```
114
157
 
115
- After registering, the engine appears in `list-agent-engines` output and can be selected via `set-agent-engine`.
158
+ ### Engine stream contract
159
+
160
+ Every engine's `stream(opts)` MUST emit, in order:
161
+
162
+ 1. Zero or more `text-delta`, `thinking-delta`, `tool-call`, and `usage`
163
+ events as they arrive from the model.
164
+ 2. Exactly one `{ type: "assistant-content", parts }` event with the
165
+ structured content for the turn. `runAgentLoop` reads this to
166
+ reconstruct the assistant message for the next turn.
167
+ 3. Exactly one terminal `{ type: "stop", reason }` event.
168
+
169
+ After registering, the engine appears in `list-agent-engines` output and can
170
+ be selected via `set-agent-engine`.
116
171
 
117
172
  ## Env Vars Reference
118
173
 
@@ -120,6 +175,7 @@ After registering, the engine appears in `list-agent-engines` output and can be
120
175
  |---|---|
121
176
  | `ANTHROPIC_API_KEY` | Required for `anthropic` and `ai-sdk:anthropic` engines |
122
177
  | `OPENAI_API_KEY` | Required for `ai-sdk:openai` |
178
+ | `OPENROUTER_API_KEY` | Required for `ai-sdk:openrouter` |
123
179
  | `GOOGLE_GENERATIVE_AI_API_KEY` | Required for `ai-sdk:google` |
124
180
  | `GROQ_API_KEY` | Required for `ai-sdk:groq` |
125
181
  | `MISTRAL_API_KEY` | Required for `ai-sdk:mistral` |