@agent-native/core 0.7.12 → 0.7.13

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 (302) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  3. package/dist/agent/engine/ai-sdk-engine.js +26 -8
  4. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  5. package/dist/agent/engine/builder-engine.d.ts +19 -0
  6. package/dist/agent/engine/builder-engine.d.ts.map +1 -0
  7. package/dist/agent/engine/builder-engine.js +430 -0
  8. package/dist/agent/engine/builder-engine.js.map +1 -0
  9. package/dist/agent/engine/builtin.d.ts.map +1 -1
  10. package/dist/agent/engine/builtin.js +26 -10
  11. package/dist/agent/engine/builtin.js.map +1 -1
  12. package/dist/agent/engine/index.d.ts +1 -1
  13. package/dist/agent/engine/index.d.ts.map +1 -1
  14. package/dist/agent/engine/index.js +1 -1
  15. package/dist/agent/engine/index.js.map +1 -1
  16. package/dist/agent/engine/registry.d.ts +20 -1
  17. package/dist/agent/engine/registry.d.ts.map +1 -1
  18. package/dist/agent/engine/registry.js +49 -1
  19. package/dist/agent/engine/registry.js.map +1 -1
  20. package/dist/agent/engine/types.d.ts +30 -0
  21. package/dist/agent/engine/types.d.ts.map +1 -1
  22. package/dist/agent/engine/types.js +19 -1
  23. package/dist/agent/engine/types.js.map +1 -1
  24. package/dist/agent/production-agent.d.ts.map +1 -1
  25. package/dist/agent/production-agent.js +65 -7
  26. package/dist/agent/production-agent.js.map +1 -1
  27. package/dist/agent/run-manager.d.ts.map +1 -1
  28. package/dist/agent/run-manager.js +11 -1
  29. package/dist/agent/run-manager.js.map +1 -1
  30. package/dist/agent/thread-data-builder.d.ts +4 -0
  31. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  32. package/dist/agent/thread-data-builder.js +1 -0
  33. package/dist/agent/thread-data-builder.js.map +1 -1
  34. package/dist/agent/types.d.ts +8 -0
  35. package/dist/agent/types.d.ts.map +1 -1
  36. package/dist/checkpoints/service.d.ts +1 -0
  37. package/dist/checkpoints/service.d.ts.map +1 -1
  38. package/dist/checkpoints/service.js +26 -2
  39. package/dist/checkpoints/service.js.map +1 -1
  40. package/dist/cli/create.d.ts +30 -0
  41. package/dist/cli/create.d.ts.map +1 -1
  42. package/dist/cli/create.js +25 -13
  43. package/dist/cli/create.js.map +1 -1
  44. package/dist/client/AgentPanel.js +1 -1
  45. package/dist/client/AgentPanel.js.map +1 -1
  46. package/dist/client/AssistantChat.d.ts.map +1 -1
  47. package/dist/client/AssistantChat.js +49 -10
  48. package/dist/client/AssistantChat.js.map +1 -1
  49. package/dist/client/ConnectBuilderCard.d.ts +1 -7
  50. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  51. package/dist/client/ConnectBuilderCard.js +30 -132
  52. package/dist/client/ConnectBuilderCard.js.map +1 -1
  53. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  54. package/dist/client/MultiTabAssistantChat.js +30 -9
  55. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  56. package/dist/client/analytics.d.ts +5 -8
  57. package/dist/client/analytics.d.ts.map +1 -1
  58. package/dist/client/analytics.js +53 -11
  59. package/dist/client/analytics.js.map +1 -1
  60. package/dist/client/builder-mark.d.ts +9 -0
  61. package/dist/client/builder-mark.d.ts.map +1 -0
  62. package/dist/client/builder-mark.js +10 -0
  63. package/dist/client/builder-mark.js.map +1 -0
  64. package/dist/client/components/ui/popover.d.ts +8 -0
  65. package/dist/client/components/ui/popover.d.ts.map +1 -0
  66. package/dist/client/components/ui/popover.js +11 -0
  67. package/dist/client/components/ui/popover.js.map +1 -0
  68. package/dist/client/composer/ComposerPlusMenu.d.ts +2 -0
  69. package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -0
  70. package/dist/client/composer/ComposerPlusMenu.js +244 -0
  71. package/dist/client/composer/ComposerPlusMenu.js.map +1 -0
  72. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  73. package/dist/client/composer/TiptapComposer.js +9 -5
  74. package/dist/client/composer/TiptapComposer.js.map +1 -1
  75. package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
  76. package/dist/client/composer/useVoiceDictation.js +4 -2
  77. package/dist/client/composer/useVoiceDictation.js.map +1 -1
  78. package/dist/client/error-format.d.ts +2 -0
  79. package/dist/client/error-format.d.ts.map +1 -0
  80. package/dist/client/error-format.js +31 -0
  81. package/dist/client/error-format.js.map +1 -0
  82. package/dist/client/index.d.ts +3 -1
  83. package/dist/client/index.d.ts.map +1 -1
  84. package/dist/client/index.js +3 -1
  85. package/dist/client/index.js.map +1 -1
  86. package/dist/client/observability/ObservabilityDashboard.d.ts +5 -0
  87. package/dist/client/observability/ObservabilityDashboard.d.ts.map +1 -0
  88. package/dist/client/observability/ObservabilityDashboard.js +169 -0
  89. package/dist/client/observability/ObservabilityDashboard.js.map +1 -0
  90. package/dist/client/observability/ThumbsFeedback.d.ts +8 -0
  91. package/dist/client/observability/ThumbsFeedback.d.ts.map +1 -0
  92. package/dist/client/observability/ThumbsFeedback.js +64 -0
  93. package/dist/client/observability/ThumbsFeedback.js.map +1 -0
  94. package/dist/client/observability/index.d.ts +4 -0
  95. package/dist/client/observability/index.d.ts.map +1 -0
  96. package/dist/client/observability/index.js +4 -0
  97. package/dist/client/observability/index.js.map +1 -0
  98. package/dist/client/observability/useObservability.d.ts +128 -0
  99. package/dist/client/observability/useObservability.d.ts.map +1 -0
  100. package/dist/client/observability/useObservability.js +109 -0
  101. package/dist/client/observability/useObservability.js.map +1 -0
  102. package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
  103. package/dist/client/onboarding/OnboardingPanel.js +34 -92
  104. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  105. package/dist/client/org/RequireActiveOrg.d.ts +33 -0
  106. package/dist/client/org/RequireActiveOrg.d.ts.map +1 -0
  107. package/dist/client/org/RequireActiveOrg.js +63 -0
  108. package/dist/client/org/RequireActiveOrg.js.map +1 -0
  109. package/dist/client/org/hooks.d.ts.map +1 -1
  110. package/dist/client/org/hooks.js +50 -15
  111. package/dist/client/org/hooks.js.map +1 -1
  112. package/dist/client/org/index.d.ts +1 -0
  113. package/dist/client/org/index.d.ts.map +1 -1
  114. package/dist/client/org/index.js +1 -0
  115. package/dist/client/org/index.js.map +1 -1
  116. package/dist/client/resources/ResourcesPanel.js +3 -3
  117. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  118. package/dist/client/settings/AutomationsSection.js +1 -1
  119. package/dist/client/settings/AutomationsSection.js.map +1 -1
  120. package/dist/client/settings/BrowserSection.js +1 -1
  121. package/dist/client/settings/BrowserSection.js.map +1 -1
  122. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  123. package/dist/client/settings/SettingsPanel.js +112 -12
  124. package/dist/client/settings/SettingsPanel.js.map +1 -1
  125. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  126. package/dist/client/settings/VoiceTranscriptionSection.js +10 -4
  127. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  128. package/dist/client/settings/useBuilderStatus.d.ts +26 -0
  129. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  130. package/dist/client/settings/useBuilderStatus.js +128 -4
  131. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  132. package/dist/client/sse-event-processor.d.ts +2 -0
  133. package/dist/client/sse-event-processor.d.ts.map +1 -1
  134. package/dist/client/sse-event-processor.js +6 -2
  135. package/dist/client/sse-event-processor.js.map +1 -1
  136. package/dist/client/transcription/BuilderTranscriptionCta.d.ts +9 -0
  137. package/dist/client/transcription/BuilderTranscriptionCta.d.ts.map +1 -0
  138. package/dist/client/transcription/BuilderTranscriptionCta.js +18 -0
  139. package/dist/client/transcription/BuilderTranscriptionCta.js.map +1 -0
  140. package/dist/client/transcription/use-live-transcription.d.ts +29 -0
  141. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -0
  142. package/dist/client/transcription/use-live-transcription.js +156 -0
  143. package/dist/client/transcription/use-live-transcription.js.map +1 -0
  144. package/dist/client/use-builder-enabled.d.ts +17 -0
  145. package/dist/client/use-builder-enabled.d.ts.map +1 -0
  146. package/dist/client/use-builder-enabled.js +36 -0
  147. package/dist/client/use-builder-enabled.js.map +1 -0
  148. package/dist/client/use-db-sync.d.ts.map +1 -1
  149. package/dist/client/use-db-sync.js +4 -2
  150. package/dist/client/use-db-sync.js.map +1 -1
  151. package/dist/client/useProductionAgent.d.ts.map +1 -1
  152. package/dist/client/useProductionAgent.js +3 -1
  153. package/dist/client/useProductionAgent.js.map +1 -1
  154. package/dist/db/migrations.d.ts +9 -0
  155. package/dist/db/migrations.d.ts.map +1 -1
  156. package/dist/db/migrations.js +75 -10
  157. package/dist/db/migrations.js.map +1 -1
  158. package/dist/file-upload/builder.d.ts.map +1 -1
  159. package/dist/file-upload/builder.js +11 -4
  160. package/dist/file-upload/builder.js.map +1 -1
  161. package/dist/jobs/tools.d.ts.map +1 -1
  162. package/dist/jobs/tools.js +137 -161
  163. package/dist/jobs/tools.js.map +1 -1
  164. package/dist/notifications/actions.d.ts +2 -2
  165. package/dist/notifications/actions.d.ts.map +1 -1
  166. package/dist/notifications/actions.js +77 -69
  167. package/dist/notifications/actions.js.map +1 -1
  168. package/dist/observability/evals.d.ts +22 -0
  169. package/dist/observability/evals.d.ts.map +1 -0
  170. package/dist/observability/evals.js +371 -0
  171. package/dist/observability/evals.js.map +1 -0
  172. package/dist/observability/experiments.d.ts +24 -0
  173. package/dist/observability/experiments.d.ts.map +1 -0
  174. package/dist/observability/experiments.js +274 -0
  175. package/dist/observability/experiments.js.map +1 -0
  176. package/dist/observability/feedback.d.ts +14 -0
  177. package/dist/observability/feedback.d.ts.map +1 -0
  178. package/dist/observability/feedback.js +256 -0
  179. package/dist/observability/feedback.js.map +1 -0
  180. package/dist/observability/index.d.ts +6 -0
  181. package/dist/observability/index.d.ts.map +1 -0
  182. package/dist/observability/index.js +5 -0
  183. package/dist/observability/index.js.map +1 -0
  184. package/dist/observability/plugin.d.ts +2 -0
  185. package/dist/observability/plugin.d.ts.map +1 -0
  186. package/dist/observability/plugin.js +12 -0
  187. package/dist/observability/plugin.js.map +1 -0
  188. package/dist/observability/routes.d.ts +68 -0
  189. package/dist/observability/routes.d.ts.map +1 -0
  190. package/dist/observability/routes.js +301 -0
  191. package/dist/observability/routes.js.map +1 -0
  192. package/dist/observability/store.d.ts +77 -0
  193. package/dist/observability/store.d.ts.map +1 -0
  194. package/dist/observability/store.js +976 -0
  195. package/dist/observability/store.js.map +1 -0
  196. package/dist/observability/traces.d.ts +37 -0
  197. package/dist/observability/traces.d.ts.map +1 -0
  198. package/dist/observability/traces.js +182 -0
  199. package/dist/observability/traces.js.map +1 -0
  200. package/dist/observability/types.d.ts +159 -0
  201. package/dist/observability/types.d.ts.map +1 -0
  202. package/dist/observability/types.js +16 -0
  203. package/dist/observability/types.js.map +1 -0
  204. package/dist/onboarding/default-steps.d.ts.map +1 -1
  205. package/dist/onboarding/default-steps.js +6 -5
  206. package/dist/onboarding/default-steps.js.map +1 -1
  207. package/dist/onboarding/types.d.ts +10 -1
  208. package/dist/onboarding/types.d.ts.map +1 -1
  209. package/dist/org/context.d.ts +8 -1
  210. package/dist/org/context.d.ts.map +1 -1
  211. package/dist/org/context.js +163 -6
  212. package/dist/org/context.js.map +1 -1
  213. package/dist/org/handlers.d.ts.map +1 -1
  214. package/dist/org/handlers.js +49 -30
  215. package/dist/org/handlers.js.map +1 -1
  216. package/dist/progress/actions.d.ts +3 -0
  217. package/dist/progress/actions.d.ts.map +1 -1
  218. package/dist/progress/actions.js +86 -110
  219. package/dist/progress/actions.js.map +1 -1
  220. package/dist/progress/routes.d.ts +1 -1
  221. package/dist/progress/routes.js +1 -1
  222. package/dist/scripts/agent-engines/list-agent-engines.js +1 -1
  223. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  224. package/dist/scripts/agent-engines/manage-agent-engine.d.ts +10 -0
  225. package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -0
  226. package/dist/scripts/agent-engines/manage-agent-engine.js +47 -0
  227. package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -0
  228. package/dist/scripts/agent-engines/set-agent-engine.js +2 -2
  229. package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
  230. package/dist/server/agent-chat-plugin.d.ts +39 -0
  231. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  232. package/dist/server/agent-chat-plugin.js +707 -443
  233. package/dist/server/agent-chat-plugin.js.map +1 -1
  234. package/dist/server/agent-teams.js +1 -1
  235. package/dist/server/agent-teams.js.map +1 -1
  236. package/dist/server/analytics.d.ts +5 -6
  237. package/dist/server/analytics.d.ts.map +1 -1
  238. package/dist/server/analytics.js +6 -14
  239. package/dist/server/analytics.js.map +1 -1
  240. package/dist/server/app-name.d.ts +5 -2
  241. package/dist/server/app-name.d.ts.map +1 -1
  242. package/dist/server/app-name.js +14 -3
  243. package/dist/server/app-name.js.map +1 -1
  244. package/dist/server/app-url.d.ts.map +1 -1
  245. package/dist/server/app-url.js +10 -1
  246. package/dist/server/app-url.js.map +1 -1
  247. package/dist/server/auth.d.ts +2 -0
  248. package/dist/server/auth.d.ts.map +1 -1
  249. package/dist/server/auth.js +153 -2
  250. package/dist/server/auth.js.map +1 -1
  251. package/dist/server/better-auth-instance.d.ts +2 -0
  252. package/dist/server/better-auth-instance.d.ts.map +1 -1
  253. package/dist/server/better-auth-instance.js +4 -0
  254. package/dist/server/better-auth-instance.js.map +1 -1
  255. package/dist/server/builder-browser.d.ts +59 -1
  256. package/dist/server/builder-browser.d.ts.map +1 -1
  257. package/dist/server/builder-browser.js +127 -11
  258. package/dist/server/builder-browser.js.map +1 -1
  259. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  260. package/dist/server/core-routes-plugin.js +208 -6
  261. package/dist/server/core-routes-plugin.js.map +1 -1
  262. package/dist/server/credential-provider.d.ts +7 -0
  263. package/dist/server/credential-provider.d.ts.map +1 -1
  264. package/dist/server/credential-provider.js +10 -0
  265. package/dist/server/credential-provider.js.map +1 -1
  266. package/dist/server/onboarding-html.d.ts.map +1 -1
  267. package/dist/server/onboarding-html.js +29 -4
  268. package/dist/server/onboarding-html.js.map +1 -1
  269. package/dist/server/poll.d.ts.map +1 -1
  270. package/dist/server/poll.js +46 -5
  271. package/dist/server/poll.js.map +1 -1
  272. package/dist/server/ssr-handler.d.ts.map +1 -1
  273. package/dist/server/ssr-handler.js +2 -1
  274. package/dist/server/ssr-handler.js.map +1 -1
  275. package/dist/server/transcribe-voice.d.ts.map +1 -1
  276. package/dist/server/transcribe-voice.js +44 -5
  277. package/dist/server/transcribe-voice.js.map +1 -1
  278. package/dist/styles/agent-native.css +11 -2
  279. package/dist/templates/default/.agents/skills/progress/SKILL.md +14 -12
  280. package/dist/templates/default/app/root.tsx +7 -0
  281. package/dist/transcription/builder-transcription.d.ts +27 -0
  282. package/dist/transcription/builder-transcription.d.ts.map +1 -0
  283. package/dist/transcription/builder-transcription.js +41 -0
  284. package/dist/transcription/builder-transcription.js.map +1 -0
  285. package/dist/triggers/actions.d.ts +3 -0
  286. package/dist/triggers/actions.d.ts.map +1 -1
  287. package/dist/triggers/actions.js +189 -213
  288. package/dist/triggers/actions.js.map +1 -1
  289. package/docs/content/agent-mentions.md +1 -1
  290. package/docs/content/automations.md +22 -19
  291. package/docs/content/cloneable-saas.md +2 -2
  292. package/docs/content/deployment.md +21 -61
  293. package/docs/content/getting-started.md +1 -1
  294. package/docs/content/key-concepts.md +1 -1
  295. package/docs/content/{enterprise-workspace.md → multi-app-workspace.md} +3 -3
  296. package/docs/content/multi-tenancy.md +1 -1
  297. package/docs/content/progress.md +11 -11
  298. package/docs/content/template-dispatch.md +3 -3
  299. package/docs/content/workspace-management.md +1 -1
  300. package/package.json +9 -2
  301. package/src/templates/default/.agents/skills/progress/SKILL.md +14 -12
  302. package/src/templates/default/app/root.tsx +7 -0
@@ -14,7 +14,7 @@ import { createThread, getThread, listThreads, searchThreads, updateThreadData,
14
14
  import { resourceListAccessible, resourceList, resourceGet, resourceGetByPath, ensurePersonalDefaults, SHARED_OWNER, } from "../resources/store.js";
15
15
  import nodePath from "node:path";
16
16
  import { readBody } from "./h3-helpers.js";
17
- import { getBuilderBrowserConnectUrl, requestBuilderBrowserConnection, } from "./builder-browser.js";
17
+ import { getBuilderBrowserConnectUrl } from "./builder-browser.js";
18
18
  // Lazy fs — loaded via dynamic import() on first use.
19
19
  // This avoids require() which bundlers convert to createRequire(import.meta.url)
20
20
  // that crashes on CF Workers where import.meta.url is undefined.
@@ -74,6 +74,44 @@ function wrapCliScript(tool, cliDefault, opts) {
74
74
  },
75
75
  };
76
76
  }
77
+ /**
78
+ * Creates the `get-framework-context` tool. Returns detailed instructions
79
+ * for framework capabilities that are summarized in the compact prompt.
80
+ * The agent calls this on-demand when it needs specifics about embeds,
81
+ * agent teams, recurring jobs, etc.
82
+ */
83
+ function createFrameworkContextEntry() {
84
+ const topicList = Object.keys(FRAMEWORK_CONTEXT_SECTIONS).join(", ");
85
+ return {
86
+ "get-framework-context": {
87
+ tool: {
88
+ description: `Read detailed framework instructions for a specific capability. Available topics: ${topicList}. Call with topic="all" to get everything.`,
89
+ parameters: {
90
+ type: "object",
91
+ properties: {
92
+ topic: {
93
+ type: "string",
94
+ description: `Topic to read. One of: ${topicList}, or "all" for everything.`,
95
+ },
96
+ },
97
+ required: ["topic"],
98
+ },
99
+ },
100
+ run: async (args) => {
101
+ const topic = String(args.topic ?? "all").toLowerCase();
102
+ if (topic === "all") {
103
+ return Object.values(FRAMEWORK_CONTEXT_SECTIONS).join("\n\n");
104
+ }
105
+ const section = FRAMEWORK_CONTEXT_SECTIONS[topic];
106
+ if (!section) {
107
+ return `Unknown topic "${topic}". Available: ${topicList}`;
108
+ }
109
+ return section;
110
+ },
111
+ readOnly: true,
112
+ },
113
+ };
114
+ }
77
115
  /**
78
116
  * Creates the `refresh-screen` tool. Writes a bump to `application_state`
79
117
  * under a well-known key; the client's `useDbSync` watches for this and
@@ -370,91 +408,87 @@ async function createResourceScriptEntries() {
370
408
  import("../scripts/resources/save-memory.js"),
371
409
  import("../scripts/resources/delete-memory.js"),
372
410
  ]);
411
+ // Wrap each CLI runner so it captures stdout and converts args properly
412
+ const listEntry = wrapCliScript({
413
+ description: "",
414
+ parameters: { type: "object", properties: {} },
415
+ }, list.default, { readOnly: true });
416
+ const readEntry = wrapCliScript({
417
+ description: "",
418
+ parameters: { type: "object", properties: {} },
419
+ }, read.default, { readOnly: true });
420
+ const writeEntry = wrapCliScript({
421
+ description: "",
422
+ parameters: { type: "object", properties: {} },
423
+ }, write.default);
424
+ const deleteEntry = wrapCliScript({
425
+ description: "",
426
+ parameters: { type: "object", properties: {} },
427
+ }, del.default);
373
428
  return {
374
- "resource-list": wrapCliScript({
375
- description: "List resources (persistent files/notes). Returns file paths, sizes, and metadata.",
376
- parameters: {
377
- type: "object",
378
- properties: {
379
- prefix: {
380
- type: "string",
381
- description: "Filter by path prefix (e.g. 'notes/')",
382
- },
383
- scope: {
384
- type: "string",
385
- description: "Which resources to list: personal, shared, or all (default: all)",
386
- enum: ["personal", "shared", "all"],
387
- },
388
- format: {
389
- type: "string",
390
- description: 'Output format: "json" or "text" (default: text)',
391
- enum: ["json", "text"],
392
- },
393
- },
394
- },
395
- }, list.default),
396
- "resource-read": wrapCliScript({
397
- description: "Read a resource by path. Returns the file contents.",
398
- parameters: {
399
- type: "object",
400
- properties: {
401
- path: {
402
- type: "string",
403
- description: "Resource path (e.g. 'LEARNINGS.md', 'notes/ideas.md')",
404
- },
405
- scope: {
406
- type: "string",
407
- description: "personal or shared (default: personal, falls back to shared)",
408
- enum: ["personal", "shared"],
409
- },
410
- },
411
- required: ["path"],
412
- },
413
- }, read.default),
414
- "resource-write": wrapCliScript({
415
- description: "Write or update a resource. Creates the resource if it doesn't exist.",
416
- parameters: {
417
- type: "object",
418
- properties: {
419
- path: {
420
- type: "string",
421
- description: "Resource path (e.g. 'LEARNINGS.md', 'notes/ideas.md')",
422
- },
423
- content: {
424
- type: "string",
425
- description: "The content to write",
426
- },
427
- scope: {
428
- type: "string",
429
- description: "personal or shared (default: personal)",
430
- enum: ["personal", "shared"],
431
- },
432
- mime: {
433
- type: "string",
434
- description: "MIME type (default: inferred from extension)",
429
+ resources: {
430
+ tool: {
431
+ description: 'Manage persistent user files and notes. Actions: "list" (browse), "read" (get contents), "write" (create/update), "delete" (remove).',
432
+ parameters: {
433
+ type: "object",
434
+ properties: {
435
+ action: {
436
+ type: "string",
437
+ description: "The operation to perform",
438
+ enum: ["list", "read", "write", "delete"],
439
+ },
440
+ path: {
441
+ type: "string",
442
+ description: "Resource path (e.g. 'LEARNINGS.md', 'notes/ideas.md'). Required for read/write/delete.",
443
+ },
444
+ content: {
445
+ type: "string",
446
+ description: "Content to write. Required for write.",
447
+ },
448
+ scope: {
449
+ type: "string",
450
+ description: "personal, shared, or all (default varies by action)",
451
+ enum: ["personal", "shared", "all"],
452
+ },
453
+ prefix: {
454
+ type: "string",
455
+ description: "Filter by path prefix when listing (e.g. 'notes/')",
456
+ },
457
+ mime: {
458
+ type: "string",
459
+ description: "MIME type for write (default: inferred from extension)",
460
+ },
461
+ format: {
462
+ type: "string",
463
+ description: 'Output format for list: "json" or "text" (default: text)',
464
+ enum: ["json", "text"],
465
+ },
435
466
  },
467
+ required: ["action"],
436
468
  },
437
- required: ["path", "content"],
438
469
  },
439
- }, write.default),
440
- "resource-delete": wrapCliScript({
441
- description: "Delete a resource by path.",
442
- parameters: {
443
- type: "object",
444
- properties: {
445
- path: {
446
- type: "string",
447
- description: "Resource path to delete",
448
- },
449
- scope: {
450
- type: "string",
451
- description: "personal or shared (default: personal)",
452
- enum: ["personal", "shared"],
453
- },
454
- },
455
- required: ["path"],
470
+ run: async (args) => {
471
+ const { action: a, ...rest } = args;
472
+ if (a === "list")
473
+ return listEntry.run(rest);
474
+ if (a === "read") {
475
+ if (!rest.path)
476
+ return "Error: path is required for read";
477
+ return readEntry.run(rest);
478
+ }
479
+ if (a === "write") {
480
+ if (!rest.path || !rest.content)
481
+ return "Error: path and content are required for write";
482
+ return writeEntry.run(rest);
483
+ }
484
+ if (a === "delete") {
485
+ if (!rest.path)
486
+ return "Error: path is required for delete";
487
+ return deleteEntry.run(rest);
488
+ }
489
+ return `Error: unknown action "${a}". Use: list, read, write, delete`;
456
490
  },
457
- }, del.default),
491
+ },
458
492
  "save-memory": wrapCliScript({
459
493
  description: "Save a memory for future conversations. Creates or updates a memory file and its index entry. Use proactively when you learn preferences, corrections, project context, or references.",
460
494
  parameters: {
@@ -502,7 +536,7 @@ async function createResourceScriptEntries() {
502
536
  }
503
537
  }
504
538
  /**
505
- * Creates chat management ActionEntries (search-chats, open-chat).
539
+ * Creates a unified chat-history ActionEntry that dispatches to search or open.
506
540
  */
507
541
  async function createChatScriptEntries() {
508
542
  try {
@@ -510,41 +544,80 @@ async function createChatScriptEntries() {
510
544
  import("../scripts/chat/search-chats.js"),
511
545
  import("../scripts/chat/open-chat.js"),
512
546
  ]);
513
- return {
514
- "search-chats": wrapCliScript({
515
- description: "Search or list past agent chat threads. Use this to find previous conversations by keyword.",
516
- parameters: {
517
- type: "object",
518
- properties: {
519
- query: {
520
- type: "string",
521
- description: "Search term to find chats by title, preview, or content",
522
- },
523
- limit: {
524
- type: "string",
525
- description: "Max number of results (default: 20)",
526
- },
527
- format: {
528
- type: "string",
529
- description: "Output format",
530
- enum: ["json", "text"],
531
- },
547
+ const searchEntry = wrapCliScript({
548
+ description: "Search or list past agent chat threads.",
549
+ parameters: {
550
+ type: "object",
551
+ properties: {
552
+ query: {
553
+ type: "string",
554
+ description: "Search term to find chats by title, preview, or content",
555
+ },
556
+ limit: {
557
+ type: "string",
558
+ description: "Max number of results (default: 20)",
559
+ },
560
+ format: {
561
+ type: "string",
562
+ description: "Output format",
563
+ enum: ["json", "text"],
532
564
  },
533
565
  },
534
- }, searchMod.default),
535
- "open-chat": wrapCliScript({
536
- description: "Open a chat thread in the UI as a new tab and focus it. Use search-chats first to find the thread ID.",
537
- parameters: {
538
- type: "object",
539
- properties: {
540
- id: {
541
- type: "string",
542
- description: "The chat thread ID to open",
566
+ },
567
+ }, searchMod.default);
568
+ const openEntry = wrapCliScript({
569
+ description: "Open a chat thread in the UI.",
570
+ parameters: {
571
+ type: "object",
572
+ properties: {
573
+ id: {
574
+ type: "string",
575
+ description: "The chat thread ID to open",
576
+ },
577
+ },
578
+ required: ["id"],
579
+ },
580
+ }, openMod.default);
581
+ return {
582
+ "chat-history": {
583
+ tool: {
584
+ description: "Manage past agent chat threads. Use action 'search' to find previous conversations by keyword, or 'open' to open a thread in the UI.",
585
+ parameters: {
586
+ type: "object",
587
+ properties: {
588
+ action: {
589
+ type: "string",
590
+ description: "The operation to perform",
591
+ enum: ["search", "open"],
592
+ },
593
+ query: {
594
+ type: "string",
595
+ description: "(search) Search term to find chats by title, preview, or content",
596
+ },
597
+ limit: {
598
+ type: "string",
599
+ description: "(search) Max number of results (default: 20)",
600
+ },
601
+ format: {
602
+ type: "string",
603
+ description: "(search) Output format",
604
+ enum: ["json", "text"],
605
+ },
606
+ id: {
607
+ type: "string",
608
+ description: "(open) The chat thread ID to open",
609
+ },
543
610
  },
611
+ required: ["action"],
544
612
  },
545
- required: ["id"],
546
613
  },
547
- }, openMod.default),
614
+ run: async (args) => {
615
+ if (args?.action === "open") {
616
+ return openEntry.run(args);
617
+ }
618
+ return searchEntry.run(args);
619
+ },
620
+ },
548
621
  };
549
622
  }
550
623
  catch {
@@ -552,20 +625,14 @@ async function createChatScriptEntries() {
552
625
  }
553
626
  }
554
627
  /**
555
- * Creates agent engine management tools (list-agent-engines, set-agent-engine,
556
- * test-agent-engine). Let the agent inspect and configure the active LLM engine.
628
+ * Creates the consolidated manage-agent-engine tool (list / set / test).
629
+ * Let the agent inspect and configure the active LLM engine.
557
630
  */
558
631
  async function createAgentEngineScriptEntries() {
559
632
  try {
560
- const [listMod, setMod, testMod] = await Promise.all([
561
- import("../scripts/agent-engines/list-agent-engines.js"),
562
- import("../scripts/agent-engines/set-agent-engine.js"),
563
- import("../scripts/agent-engines/test-agent-engine.js"),
564
- ]);
633
+ const mod = await import("../scripts/agent-engines/manage-agent-engine.js");
565
634
  return {
566
- "list-agent-engines": { tool: listMod.tool, run: listMod.run },
567
- "set-agent-engine": { tool: setMod.tool, run: setMod.run },
568
- "test-agent-engine": { tool: testMod.tool, run: testMod.run },
635
+ "manage-agent-engine": { tool: mod.tool, run: mod.run },
569
636
  };
570
637
  }
571
638
  catch {
@@ -611,270 +678,178 @@ function createBuilderBrowserTool(deps) {
611
678
  return JSON.stringify({
612
679
  kind: "connect-builder-card",
613
680
  configured,
614
- builderEnabled: !!process.env.ENABLE_BUILDER,
615
681
  connectUrl: getBuilderBrowserConnectUrl(deps.getOrigin()),
616
682
  orgName: process.env.BUILDER_ORG_NAME || null,
617
683
  prompt,
618
684
  });
619
685
  },
620
686
  },
621
- "get-browser-connection": {
622
- tool: {
623
- description: "Provision a Builder-backed browser session and return browser websocket connection details. If Builder browser access is not configured yet, this returns setup guidance instead.",
624
- parameters: {
625
- type: "object",
626
- properties: {
627
- sessionId: {
628
- type: "string",
629
- description: "Stable browser session identifier. Reuse it to reconnect to the same browser session.",
630
- },
631
- projectId: {
632
- type: "string",
633
- description: "Optional Builder project or space identifier to scope the session.",
634
- },
635
- branchName: {
636
- type: "string",
637
- description: "Optional branch name for Builder preview sessions.",
638
- },
639
- proxyOrigin: {
640
- type: "string",
641
- description: "Optional source origin to proxy from when browsing a local app.",
642
- },
643
- proxyDefaultOrigin: {
644
- type: "string",
645
- description: "Optional default origin that the browser should use for proxied requests.",
646
- },
647
- proxyDestination: {
648
- type: "string",
649
- description: "Optional destination origin for proxying local development traffic.",
650
- },
651
- },
652
- required: ["sessionId"],
653
- },
654
- },
655
- run: async (args) => {
656
- if (!process.env.BUILDER_PRIVATE_KEY ||
657
- !process.env.BUILDER_PUBLIC_KEY) {
658
- return JSON.stringify({
659
- configured: false,
660
- message: "Builder browser access is not configured. Connect Builder from the workspace Resources panel before requesting a browser session.",
661
- connectUrl: getBuilderBrowserConnectUrl(deps.getOrigin()),
662
- });
663
- }
664
- const connection = await requestBuilderBrowserConnection({
665
- sessionId: args.sessionId,
666
- projectId: args.projectId,
667
- branchName: args.branchName,
668
- proxyOrigin: args.proxyOrigin,
669
- proxyDefaultOrigin: args.proxyDefaultOrigin,
670
- proxyDestination: args.proxyDestination,
671
- });
672
- return JSON.stringify({
673
- configured: true,
674
- sessionId: args.sessionId,
675
- ...connection,
676
- });
677
- },
678
- },
679
687
  };
680
688
  }
681
689
  /**
682
- * Creates agent team orchestration tools (spawn-task, task-status, read-task-result).
683
- * These let the main agent spawn sub-agents and coordinate work.
690
+ * Creates the unified `agent-teams` tool that consolidates all sub-agent
691
+ * orchestration behind a single tool with an `action` parameter.
684
692
  */
685
693
  function createTeamTools(deps) {
686
694
  return {
687
- "spawn-task": {
695
+ "agent-teams": {
688
696
  tool: {
689
- description: "Spawn a sub-agent to handle a task in the background. The sub-agent runs independently with its own conversation thread. Use this to delegate work so the main chat stays free for new requests. A live preview card will appear in the chat showing the sub-agent's progress.",
697
+ description: "Manage sub-agent tasks. Use action 'spawn' to start a new sub-agent, 'status' to check progress, 'read-result' to get a finished task's output, 'send' to message a running sub-agent, or 'list' to see all tasks.",
690
698
  parameters: {
691
699
  type: "object",
692
700
  properties: {
701
+ action: {
702
+ type: "string",
703
+ enum: ["spawn", "status", "read-result", "send", "list"],
704
+ description: "The operation to perform",
705
+ },
693
706
  task: {
694
707
  type: "string",
695
- description: "Clear description of what the sub-agent should accomplish",
708
+ description: "(spawn) Clear description of what the sub-agent should accomplish",
696
709
  },
697
710
  instructions: {
698
711
  type: "string",
699
- description: "Optional additional instructions or context for the sub-agent",
712
+ description: "(spawn) Optional additional instructions or context for the sub-agent",
700
713
  },
701
714
  name: {
702
715
  type: "string",
703
- description: "Short name for the sub-agent tab (e.g. 'Research', 'Draft email'). If omitted, derived from the task.",
716
+ description: "(spawn) Short name for the sub-agent tab (e.g. 'Research', 'Draft email'). If omitted, derived from the task.",
704
717
  },
705
718
  agent: {
706
719
  type: "string",
707
- description: "Optional custom agent profile from agents/*.md to use for this task.",
720
+ description: "(spawn) Optional custom agent profile from agents/*.md to use for this task.",
708
721
  },
709
- },
710
- required: ["task"],
711
- },
712
- },
713
- run: async (args) => {
714
- // Capture the send function NOW (at spawn time) so that
715
- // concurrent runs don't clobber each other's send reference.
716
- const capturedSend = deps.getSend();
717
- const { spawnTask } = await import("./agent-teams.js");
718
- // Filter out team orchestration tools so sub-agents can't spawn sub-agents
719
- const teamToolNames = new Set([
720
- "spawn-task",
721
- "task-status",
722
- "read-task-result",
723
- "send-to-task",
724
- "list-tasks",
725
- ]);
726
- const subAgentActions = Object.fromEntries(Object.entries(deps.getActions()).filter(([name]) => !teamToolNames.has(name)));
727
- let instructions = args.instructions;
728
- let selectedModel = deps.getModel();
729
- let selectedName = args.name || "";
730
- if (args.agent) {
731
- const { findAccessibleCustomAgent } = await import("../resources/agents.js");
732
- const profile = await findAccessibleCustomAgent(deps.getOwner(), args.agent);
733
- if (!profile) {
734
- throw new Error(`Custom agent not found: ${args.agent}`);
735
- }
736
- const profileInstructions = `## Custom Agent Profile: ${profile.name}\n\n` +
737
- (profile.description ? `${profile.description}\n\n` : "") +
738
- profile.instructions;
739
- instructions = instructions
740
- ? `${profileInstructions}\n\n## Extra Task Context\n\n${instructions}`
741
- : profileInstructions;
742
- selectedModel = profile.model ?? selectedModel;
743
- selectedName = selectedName || profile.name;
744
- }
745
- const task = await spawnTask({
746
- description: args.task,
747
- instructions,
748
- ownerEmail: deps.getOwner(),
749
- systemPrompt: deps.getSystemPrompt(),
750
- actions: subAgentActions,
751
- engine: deps.getEngine(),
752
- model: selectedModel,
753
- parentThreadId: deps.getParentThreadId(),
754
- parentSend: (event) => {
755
- if (capturedSend)
756
- capturedSend(event);
757
- },
758
- });
759
- return JSON.stringify({
760
- taskId: task.taskId,
761
- threadId: task.threadId,
762
- status: task.status,
763
- description: task.description,
764
- name: selectedName,
765
- });
766
- },
767
- },
768
- "task-status": {
769
- tool: {
770
- description: "Check the status of a sub-agent task. Returns current status, preview of output, and current step.",
771
- parameters: {
772
- type: "object",
773
- properties: {
774
722
  taskId: {
775
723
  type: "string",
776
- description: "The task ID returned by spawn-task",
724
+ description: "(status, read-result, send) The task ID returned by a previous spawn",
777
725
  },
778
- },
779
- required: ["taskId"],
780
- },
781
- },
782
- run: async (args) => {
783
- const { getTask } = await import("./agent-teams.js");
784
- const task = await getTask(args.taskId);
785
- if (!task)
786
- return JSON.stringify({ error: "Task not found" });
787
- return JSON.stringify({
788
- taskId: task.taskId,
789
- threadId: task.threadId,
790
- status: task.status,
791
- description: task.description,
792
- preview: task.preview,
793
- currentStep: task.currentStep,
794
- summary: task.summary,
795
- });
796
- },
797
- },
798
- "read-task-result": {
799
- tool: {
800
- description: "Read the result of a completed sub-agent task. Returns the full output summary.",
801
- parameters: {
802
- type: "object",
803
- properties: {
804
- taskId: {
726
+ message: {
805
727
  type: "string",
806
- description: "The task ID returned by spawn-task",
728
+ description: "(send) Message to send to the sub-agent",
807
729
  },
808
730
  },
809
- required: ["taskId"],
731
+ required: ["action"],
810
732
  },
811
733
  },
812
734
  run: async (args) => {
813
- const { getTask } = await import("./agent-teams.js");
814
- const task = await getTask(args.taskId);
815
- if (!task)
816
- return JSON.stringify({ error: "Task not found" });
817
- if (task.status === "running") {
735
+ const action = args.action;
736
+ // ── spawn ──────────────────────────────────────────────
737
+ if (action === "spawn") {
738
+ if (!args.task)
739
+ throw new Error("'task' is required for spawn");
740
+ // Capture the send function NOW (at spawn time) so that
741
+ // concurrent runs don't clobber each other's send reference.
742
+ const capturedSend = deps.getSend();
743
+ const { spawnTask } = await import("./agent-teams.js");
744
+ // Filter out the team tool so sub-agents can't spawn sub-agents
745
+ const subAgentActions = Object.fromEntries(Object.entries(deps.getActions()).filter(([name]) => name !== "agent-teams"));
746
+ let instructions = args.instructions;
747
+ let selectedModel = deps.getModel();
748
+ let selectedName = args.name || "";
749
+ if (args.agent) {
750
+ const { findAccessibleCustomAgent } = await import("../resources/agents.js");
751
+ const profile = await findAccessibleCustomAgent(deps.getOwner(), args.agent);
752
+ if (!profile) {
753
+ throw new Error(`Custom agent not found: ${args.agent}`);
754
+ }
755
+ const profileInstructions = `## Custom Agent Profile: ${profile.name}\n\n` +
756
+ (profile.description ? `${profile.description}\n\n` : "") +
757
+ profile.instructions;
758
+ instructions = instructions
759
+ ? `${profileInstructions}\n\n## Extra Task Context\n\n${instructions}`
760
+ : profileInstructions;
761
+ selectedModel = profile.model ?? selectedModel;
762
+ selectedName = selectedName || profile.name;
763
+ }
764
+ const task = await spawnTask({
765
+ description: args.task,
766
+ instructions,
767
+ ownerEmail: deps.getOwner(),
768
+ systemPrompt: deps.getSystemPrompt(),
769
+ actions: subAgentActions,
770
+ engine: deps.getEngine(),
771
+ model: selectedModel,
772
+ parentThreadId: deps.getParentThreadId(),
773
+ parentSend: (event) => {
774
+ if (capturedSend)
775
+ capturedSend(event);
776
+ },
777
+ });
818
778
  return JSON.stringify({
819
- status: "running",
779
+ taskId: task.taskId,
780
+ threadId: task.threadId,
781
+ status: task.status,
782
+ description: task.description,
783
+ name: selectedName,
784
+ });
785
+ }
786
+ // ── status ─────────────────────────────────────────────
787
+ if (action === "status") {
788
+ if (!args.taskId)
789
+ throw new Error("'taskId' is required for status");
790
+ const { getTask } = await import("./agent-teams.js");
791
+ const task = await getTask(args.taskId);
792
+ if (!task)
793
+ return JSON.stringify({ error: "Task not found" });
794
+ return JSON.stringify({
795
+ taskId: task.taskId,
796
+ threadId: task.threadId,
797
+ status: task.status,
798
+ description: task.description,
820
799
  preview: task.preview,
821
- message: "Task is still running. Check back later.",
800
+ currentStep: task.currentStep,
801
+ summary: task.summary,
822
802
  });
823
803
  }
824
- return JSON.stringify({
825
- taskId: task.taskId,
826
- status: task.status,
827
- summary: task.summary,
828
- preview: task.preview,
829
- });
830
- },
831
- },
832
- "send-to-task": {
833
- tool: {
834
- description: "Send a message or update to a running sub-agent. Use this to redirect, add context, or give feedback to a sub-agent while it's working.",
835
- parameters: {
836
- type: "object",
837
- properties: {
838
- taskId: {
839
- type: "string",
840
- description: "The task ID returned by spawn-task",
841
- },
842
- message: {
843
- type: "string",
844
- description: "Message to send to the sub-agent",
845
- },
846
- },
847
- required: ["taskId", "message"],
848
- },
849
- },
850
- run: async (args) => {
851
- const { sendToTask } = await import("./agent-teams.js");
852
- const result = await sendToTask(args.taskId, args.message);
853
- return JSON.stringify(result);
854
- },
855
- },
856
- "list-tasks": {
857
- tool: {
858
- description: "List all sub-agent tasks and their current status. Use this to see what's running, completed, or failed.",
859
- parameters: {
860
- type: "object",
861
- properties: {},
862
- },
863
- },
864
- run: async () => {
865
- const { listTasks } = await import("./agent-teams.js");
866
- const tasks = await listTasks();
867
- if (tasks.length === 0) {
868
- return "No sub-agent tasks.";
869
- }
870
- return JSON.stringify(tasks.map((t) => ({
871
- taskId: t.taskId,
872
- threadId: t.threadId,
873
- description: t.description,
874
- status: t.status,
875
- currentStep: t.currentStep,
876
- hasResult: t.summary.length > 0,
877
- })), null, 2);
804
+ // ── read-result ────────────────────────────────────────
805
+ if (action === "read-result") {
806
+ if (!args.taskId)
807
+ throw new Error("'taskId' is required for read-result");
808
+ const { getTask } = await import("./agent-teams.js");
809
+ const task = await getTask(args.taskId);
810
+ if (!task)
811
+ return JSON.stringify({ error: "Task not found" });
812
+ if (task.status === "running") {
813
+ return JSON.stringify({
814
+ status: "running",
815
+ preview: task.preview,
816
+ message: "Task is still running. Check back later.",
817
+ });
818
+ }
819
+ return JSON.stringify({
820
+ taskId: task.taskId,
821
+ status: task.status,
822
+ summary: task.summary,
823
+ preview: task.preview,
824
+ });
825
+ }
826
+ // ── send ───────────────────────────────────────────────
827
+ if (action === "send") {
828
+ if (!args.taskId)
829
+ throw new Error("'taskId' is required for send");
830
+ if (!args.message)
831
+ throw new Error("'message' is required for send");
832
+ const { sendToTask } = await import("./agent-teams.js");
833
+ const result = await sendToTask(args.taskId, args.message);
834
+ return JSON.stringify(result);
835
+ }
836
+ // ── list ───────────────────────────────────────────────
837
+ if (action === "list") {
838
+ const { listTasks } = await import("./agent-teams.js");
839
+ const tasks = await listTasks();
840
+ if (tasks.length === 0) {
841
+ return "No sub-agent tasks.";
842
+ }
843
+ return JSON.stringify(tasks.map((t) => ({
844
+ taskId: t.taskId,
845
+ threadId: t.threadId,
846
+ description: t.description,
847
+ status: t.status,
848
+ currentStep: t.currentStep,
849
+ hasResult: t.summary.length > 0,
850
+ })), null, 2);
851
+ }
852
+ throw new Error(`Unknown action '${action}'. Use one of: spawn, status, read-result, send, list`);
878
853
  },
879
854
  },
880
855
  };
@@ -885,7 +860,157 @@ function createTeamTools(deps) {
885
860
  * Template AGENTS.md resources only need template-specific content.
886
861
  */
887
862
  /**
888
- * Framework instructions shared across both modes. The mode-specific
863
+ * Compact framework instructions for lazy-context mode. Keeps the critical
864
+ * behavioral rules but defers verbose details (chat history, agent teams,
865
+ * recurring jobs, builder.io, browser, A2A, structured memory) behind the
866
+ * `get-framework-context` tool.
867
+ */
868
+ const FRAMEWORK_CORE_COMPACT = `
869
+ ### Core Rules
870
+
871
+ 1. **Data lives in SQL** — All app state is in a SQL database. Use the available database tools. Call \`db-schema\` to see the full schema when needed.
872
+ 2. **Context awareness** — The user's current screen state is in \`<current-screen>\`, current URL in \`<current-url>\`. Use both to understand what the user is looking at. To change URL state, use \`set-search-params\` or \`set-url-path\`.
873
+ 3. **Navigate the UI** — Use the \`navigate\` tool to switch views, open items, or focus elements.
874
+ 4. **Application state** — Ephemeral UI state lives in \`application_state\`. Use \`readAppState\`/\`writeAppState\`.
875
+ 5. **Screen refresh is automatic** — The framework auto-refreshes after mutating tool calls. Only call \`refresh-screen\` when you mutated data via a path the framework can't detect.
876
+ 6. **Memory** — Use \`save-memory\` proactively when you learn preferences, corrections, or project context.
877
+ 7. **Security** — Always use parameterized queries. Never \`dangerouslySetInnerHTML\`, \`innerHTML\`, or \`eval()\`.
878
+
879
+ ### Resources
880
+
881
+ Use resource-list, resource-read, resource-write, resource-delete for persistent notes and context files.
882
+ Resources are NOT an agent scratchpad — never create executable scripts, task plans, or work-in-progress files.
883
+
884
+ ### Navigation Rule
885
+
886
+ When the user says "show me", "go to", "open", etc., ALWAYS use \`navigate\` first.
887
+
888
+ ### Extended Capabilities
889
+
890
+ You also have tools for: inline embeds, chat history search, agent teams/sub-agents, recurring jobs, A2A cross-app calls, structured memory, and browser access. Call \`get-framework-context\` to read detailed instructions for any of these when needed.
891
+ `;
892
+ /**
893
+ * Verbose framework sections returned by the `get-framework-context` tool.
894
+ * Keyed by topic so the agent can request specific sections.
895
+ */
896
+ const FRAMEWORK_CONTEXT_SECTIONS = {
897
+ embeds: `### Inline Embeds
898
+
899
+ You can embed an interactive view inline in your chat reply by writing an \`embed\` fenced code block. The chat renderer swaps the fence for a sandboxed iframe pointing at a route inside this app.
900
+
901
+ Syntax:
902
+
903
+ \`\`\`\`
904
+ \`\`\`embed
905
+ src: /some/path?param=value
906
+ aspect: 16/9
907
+ title: Optional label
908
+ \`\`\`
909
+ \`\`\`\`
910
+
911
+ Keys:
912
+ - \`src\` (required) — **must be a same-origin path starting with \`/\`**. Cross-origin URLs are blocked. No \`javascript:\` or \`data:\` URLs.
913
+ - \`aspect\` (optional) — one of \`16/9\` (default), \`4/3\`, \`3/2\`, \`2/1\`, \`21/9\`, \`1/1\`.
914
+ - \`title\` (optional) — accessible label / hover tooltip.
915
+ - \`height\` (optional) — fixed pixel height when aspect ratio isn't a good fit.
916
+
917
+ Use for charts, visualizations, previews. Don't use for simple text/tables or external sites.`,
918
+ "chat-history": `### Chat History
919
+
920
+ You can search and restore previous chat conversations using \`chat-history\`:
921
+ - \`chat-history\` (action: "search") — Search or list past chat threads by keyword
922
+ - \`chat-history\` (action: "open") — Open a chat thread in the UI as a new tab and focus it
923
+
924
+ When the user asks to find a previous conversation, use \`chat-history\` with action "search" first to find matching threads, then action "open" to restore the one they want.`,
925
+ "agent-teams": `### Agent Teams — Orchestration
926
+
927
+ You are an orchestrator. For complex or multi-step tasks, delegate to sub-agents using the \`agent-teams\` tool:
928
+ - \`agent-teams\` (action: "spawn") — Spawn a sub-agent for a task. It runs in its own thread while you stay available.
929
+ - \`agent-teams\` (action: "status") — Check the progress of a running sub-agent.
930
+ - \`agent-teams\` (action: "read-result") — Read the result when a sub-agent finishes.
931
+ - \`agent-teams\` (action: "send") — Send a message to a running sub-agent.
932
+ - \`agent-teams\` (action: "list") — List all sub-agent tasks.
933
+
934
+ **When to delegate vs do directly:**
935
+ - **Delegate** when the task involves multiple tool calls, research, content generation, or anything that takes more than a few seconds.
936
+ - **Do directly** for quick single-step tasks like navigation, reading state, or answering simple questions.
937
+ - **Spawn multiple sub-agents** when the user asks for multiple independent things — they'll run in parallel.
938
+
939
+ Sub-agents have access to all template tools but **cannot spawn sub-agents themselves**.`,
940
+ "recurring-jobs": `### Recurring Jobs
941
+
942
+ You can create recurring jobs that run on a cron schedule. Jobs are resource files under \`jobs/\`.
943
+
944
+ - \`manage-jobs\` (action: "create") — Create a new recurring job with a cron schedule and instructions
945
+ - \`manage-jobs\` (action: "list") — List all recurring jobs and their status
946
+ - \`manage-jobs\` (action: "update") — Update a job's schedule, instructions, or toggle enabled/disabled
947
+ - Delete a job with \`resource-delete --path jobs/<name>.md\`
948
+
949
+ Convert natural language to 5-field cron format:
950
+ - "every morning" / "daily at 9am" → \`0 9 * * *\`
951
+ - "every weekday at 9am" → \`0 9 * * 1-5\`
952
+ - "every hour" → \`0 * * * *\`
953
+ - "every monday at 9am" → \`0 9 * * 1\``,
954
+ builder: `### Connecting Builder.io
955
+
956
+ When the user asks to connect Builder.io or you hit a "Builder not configured" error, call the \`connect-builder\` tool. It renders a one-click Connect card inline — do NOT write out multi-step setup instructions yourself.`,
957
+ browser: `### Browser Access
958
+
959
+ Use \`connect-builder\` when you need browser access backed by Builder. It renders a Connect card that provisions a browser session.
960
+
961
+ - If Builder is not configured, the card will guide the user through setup.`,
962
+ "call-agent": `### call-agent — External Apps Only
963
+
964
+ The \`call-agent\` tool sends a message to a DIFFERENT, separately-deployed app's agent (A2A protocol). It is **not** for calling actions within the current app.
965
+
966
+ **NEVER use \`call-agent\` to:**
967
+ - Call your own app by name
968
+ - Perform tasks you can accomplish with your own registered tools
969
+
970
+ **ONLY use \`call-agent\` when:**
971
+ - The user explicitly asks you to communicate with a different app
972
+ - You need data that only another deployed app can provide`,
973
+ memory: `### Structured Memory
974
+
975
+ Your memory index (\`memory/MEMORY.md\`) is loaded at the start of every conversation.
976
+
977
+ **Tools:**
978
+ - \`save-memory\` — Create or update a memory (name, type, description, content)
979
+ - \`delete-memory\` — Remove a memory and its index entry
980
+ - \`resource-read --path memory/<name>.md\` — Read the full content of a specific memory
981
+
982
+ **Memory types:** user, feedback, project, reference
983
+
984
+ **When to save (proactively):**
985
+ - User corrects your approach → \`feedback\`
986
+ - User shares preferences → \`user\`
987
+ - Non-obvious pattern or gotcha → \`feedback\`
988
+ - Personal context (contacts, team) → \`user\`
989
+ - Project context to track → \`project\`
990
+
991
+ **Rules:**
992
+ - Don't save things obvious from code or standard framework behavior
993
+ - When updating, read first and merge — don't overwrite
994
+ - Keep descriptions concise
995
+ - One memory per logical topic`,
996
+ "sql-tools": `### SQL Tools
997
+
998
+ - \`db-schema\` — refresh the full schema with indexes and foreign keys
999
+ - \`db-query\` — run a SELECT (read-only; results already filtered to the current user/org)
1000
+ - \`db-exec\` — run INSERT / UPDATE / DELETE (writes already scoped; owner_email and org_id are auto-injected on INSERT)
1001
+ - \`db-patch\` — surgical search-and-replace on a large text column. Use for edits to large fields instead of re-sending multi-kilobyte strings.
1002
+
1003
+ ### When to pick which SQL tool
1004
+ - Set a short column outright, update multiple columns, or do computed updates → \`db-exec UPDATE\`
1005
+ - Change a small slice of a large text/JSON column → \`db-patch\`
1006
+ - A template-specific action exists for the table → use that action (it encodes business rules and pushes live Yjs updates)
1007
+ - Read data → \`db-query\`. Never re-add \`WHERE owner_email = ...\` — scoping already applies it.
1008
+
1009
+ ### External data sources vs the app database
1010
+ The \`db-*\` tools ONLY query the app's own SQL database. They do NOT reach external data warehouses. If the user asks about tables NOT in the schema, use the appropriate template action instead.`,
1011
+ };
1012
+ /**
1013
+ * Full framework instructions shared across both modes. The mode-specific
889
1014
  * preamble is prepended by the prompt composition below.
890
1015
  */
891
1016
  const FRAMEWORK_CORE = `
@@ -902,12 +1027,12 @@ const FRAMEWORK_CORE = `
902
1027
  ### Resources
903
1028
 
904
1029
  You have access to a Resources system for persistent notes and context files.
905
- Use resource-list, resource-read, resource-write, and resource-delete to manage resources.
1030
+ Use resource-list, resource-read, resource-write, resource-delete to manage resources.
906
1031
  Resources can be personal (per-user) or shared (team-wide). By default, resources are personal.
907
1032
 
908
1033
  When the user gives instructions that should apply to all users/sessions, update the shared "AGENTS.md" resource.
909
1034
 
910
- **Resources are NOT an agent scratchpad.** Never use \`resource-write\` to store executable scripts, task plans, retry notes, or work-in-progress files you're writing to yourself. Specifically, do NOT create resources under \`scripts/\` or \`tasks/\` unless the user explicitly asked for a file at that path, or a tool (like \`create-job\` or \`spawn-task\`) writes there as part of its contract. If you can't complete a task with the tools you have, say so — don't improvise by leaving behind \`FINAL-*.md\`, \`EXECUTE-NOW-*.js\`, or similar artifacts. Resources are visible to the user in the workspace sidebar; every file you write is something they'll see and have to clean up.
1035
+ **Resources are NOT an agent scratchpad.** Never use \`resource-write\` to store executable scripts, task plans, retry notes, or work-in-progress files you're writing to yourself. Specifically, do NOT create resources under \`scripts/\` or \`tasks/\` unless the user explicitly asked for a file at that path, or a tool (like \`manage-jobs\` or \`agent-teams\`) writes there as part of its contract. If you can't complete a task with the tools you have, say so — don't improvise by leaving behind \`FINAL-*.md\`, \`EXECUTE-NOW-*.js\`, or similar artifacts. Resources are visible to the user in the workspace sidebar; every file you write is something they'll see and have to clean up.
911
1036
 
912
1037
  ### Navigation Rule
913
1038
 
@@ -946,18 +1071,20 @@ Which routes are renderable as embeds is template-specific — the app's \`AGENT
946
1071
 
947
1072
  ### Chat History
948
1073
 
949
- You can search and restore previous chat conversations:
950
- - \`search-chats\` — Search or list past chat threads by keyword
951
- - \`open-chat\` — Open a chat thread in the UI as a new tab and focus it
1074
+ You can search and restore previous chat conversations using \`chat-history\`:
1075
+ - \`chat-history\` (action: "search") — Search or list past chat threads by keyword
1076
+ - \`chat-history\` (action: "open") — Open a chat thread in the UI as a new tab and focus it
952
1077
 
953
- When the user asks to find a previous conversation, use \`search-chats\` first to find matching threads, then \`open-chat\` to restore the one they want.
1078
+ When the user asks to find a previous conversation, use \`chat-history\` with action "search" first to find matching threads, then action "open" to restore the one they want.
954
1079
 
955
1080
  ### Agent Teams — Orchestration
956
1081
 
957
- You are an orchestrator. For complex or multi-step tasks, delegate to sub-agents:
958
- - \`spawn-task\` — Spawn a sub-agent for a task. It runs in its own thread while you stay available. A live preview card appears in the chat. You can optionally choose a custom agent profile from \`agents/*.md\`.
959
- - \`task-status\` — Check the progress of a running sub-agent.
960
- - \`read-task-result\` — Read the result when a sub-agent finishes.
1082
+ You are an orchestrator. For complex or multi-step tasks, delegate to sub-agents using the \`agent-teams\` tool:
1083
+ - \`agent-teams\` (action: "spawn") — Spawn a sub-agent for a task. It runs in its own thread while you stay available. A live preview card appears in the chat. You can optionally choose a custom agent profile from \`agents/*.md\`.
1084
+ - \`agent-teams\` (action: "status") — Check the progress of a running sub-agent.
1085
+ - \`agent-teams\` (action: "read-result") — Read the result when a sub-agent finishes.
1086
+ - \`agent-teams\` (action: "send") — Send a message to a running sub-agent.
1087
+ - \`agent-teams\` (action: "list") — List all sub-agent tasks.
961
1088
 
962
1089
  **When to delegate vs do directly:**
963
1090
  - **Delegate** when the task involves multiple tool calls, research, content generation, or anything that takes more than a few seconds. Examples: "create a deck about X", "analyze the data and write a report", "look up Y and draft an email about it".
@@ -968,18 +1095,18 @@ You are an orchestrator. For complex or multi-step tasks, delegate to sub-agents
968
1095
  1. When the user asks for something complex, spawn a sub-agent with a clear task description.
969
1096
  2. Tell the user what you've started ("I'm having a sub-agent research that for you").
970
1097
  3. You can keep chatting — sub-agents run independently.
971
- 4. Use \`read-task-result\` to check results when needed, or the user can see live progress in the card.
1098
+ 4. Use \`agent-teams\` (action: "read-result") to check results when needed, or the user can see live progress in the card.
972
1099
  5. If the user's request has multiple steps, you can spawn one sub-agent per step, or chain them.
973
1100
 
974
- Sub-agents have access to all template tools but **cannot spawn sub-agents themselves** — only you (the orchestrator) can do that. Give the sub-agent a specific, actionable task description — it will figure out which tools to use. If a matching custom agent profile exists, pass it via the \`agent\` parameter on \`spawn-task\`.
1101
+ Sub-agents have access to all template tools but **cannot spawn sub-agents themselves** — only you (the orchestrator) can do that. Give the sub-agent a specific, actionable task description — it will figure out which tools to use. If a matching custom agent profile exists, pass it via the \`agent\` parameter on \`agent-teams\` (action: "spawn").
975
1102
 
976
1103
  ### Recurring Jobs
977
1104
 
978
1105
  You can create recurring jobs that run on a cron schedule. Jobs are resource files under \`jobs/\`. Each job has a cron schedule and instructions that the agent executes automatically.
979
1106
 
980
- - \`create-job\` — Create a new recurring job with a cron schedule and instructions
981
- - \`list-jobs\` — List all recurring jobs and their status (schedule, last run, next run, errors)
982
- - \`update-job\` — Update a job's schedule, instructions, or toggle enabled/disabled
1107
+ - \`manage-jobs\` (action: "create") — Create a new recurring job with a cron schedule and instructions
1108
+ - \`manage-jobs\` (action: "list") — List all recurring jobs and their status (schedule, last run, next run, errors)
1109
+ - \`manage-jobs\` (action: "update") — Update a job's schedule, instructions, or toggle enabled/disabled
983
1110
  - Delete a job with \`resource-delete --path jobs/<name>.md\`
984
1111
 
985
1112
  When the user asks for something recurring ("every morning", "daily at 9am", "weekly on Mondays"), create a job. Convert natural language to 5-field cron format:
@@ -998,11 +1125,9 @@ When the user asks to connect Builder.io, needs Builder for LLM access / browser
998
1125
 
999
1126
  ### Browser Access
1000
1127
 
1001
- Use \`get-browser-connection\` when you need a real browser session backed by Builder. It returns websocket connection details for a provisioned browser session.
1128
+ Use \`connect-builder\` when you need browser access backed by Builder. It renders a Connect card that provisions a browser session.
1002
1129
 
1003
- - If the tool says Builder is not configured, call \`connect-builder\` to show the user a Connect card.
1004
- - Reuse a stable \`sessionId\` when you want to reconnect to the same browser session.
1005
- - Include proxy parameters when you need the browser to reach a local dev server through Builder's browser connection flow.
1130
+ - If Builder is not configured, the card will guide the user through setup.
1006
1131
 
1007
1132
  ### call-agent — External Apps Only
1008
1133
 
@@ -1068,7 +1193,7 @@ When the user asks you to change the UI, modify code, add a feature, fix a bug i
1068
1193
  - Do NOT read source files, list directories, or explore the codebase. You have no filesystem tools and don't need to look at code to recommend Builder.
1069
1194
  - Do NOT write an implementation plan. Do NOT write code in your response. Do NOT describe which files to create or modify. Builder will figure that out in its sandbox.
1070
1195
  - Do NOT save plans, specs, or code to \`resource-write\`. Resources are for app data, not implementation plans the user didn't ask for.
1071
- - Do NOT spawn sub-agents (\`spawn-task\`) to design, plan, or research the feature. The answer is always: call \`connect-builder\`, say one sentence, stop. Sub-agents inherit these same rules and have no code-editing tools either.
1196
+ - Do NOT spawn sub-agents (\`agent-teams\`) to design, plan, or research the feature. The answer is always: call \`connect-builder\`, say one sentence, stop. Sub-agents inherit these same rules and have no code-editing tools either.
1072
1197
  - Do NOT say "I don't have a request-code-change tool" or list what tools you lack. Just call \`connect-builder\`.
1073
1198
  - Do NOT wait for the user to ask "how" — call \`connect-builder\` the moment a code change is requested.
1074
1199
 
@@ -1098,6 +1223,34 @@ When editing code, follow the agent-native architecture:
1098
1223
  - No Node.js-specific APIs in server routes (must work on Cloudflare Workers, etc.)
1099
1224
  - Use shadcn/ui components and Tabler Icons for all UI work
1100
1225
  ${FRAMEWORK_CORE}`;
1226
+ const PROD_FRAMEWORK_PROMPT_COMPACT = `## Agent-Native Framework — Production Mode
1227
+
1228
+ You are an AI agent in an agent-native application, running in **production mode**.
1229
+
1230
+ The agent and the UI are equal partners — everything the UI can do, you can do via your tools, and vice versa. They share the same SQL database and stay in sync automatically.
1231
+
1232
+ **In production mode, you operate through registered actions exposed as tools.** These are your capabilities — use them to read data, take actions, and help the user. You cannot edit source code or access the filesystem directly. Your tools are the app's API.
1233
+
1234
+ ### Code Changes — Call \`connect-builder\`
1235
+
1236
+ When the user asks to change the UI, modify code, add a feature, or fix a bug in the app itself — call \`connect-builder\` immediately, passing the user's request as the \`prompt\`. Do NOT write code, list files, make plans, or spawn sub-agents for code changes. Builder handles it in the cloud. Mention \`npx agent-native create <app-name>\` as an offline fallback.
1237
+ ${FRAMEWORK_CORE_COMPACT}`;
1238
+ const DEV_FRAMEWORK_PROMPT_COMPACT = `## Agent-Native Framework — Development Mode
1239
+
1240
+ You are an AI agent in an agent-native application, running in **development mode**.
1241
+
1242
+ The agent and the UI are equal partners — everything the UI can do, you can do via tools/scripts, and vice versa. They share the same SQL database and stay in sync automatically.
1243
+
1244
+ **In development mode, you have UNRESTRICTED access.** You can run any shell command, read/write files, query the database, call external APIs, edit source code, and install packages.
1245
+
1246
+ **Template-specific actions are invoked via shell, NOT as direct tools.** Run them with: \`shell({ command: 'pnpm action <name> --arg value' })\`. See the "Available Actions" section below for CLI syntax.
1247
+
1248
+ When editing code, follow the agent-native architecture:
1249
+ - Every feature needs all four areas: UI + scripts + skills/instructions + application-state sync
1250
+ - All SQL must be dialect-agnostic (works on SQLite and Postgres)
1251
+ - No Node.js-specific APIs in server routes (must work on Cloudflare Workers, etc.)
1252
+ - Use shadcn/ui components and Tabler Icons for all UI work
1253
+ ${FRAMEWORK_CORE_COMPACT}`;
1101
1254
  const DEFAULT_SYSTEM_PROMPT = PROD_FRAMEWORK_PROMPT;
1102
1255
  /**
1103
1256
  * Pre-load the agent's context: AGENTS.md (template instructions), the skills
@@ -1117,7 +1270,7 @@ const DEFAULT_SYSTEM_PROMPT = PROD_FRAMEWORK_PROMPT;
1117
1270
  * AGENTS.md and restarting the server is all it takes; Vite HMR invalidates
1118
1271
  * the bundle in dev so changes land instantly.
1119
1272
  */
1120
- async function loadResourcesForPrompt(owner) {
1273
+ async function loadResourcesForPrompt(owner, compact = false) {
1121
1274
  await ensurePersonalDefaults(owner);
1122
1275
  const sections = [];
1123
1276
  // 1. Workspace AGENTS.md + skills merged into the template bundle.
@@ -1128,33 +1281,51 @@ async function loadResourcesForPrompt(owner) {
1128
1281
  if (bundle.workspaceAgentsMd && bundle.workspaceAgentsMd.trim()) {
1129
1282
  sections.push(`<resource name="AGENTS.md" scope="workspace">\n${bundle.workspaceAgentsMd.trim()}\n</resource>`);
1130
1283
  }
1131
- // 2. Template AGENTS.md.
1284
+ // 2. Template AGENTS.md — always included (critical template instructions).
1132
1285
  if (bundle.agentsMd.trim()) {
1133
1286
  sections.push(`<resource name="AGENTS.md" scope="template">\n${bundle.agentsMd.trim()}\n</resource>`);
1134
1287
  }
1135
- const skillsBlock = generateSkillsPromptBlock(bundle);
1136
- if (skillsBlock)
1137
- sections.push(skillsBlock);
1138
- }
1139
- catch { }
1140
- // LEARNINGS.md from SQL (template-level instructions are in AGENTS.md above).
1141
- // 2. Shared SQL scope
1142
- try {
1143
- const shared = await resourceGetByPath(SHARED_OWNER, "LEARNINGS.md");
1144
- if (shared?.content?.trim()) {
1145
- sections.push(`<resource name="LEARNINGS.md" scope="shared">\n${shared.content.trim()}\n</resource>`);
1288
+ // In compact mode, skip the full skills block — the agent can use
1289
+ // `docs-search` to find skills when it needs them.
1290
+ if (!compact) {
1291
+ const skillsBlock = generateSkillsPromptBlock(bundle);
1292
+ if (skillsBlock)
1293
+ sections.push(skillsBlock);
1294
+ }
1295
+ else if (Object.keys(bundle.skills).length > 0) {
1296
+ const names = Object.values(bundle.skills)
1297
+ .map((s) => s.meta.name)
1298
+ .join(", ");
1299
+ sections.push(`<skills-summary>\nSkills available in .agents/skills/: ${names}. Use \`docs-search\` to read a skill before starting a task it applies to.\n</skills-summary>`);
1146
1300
  }
1147
1301
  }
1148
1302
  catch { }
1149
- // 3. Personal memory index (skip if owner is the shared sentinel)
1150
- if (owner !== SHARED_OWNER) {
1303
+ if (compact) {
1304
+ // In compact mode, skip learnings and memory in the prompt.
1305
+ // The agent can access them via resource-read when needed.
1306
+ // Add a brief pointer so the agent knows they exist.
1307
+ sections.push(`<context-note>Shared learnings (LEARNINGS.md) and your personal memory (memory/MEMORY.md) are available via \`resource-read\`. Check them when making decisions that might benefit from prior context.</context-note>`);
1308
+ }
1309
+ else {
1310
+ // LEARNINGS.md from SQL (template-level instructions are in AGENTS.md above).
1311
+ // 2. Shared SQL scope
1151
1312
  try {
1152
- const memoryIndex = await resourceGetByPath(owner, "memory/MEMORY.md");
1153
- if (memoryIndex?.content?.trim()) {
1154
- sections.push(`<resource name="memory/MEMORY.md" scope="personal">\n${memoryIndex.content.trim()}\n</resource>`);
1313
+ const shared = await resourceGetByPath(SHARED_OWNER, "LEARNINGS.md");
1314
+ if (shared?.content?.trim()) {
1315
+ sections.push(`<resource name="LEARNINGS.md" scope="shared">\n${shared.content.trim()}\n</resource>`);
1155
1316
  }
1156
1317
  }
1157
1318
  catch { }
1319
+ // 3. Personal memory index (skip if owner is the shared sentinel)
1320
+ if (owner !== SHARED_OWNER) {
1321
+ try {
1322
+ const memoryIndex = await resourceGetByPath(owner, "memory/MEMORY.md");
1323
+ if (memoryIndex?.content?.trim()) {
1324
+ sections.push(`<resource name="memory/MEMORY.md" scope="personal">\n${memoryIndex.content.trim()}\n</resource>`);
1325
+ }
1326
+ }
1327
+ catch { }
1328
+ }
1158
1329
  }
1159
1330
  if (sections.length === 0)
1160
1331
  return "";
@@ -1272,11 +1443,9 @@ ${lines.join("\n")}`;
1272
1443
  }
1273
1444
  return `\n\n## Available Actions
1274
1445
 
1275
- **Use these actions directly to accomplish tasks. Do NOT use \`db-schema\`, \`search-files\`, or \`shell\` to explore the app these actions already connect to the correct database and services.**
1276
-
1277
- **For external data sources (BigQuery, HubSpot, Jira, GA4, etc.), use the data-source-specific action below — NOT \`db-query\`.** \`db-query\` only reaches the app's own internal database. If the user asks about tables not in the app schema, pick the matching action here.
1446
+ **Use these actions directly as tool calls.** They are your primary tools they handle database access, validation, and business logic internally. Prefer these over lower-level tools like \`web-request\` or \`db-query\`.
1278
1447
 
1279
- Parameter notation: \`name*\` = required, \`name?\` = optional. Always pass the tool's parameters as a JSON object to the tool_use call — never via shell or string-concatenated CLI flags.
1448
+ Parameter notation: \`name*\` = required, \`name?\` = optional. Pass parameters as a JSON object.
1280
1449
 
1281
1450
  ${lines.join("\n")}`;
1282
1451
  }
@@ -1467,16 +1636,31 @@ export function createAgentChatPlugin(options) {
1467
1636
  process.once("SIGTERM", stop);
1468
1637
  process.once("SIGINT", stop);
1469
1638
  }
1470
- // Resolve actions — prefer `actions`, fall back to deprecated `scripts`
1639
+ // Resolve actions — prefer explicit `actions`, fall back to deprecated
1640
+ // `scripts`. When neither is provided, auto-discover from the filesystem
1641
+ // so templates that forget to pass `actions` still work in non-serverless
1642
+ // deployments (serverless bundles need explicit imports).
1471
1643
  const rawActions = options?.actions ?? options?.scripts;
1472
- const templateScripts = typeof rawActions === "function"
1644
+ let templateScripts = typeof rawActions === "function"
1473
1645
  ? await rawActions()
1474
1646
  : (rawActions ?? {});
1647
+ if (!rawActions && Object.keys(templateScripts).length === 0) {
1648
+ try {
1649
+ const { autoDiscoverActions } = await import("./action-discovery.js");
1650
+ templateScripts = await autoDiscoverActions(process.cwd());
1651
+ }
1652
+ catch {
1653
+ // Filesystem discovery unavailable (serverless bundle) — skip.
1654
+ }
1655
+ }
1475
1656
  // Resource, chat, docs, db, and cross-agent scripts are available in both prod and dev modes
1476
1657
  const resourceScripts = await createResourceScriptEntries();
1477
1658
  const docsScripts = await createDocsScriptEntries();
1478
1659
  const dbScripts = await createDbScriptEntries();
1479
1660
  const refreshScreenTool = createRefreshScreenEntry();
1661
+ const frameworkContextTool = createFrameworkContextEntry();
1662
+ const leanPrompt = options?.leanPrompt === true;
1663
+ const lazyContext = options?.lazyContext !== false && !leanPrompt;
1480
1664
  const urlTools = createUrlTools();
1481
1665
  const engineScripts = await createAgentEngineScriptEntries();
1482
1666
  const chatScripts = {
@@ -1667,6 +1851,7 @@ export function createAgentChatPlugin(options) {
1667
1851
  ? {
1668
1852
  ...resourceScripts,
1669
1853
  ...docsScripts,
1854
+ ...(lazyContext ? frameworkContextTool : {}),
1670
1855
  ...chatScripts,
1671
1856
  ...callAgentScript,
1672
1857
  ...automationTools,
@@ -1683,6 +1868,7 @@ export function createAgentChatPlugin(options) {
1683
1868
  ...docsScripts,
1684
1869
  ...dbScripts,
1685
1870
  ...refreshScreenTool,
1871
+ ...(lazyContext ? frameworkContextTool : {}),
1686
1872
  ...urlTools,
1687
1873
  ...chatScripts,
1688
1874
  ...callAgentScript,
@@ -1767,8 +1953,10 @@ export function createAgentChatPlugin(options) {
1767
1953
  const handler = devActive && devHandler ? devHandler : prodHandler;
1768
1954
  // Build the same system prompt the interactive agent uses
1769
1955
  const owner = userEmail || "local@localhost";
1770
- const resources = await loadResourcesForPrompt(owner);
1771
- const schemaBlock = await buildSchemaBlock(owner, devActive);
1956
+ const resources = await loadResourcesForPrompt(owner, lazyContext);
1957
+ const schemaBlock = lazyContext
1958
+ ? ""
1959
+ : await buildSchemaBlock(owner, devActive);
1772
1960
  const systemPrompt = devActive
1773
1961
  ? devPrompt + resources + schemaBlock
1774
1962
  : basePrompt + resources + schemaBlock;
@@ -1782,6 +1970,7 @@ export function createAgentChatPlugin(options) {
1782
1970
  ? {
1783
1971
  ...resourceScripts,
1784
1972
  ...docsScripts,
1973
+ ...(lazyContext ? frameworkContextTool : {}),
1785
1974
  ...chatScripts,
1786
1975
  ...browserTools,
1787
1976
  ...devScriptsForA2A,
@@ -1792,6 +1981,7 @@ export function createAgentChatPlugin(options) {
1792
1981
  ...docsScripts,
1793
1982
  ...dbScripts,
1794
1983
  ...refreshScreenTool,
1984
+ ...(lazyContext ? frameworkContextTool : {}),
1795
1985
  ...urlTools,
1796
1986
  ...chatScripts,
1797
1987
  ...browserTools,
@@ -1852,11 +2042,26 @@ export function createAgentChatPlugin(options) {
1852
2042
  // Build system prompts — dynamic functions that pre-load resources per-request.
1853
2043
  // Production gets PROD_FRAMEWORK_PROMPT, dev gets DEV_FRAMEWORK_PROMPT.
1854
2044
  // Custom systemPrompt from options overrides the framework default entirely.
1855
- const prodPrompt = (options?.systemPrompt ?? PROD_FRAMEWORK_PROMPT) + prodActionsPrompt;
1856
- const devPrompt = (options?.devSystemPrompt
1857
- ? options.devSystemPrompt +
1858
- (options?.systemPrompt ?? PROD_FRAMEWORK_PROMPT)
1859
- : DEV_FRAMEWORK_PROMPT) + devActionsPrompt;
2045
+ const prodPrompt = (options?.systemPrompt ??
2046
+ (lazyContext
2047
+ ? PROD_FRAMEWORK_PROMPT_COMPACT
2048
+ : PROD_FRAMEWORK_PROMPT)) + prodActionsPrompt;
2049
+ // When template actions are registered as native tools in dev (via
2050
+ // `nativeActionsInDev` or `leanPrompt`), the dev prompt's "invoke
2051
+ // template actions via shell" guidance is wrong — use the prod prompt
2052
+ // + tool-format action list instead, same as production.
2053
+ const devNative = options?.nativeActionsInDev === true || leanPrompt;
2054
+ const devPrompt = devNative
2055
+ ? prodPrompt
2056
+ : (options?.devSystemPrompt
2057
+ ? options.devSystemPrompt +
2058
+ (options?.systemPrompt ??
2059
+ (lazyContext
2060
+ ? PROD_FRAMEWORK_PROMPT_COMPACT
2061
+ : PROD_FRAMEWORK_PROMPT))
2062
+ : lazyContext
2063
+ ? DEV_FRAMEWORK_PROMPT_COMPACT
2064
+ : DEV_FRAMEWORK_PROMPT) + devActionsPrompt;
1860
2065
  // Keep legacy names for the composition below
1861
2066
  const basePrompt = prodPrompt;
1862
2067
  const devPrefix = options?.devSystemPrompt ?? DEFAULT_DEV_PROMPT;
@@ -1882,6 +2087,7 @@ export function createAgentChatPlugin(options) {
1882
2087
  ? {
1883
2088
  ...resourceScripts,
1884
2089
  ...docsScripts,
2090
+ ...(lazyContext ? frameworkContextTool : {}),
1885
2091
  ...chatScripts,
1886
2092
  ...devScriptsForA2A,
1887
2093
  }
@@ -1891,14 +2097,29 @@ export function createAgentChatPlugin(options) {
1891
2097
  ...docsScripts,
1892
2098
  ...dbScripts,
1893
2099
  ...refreshScreenTool,
2100
+ ...(lazyContext ? frameworkContextTool : {}),
1894
2101
  ...urlTools,
1895
2102
  ...chatScripts,
1896
2103
  };
1897
2104
  const mcpTools = actionsToEngineTools(mcpActions);
1898
- const resources = await loadResourcesForPrompt("local@localhost");
1899
- const schemaBlock = await buildSchemaBlock("local@localhost", devActiveMcp);
2105
+ const resources = await loadResourcesForPrompt("local@localhost", lazyContext);
2106
+ const schemaBlock = lazyContext
2107
+ ? ""
2108
+ : await buildSchemaBlock("local@localhost", devActiveMcp);
2109
+ // Build the MCP handler's own prompt — always use the shell-based
2110
+ // dev prompt in dev mode because mcpActions routes template actions
2111
+ // through shell (`devScriptsForA2A`), regardless of `nativeActionsInDev`.
2112
+ const mcpDevPrompt = (options?.devSystemPrompt
2113
+ ? options.devSystemPrompt +
2114
+ (options?.systemPrompt ??
2115
+ (lazyContext
2116
+ ? PROD_FRAMEWORK_PROMPT_COMPACT
2117
+ : PROD_FRAMEWORK_PROMPT))
2118
+ : lazyContext
2119
+ ? DEV_FRAMEWORK_PROMPT_COMPACT
2120
+ : DEV_FRAMEWORK_PROMPT) + devActionsPrompt;
1900
2121
  const systemPrompt = devActiveMcp
1901
- ? devPrompt + resources + schemaBlock
2122
+ ? mcpDevPrompt + resources + schemaBlock
1902
2123
  : basePrompt + resources + schemaBlock;
1903
2124
  let accumulatedText = "";
1904
2125
  const controller = new AbortController();
@@ -1931,7 +2152,7 @@ export function createAgentChatPlugin(options) {
1931
2152
  }
1932
2153
  };
1933
2154
  // Auto-mount template actions as HTTP endpoints under /_agent-native/actions/
1934
- // Include engine management scripts so the UI can call list/set/test-agent-engine.
2155
+ // Include engine management script so the UI can call manage-agent-engine.
1935
2156
  const httpActions = {
1936
2157
  ...discoveredActions,
1937
2158
  ...templateScripts,
@@ -2041,20 +2262,42 @@ export function createAgentChatPlugin(options) {
2041
2262
  // Auto-checkpoint in dev mode after file-modifying agent turns
2042
2263
  if (isDevMode()) {
2043
2264
  try {
2044
- const { createCheckpoint: gitCheckpoint, isGitRepo, hasUncommittedChanges, } = await import("../checkpoints/service.js");
2265
+ const { createCheckpoint: gitCheckpoint, isGitRepo, hasUncommittedChanges, getChangedFileNames, } = await import("../checkpoints/service.js");
2045
2266
  const cwd = process.cwd();
2046
2267
  if (isGitRepo(cwd) && hasUncommittedChanges(cwd)) {
2047
- const toolNames = new Set();
2268
+ let summary = "";
2269
+ // Try to extract the first sentence of the assistant's text response
2270
+ let assistantText = "";
2048
2271
  for (const { event } of run.events ?? []) {
2049
- if (event.type === "tool_start" &&
2050
- typeof event.tool === "string") {
2051
- toolNames.add(event.tool);
2272
+ if (event.type === "text" && typeof event.text === "string") {
2273
+ assistantText += event.text;
2274
+ }
2275
+ }
2276
+ assistantText = assistantText.trim();
2277
+ if (assistantText) {
2278
+ const firstSentence = assistantText
2279
+ .split(/(?<=[.!?\n])\s/)[0]
2280
+ ?.replace(/\n/g, " ")
2281
+ .trim();
2282
+ if (firstSentence && firstSentence.length <= 120) {
2283
+ summary = firstSentence;
2284
+ }
2285
+ else if (firstSentence) {
2286
+ summary = firstSentence.slice(0, 117) + "...";
2052
2287
  }
2053
2288
  }
2054
- const summary = toolNames.size > 0
2055
- ? `Used: ${[...toolNames].join(", ")}`
2056
- : "Agent turn";
2057
- const sha = gitCheckpoint(cwd, `[agent-native] ${summary}`);
2289
+ // Fall back to listing changed files
2290
+ if (!summary) {
2291
+ const files = getChangedFileNames(cwd);
2292
+ if (files.length > 0) {
2293
+ summary = `Update ${files.join(", ")}`;
2294
+ }
2295
+ }
2296
+ if (!summary)
2297
+ summary = "Agent turn";
2298
+ if (summary.length > 120)
2299
+ summary = summary.slice(0, 117) + "...";
2300
+ const sha = gitCheckpoint(cwd, summary);
2058
2301
  if (sha) {
2059
2302
  const { insertCheckpoint } = await import("../checkpoints/store.js");
2060
2303
  const cpId = `cp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
@@ -2092,6 +2335,7 @@ export function createAgentChatPlugin(options) {
2092
2335
  // via shell, so omit them from the native tool registry.
2093
2336
  ...resourceScripts,
2094
2337
  ...docsScripts,
2338
+ ...(lazyContext ? frameworkContextTool : {}),
2095
2339
  ...chatScripts,
2096
2340
  ...devScriptsForA2A,
2097
2341
  }
@@ -2101,6 +2345,7 @@ export function createAgentChatPlugin(options) {
2101
2345
  ...docsScripts,
2102
2346
  ...dbScripts,
2103
2347
  ...refreshScreenTool,
2348
+ ...(lazyContext ? frameworkContextTool : {}),
2104
2349
  ...urlTools,
2105
2350
  ...chatScripts,
2106
2351
  },
@@ -2108,7 +2353,7 @@ export function createAgentChatPlugin(options) {
2108
2353
  createAnthropicEngine({
2109
2354
  // Sub-agents must inherit the parent run's resolved key so a
2110
2355
  // BYO-key user can't bypass the free-tier check on the parent
2111
- // run and then have spawn-task delegations bill the platform key.
2356
+ // run and then have agent-teams spawn delegations bill the platform key.
2112
2357
  apiKey: _currentRunUserApiKey ??
2113
2358
  options?.apiKey ??
2114
2359
  process.env.ANTHROPIC_API_KEY,
@@ -2122,7 +2367,7 @@ export function createAgentChatPlugin(options) {
2122
2367
  },
2123
2368
  });
2124
2369
  // Hook into the run lifecycle to set/clear the send reference.
2125
- // Job management tools (create-job, list-jobs, update-job)
2370
+ // Job management tool (manage-jobs)
2126
2371
  let jobTools = {};
2127
2372
  try {
2128
2373
  const { createJobTools } = await import("../jobs/tools.js");
@@ -2135,6 +2380,7 @@ export function createAgentChatPlugin(options) {
2135
2380
  ...docsScripts,
2136
2381
  ...dbScripts,
2137
2382
  ...refreshScreenTool,
2383
+ ...(lazyContext ? frameworkContextTool : {}),
2138
2384
  ...urlTools,
2139
2385
  ...chatScripts,
2140
2386
  ...callAgentScript,
@@ -2169,26 +2415,39 @@ export function createAgentChatPlugin(options) {
2169
2415
  return "";
2170
2416
  }
2171
2417
  };
2172
- const leanPrompt = options?.leanPrompt === true;
2173
2418
  // Lean mode: use only the template's systemPrompt + actions list.
2174
- // Skip resource loading, schema block, and extraContext — those add
2175
- // DB round-trips and tokens that minimal/voice apps don't need.
2419
+ // Skip resource loading and schema block — those add DB round-trips
2420
+ // and tokens that minimal/voice apps don't need.
2176
2421
  const leanBasePrompt = (options?.systemPrompt ?? "") + prodActionsPrompt;
2422
+ // Per-request preamble shared by both prod and dev handlers. Resolves
2423
+ // owner + user API key (stashed on the closure so downstream tools can
2424
+ // reach them) and the template-authored `extraContext`. `extraContext`
2425
+ // runs in every prompt variant (lean, lazy, full) — if a template
2426
+ // defined it, they opted in; framework-provided content is what the
2427
+ // token-saving modes strip.
2428
+ const prepareRun = async (event) => {
2429
+ _currentRequestOrigin = getOrigin(event);
2430
+ const owner = await getOwnerFromEvent(event);
2431
+ _currentRunOwner = owner;
2432
+ const { getOwnerActiveApiKey } = await import("../agent/production-agent.js");
2433
+ _currentRunUserApiKey = await getOwnerActiveApiKey(owner);
2434
+ const extra = await resolveExtraContext(event, owner);
2435
+ return { owner, extra };
2436
+ };
2177
2437
  const prodHandler = createProductionAgentHandler({
2178
2438
  actions: prodActions,
2179
2439
  systemPrompt: async (event) => {
2180
- _currentRequestOrigin = getOrigin(event);
2181
- const owner = await getOwnerFromEvent(event);
2182
- _currentRunOwner = owner;
2183
- const { getOwnerActiveApiKey } = await import("../agent/production-agent.js");
2184
- _currentRunUserApiKey = await getOwnerActiveApiKey(owner);
2440
+ const { owner, extra } = await prepareRun(event);
2185
2441
  if (leanPrompt) {
2186
- _currentRunSystemPrompt = leanBasePrompt;
2442
+ _currentRunSystemPrompt = leanBasePrompt + extra;
2187
2443
  return _currentRunSystemPrompt;
2188
2444
  }
2189
- const resources = await loadResourcesForPrompt(owner);
2190
- const schemaBlock = await buildSchemaBlock(owner, false);
2191
- const extra = await resolveExtraContext(event, owner);
2445
+ const resources = await loadResourcesForPrompt(owner, lazyContext);
2446
+ // In lazy context mode, skip embedding the full schema — the agent
2447
+ // calls `db-schema` on demand. This saves ~1-2K tokens per request.
2448
+ const schemaBlock = lazyContext
2449
+ ? ""
2450
+ : await buildSchemaBlock(owner, false);
2192
2451
  _currentRunSystemPrompt =
2193
2452
  basePrompt + resources + schemaBlock + extra;
2194
2453
  return _currentRunSystemPrompt;
@@ -2224,14 +2483,16 @@ export function createAgentChatPlugin(options) {
2224
2483
  // how Claude Code works locally and dramatically reduces the rate of
2225
2484
  // degenerate empty-object tool calls. The CLI syntax for each action is
2226
2485
  // listed in the dev system prompt's "Available Actions" section.
2227
- // In lean mode, expose the template's actions directly as native tools
2228
- // instead of routing through shell — the lean system prompt has no
2229
- // shell-usage guidance, so shell-based action invocation would break.
2230
- const devActions = leanPrompt
2486
+ // In lean mode or when `nativeActionsInDev` is set expose the
2487
+ // template's actions as native tools instead of routing through shell.
2488
+ // Templates with structured-arg actions (objects/arrays) need this to
2489
+ // avoid round-tripping JSON through the CLI parser.
2490
+ const devActions = devNative
2231
2491
  ? prodActions
2232
2492
  : {
2233
2493
  ...resourceScripts,
2234
2494
  ...docsScripts,
2495
+ ...(lazyContext ? frameworkContextTool : {}),
2235
2496
  ...chatScripts,
2236
2497
  ...callAgentScript,
2237
2498
  ...teamTools,
@@ -2245,8 +2506,8 @@ export function createAgentChatPlugin(options) {
2245
2506
  ...(await createDevScriptRegistry()),
2246
2507
  };
2247
2508
  // Keep dev action dict in sync with runtime MCP additions. When
2248
- // leanPrompt is true, devActions === prodActions so the prod listener
2249
- // already covers it.
2509
+ // native-actions mode is on (lean or `nativeActionsInDev`), devActions
2510
+ // === prodActions so the prod listener already covers it.
2250
2511
  if (devActions !== prodActions) {
2251
2512
  mcpManager.onChange(() => {
2252
2513
  syncMcpActionEntries(mcpManager, devActions);
@@ -2255,18 +2516,15 @@ export function createAgentChatPlugin(options) {
2255
2516
  devHandler = createProductionAgentHandler({
2256
2517
  actions: devActions,
2257
2518
  systemPrompt: async (event) => {
2258
- _currentRequestOrigin = getOrigin(event);
2259
- const owner = await getOwnerFromEvent(event);
2260
- _currentRunOwner = owner;
2261
- const { getOwnerActiveApiKey } = await import("../agent/production-agent.js");
2262
- _currentRunUserApiKey = await getOwnerActiveApiKey(owner);
2519
+ const { owner, extra } = await prepareRun(event);
2263
2520
  if (leanPrompt) {
2264
- _currentRunSystemPrompt = leanBasePrompt;
2521
+ _currentRunSystemPrompt = leanBasePrompt + extra;
2265
2522
  return _currentRunSystemPrompt;
2266
2523
  }
2267
- const resources = await loadResourcesForPrompt(owner);
2268
- const schemaBlock = await buildSchemaBlock(owner, true);
2269
- const extra = await resolveExtraContext(event, owner);
2524
+ const resources = await loadResourcesForPrompt(owner, lazyContext);
2525
+ const schemaBlock = lazyContext
2526
+ ? ""
2527
+ : await buildSchemaBlock(owner, true);
2270
2528
  _currentRunSystemPrompt =
2271
2529
  devPrompt + resources + schemaBlock + extra;
2272
2530
  return _currentRunSystemPrompt;
@@ -3130,6 +3388,7 @@ export function createAgentChatPlugin(options) {
3130
3388
  ...templateScripts,
3131
3389
  ...resourceScripts,
3132
3390
  ...docsScripts,
3391
+ ...(lazyContext ? frameworkContextTool : {}),
3133
3392
  ...chatScripts,
3134
3393
  ...jobTools,
3135
3394
  ...automationTools,
@@ -3138,8 +3397,10 @@ export function createAgentChatPlugin(options) {
3138
3397
  ...fetchTool,
3139
3398
  }),
3140
3399
  getSystemPrompt: async (owner) => {
3141
- const resources = await loadResourcesForPrompt(owner);
3142
- const schemaBlock = await buildSchemaBlock(owner, false);
3400
+ const resources = await loadResourcesForPrompt(owner, lazyContext);
3401
+ const schemaBlock = lazyContext
3402
+ ? ""
3403
+ : await buildSchemaBlock(owner, false);
3143
3404
  return basePrompt + resources + schemaBlock;
3144
3405
  },
3145
3406
  apiKey: options?.apiKey ?? process.env.ANTHROPIC_API_KEY,
@@ -3167,6 +3428,7 @@ export function createAgentChatPlugin(options) {
3167
3428
  ...templateScripts,
3168
3429
  ...resourceScripts,
3169
3430
  ...docsScripts,
3431
+ ...(lazyContext ? frameworkContextTool : {}),
3170
3432
  ...chatScripts,
3171
3433
  ...jobTools,
3172
3434
  ...automationTools,
@@ -3175,8 +3437,10 @@ export function createAgentChatPlugin(options) {
3175
3437
  ...fetchTool,
3176
3438
  }),
3177
3439
  getSystemPrompt: async (owner) => {
3178
- const resources = await loadResourcesForPrompt(owner);
3179
- const schemaBlock = await buildSchemaBlock(owner, false);
3440
+ const resources = await loadResourcesForPrompt(owner, lazyContext);
3441
+ const schemaBlock = lazyContext
3442
+ ? ""
3443
+ : await buildSchemaBlock(owner, false);
3180
3444
  return basePrompt + resources + schemaBlock;
3181
3445
  },
3182
3446
  apiKey: options?.apiKey ?? process.env.ANTHROPIC_API_KEY,