@agent-native/core 0.13.1 → 0.14.0

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 (67) hide show
  1. package/dist/agent/production-agent.d.ts +23 -1
  2. package/dist/agent/production-agent.d.ts.map +1 -1
  3. package/dist/agent/production-agent.js +82 -1
  4. package/dist/agent/production-agent.js.map +1 -1
  5. package/dist/agent/run-store.d.ts.map +1 -1
  6. package/dist/agent/run-store.js +8 -2
  7. package/dist/agent/run-store.js.map +1 -1
  8. package/dist/agent/types.d.ts +1 -1
  9. package/dist/agent/types.d.ts.map +1 -1
  10. package/dist/agent/types.js.map +1 -1
  11. package/dist/client/AssistantChat.d.ts.map +1 -1
  12. package/dist/client/AssistantChat.js +1 -1
  13. package/dist/client/AssistantChat.js.map +1 -1
  14. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  15. package/dist/client/ConnectBuilderCard.js +24 -0
  16. package/dist/client/ConnectBuilderCard.js.map +1 -1
  17. package/dist/client/analytics.d.ts.map +1 -1
  18. package/dist/client/analytics.js +10 -1
  19. package/dist/client/analytics.js.map +1 -1
  20. package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
  21. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  22. package/dist/client/use-db-sync.d.ts.map +1 -1
  23. package/dist/client/use-db-sync.js +3 -1
  24. package/dist/client/use-db-sync.js.map +1 -1
  25. package/dist/db/client.d.ts.map +1 -1
  26. package/dist/db/client.js +9 -0
  27. package/dist/db/client.js.map +1 -1
  28. package/dist/db/create-get-db.d.ts.map +1 -1
  29. package/dist/db/create-get-db.js +7 -0
  30. package/dist/db/create-get-db.js.map +1 -1
  31. package/dist/extensions/actions.js +1 -1
  32. package/dist/extensions/actions.js.map +1 -1
  33. package/dist/extensions/fetch-tool.d.ts.map +1 -1
  34. package/dist/extensions/fetch-tool.js +46 -5
  35. package/dist/extensions/fetch-tool.js.map +1 -1
  36. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  37. package/dist/server/agent-chat-plugin.js +73 -7
  38. package/dist/server/agent-chat-plugin.js.map +1 -1
  39. package/dist/server/agent-discovery.d.ts +21 -0
  40. package/dist/server/agent-discovery.d.ts.map +1 -1
  41. package/dist/server/agent-discovery.js +18 -3
  42. package/dist/server/agent-discovery.js.map +1 -1
  43. package/dist/server/auth.d.ts +27 -0
  44. package/dist/server/auth.d.ts.map +1 -1
  45. package/dist/server/auth.js +71 -12
  46. package/dist/server/auth.js.map +1 -1
  47. package/dist/server/better-auth-instance.js +13 -0
  48. package/dist/server/better-auth-instance.js.map +1 -1
  49. package/dist/server/google-auth-mode.d.ts +20 -0
  50. package/dist/server/google-auth-mode.d.ts.map +1 -0
  51. package/dist/server/google-auth-mode.js +20 -0
  52. package/dist/server/google-auth-mode.js.map +1 -0
  53. package/dist/server/google-auth-plugin.d.ts +7 -0
  54. package/dist/server/google-auth-plugin.d.ts.map +1 -1
  55. package/dist/server/google-auth-plugin.js +21 -5
  56. package/dist/server/google-auth-plugin.js.map +1 -1
  57. package/dist/server/index.d.ts +1 -0
  58. package/dist/server/index.d.ts.map +1 -1
  59. package/dist/server/index.js.map +1 -1
  60. package/dist/server/onboarding-html.d.ts +7 -0
  61. package/dist/server/onboarding-html.d.ts.map +1 -1
  62. package/dist/server/onboarding-html.js +22 -3
  63. package/dist/server/onboarding-html.js.map +1 -1
  64. package/dist/server/sentry.d.ts.map +1 -1
  65. package/dist/server/sentry.js +41 -0
  66. package/dist/server/sentry.js.map +1 -1
  67. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/extensions/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionEntry } from \"../agent/production-agent.js\";\nimport { writeAppState } from \"../application-state/script-helpers.js\";\nimport {\n createExtension,\n deleteExtension,\n getHiddenExtensionIdsForCurrentUser,\n getExtension,\n hideExtension,\n listExtensions,\n unhideExtension,\n updateExtension,\n updateExtensionContent,\n type ExtensionRow,\n} from \"./store.js\";\nimport { resolveAccess } from \"../sharing/access.js\";\nimport {\n addExtensionSlotTarget,\n installExtensionSlot,\n uninstallExtensionSlot,\n listExtensionsForSlot,\n listSlotsForExtension,\n} from \"./slots/store.js\";\n\ntype ExtensionPatch = { find: string; replace: string };\n\nexport function createExtensionActionEntries(): Record<string, ActionEntry> {\n return {\n \"list-extensions\": {\n tool: {\n description:\n \"List extensions visible in the current user's Extensions list/sidebar. Use this before updating, hiding, or deleting existing extensions; do not query the legacy tools table directly for extension management.\",\n parameters: {\n type: \"object\",\n properties: {\n search: {\n type: \"string\",\n description:\n \"Optional case-insensitive filter matched against id, name, description, and owner email. Example: Connect Zoom.\",\n },\n includeHidden: {\n type: \"boolean\",\n description:\n \"Include extensions the current user has hidden from their list. Defaults to false.\",\n },\n includeContent: {\n type: \"boolean\",\n description:\n \"Include full Alpine.js content. Defaults to false to keep results concise.\",\n },\n limit: {\n type: \"number\",\n description: \"Maximum results to return. Defaults to 100.\",\n },\n },\n },\n },\n run: async (args) => {\n const includeHidden = coerceBoolean(args?.includeHidden);\n const includeContent = coerceBoolean(args?.includeContent);\n const search = String(args?.search ?? \"\")\n .trim()\n .toLowerCase();\n const limit = coerceLimit(args?.limit);\n const hiddenIds = await getHiddenExtensionIdsForCurrentUser();\n\n let rows = await listExtensions({ includeHidden });\n if (search) {\n rows = rows.filter((row) =>\n [row.id, row.name, row.description, row.ownerEmail]\n .join(\"\\n\")\n .toLowerCase()\n .includes(search),\n );\n }\n\n rows = rows.slice(0, limit);\n const extensions = await Promise.all(\n rows.map((row) => summarizeExtension(row, hiddenIds, includeContent)),\n );\n return {\n ok: true,\n count: extensions.length,\n extensions,\n };\n },\n readOnly: true,\n },\n\n \"create-extension\": {\n tool: {\n description:\n \"Create a sandboxed Alpine.js mini-app extension. Use this when the user asks to create, build, or make an extension/widget/dashboard/calculator. Call this action exactly once per requested extension. The content must be a self-contained Alpine.js HTML body snippet that can use appAction(), appFetch(), dbQuery(), dbExec(), extensionFetch(), and extensionData. Prefer appAction(name, params) for app data and actions, including read actions mounted as GET; do not call template /api/* routes from appFetch because the extension bridge only allows framework /_agent-native/* paths. Parse JSON string action results before aggregating; use dbQuery()/dbExec() only for known existing SQL tables.\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n 'Short display name for the extension. Do not include \"app\" — e.g. name a todo app \"Todos\", a weather app \"Weather\".',\n },\n description: {\n type: \"string\",\n description: \"One-sentence summary of what the extension does.\",\n },\n content: {\n type: \"string\",\n description:\n \"Self-contained Alpine.js HTML body snippet. The iframe canvas already has modest default padding, so avoid duplicate outer padding unless the design needs it. Use semantic Tailwind colors (bg-background, text-foreground, bg-primary, etc.) for native theming. Do not include a full app build, React code, or source files.\",\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n },\n required: [\"name\", \"content\"],\n },\n },\n run: async (args) => {\n const name = String(args?.name ?? \"\").trim();\n const content = String(args?.content ?? \"\").trim();\n if (!name) return \"Error: name is required.\";\n if (!content) return \"Error: content is required.\";\n\n const extension = await createExtension({\n name,\n description: String(args?.description ?? \"\").trim(),\n content,\n icon: args?.icon ? String(args.icon) : undefined,\n });\n\n // Auto-navigate so the user lands on the new extension instead of\n // having to read the JSON response and click a link. Writes a\n // one-shot `navigate` app-state command the UI consumes and clears.\n try {\n await writeAppState(\"navigate\", {\n view: \"extensions\",\n extensionId: extension.id,\n path: `/extensions/${extension.id}`,\n });\n } catch {\n // Non-fatal — agent can still mention the path in its reply.\n }\n\n return {\n ok: true,\n extension,\n next: `Created. The user is being navigated to the new extension automatically — no further navigation tool calls needed.`,\n };\n },\n },\n\n \"update-extension\": {\n tool: {\n description:\n \"Update an existing sandboxed Alpine.js mini-app extension. Prefer patches for surgical edits; use full content replacement only when necessary.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Extension id to update.\",\n },\n name: {\n type: \"string\",\n description: \"Optional new display name.\",\n },\n description: {\n type: \"string\",\n description: \"Optional new description.\",\n },\n content: {\n type: \"string\",\n description:\n \"Optional full replacement Alpine.js HTML body snippet.\",\n },\n patches: {\n type: \"string\",\n description:\n 'Optional JSON array of { \"find\": \"...\", \"replace\": \"...\" } patches to apply to the current content.',\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n visibility: {\n type: \"string\",\n description: \"Optional sharing visibility.\",\n enum: [\"private\", \"org\", \"public\"],\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n\n let result = null;\n if (args?.content !== undefined || args?.patches !== undefined) {\n const patches = parsePatches((args as any).patches);\n if (args?.patches !== undefined && !patches) {\n return \"Error: patches must be a JSON array of { find, replace } objects.\";\n }\n result = await updateExtensionContent(id, {\n content:\n args?.content !== undefined ? String(args.content) : undefined,\n patches,\n });\n }\n\n const meta: Record<string, string> = {};\n if (args?.name !== undefined) meta.name = String(args.name).trim();\n if (args?.description !== undefined) {\n meta.description = String(args.description).trim();\n }\n if (args?.icon !== undefined) meta.icon = String(args.icon);\n if (args?.visibility !== undefined) {\n meta.visibility = String(args.visibility);\n }\n if (Object.keys(meta).length > 0) {\n result = await updateExtension(id, meta as any);\n }\n\n if (!result) result = await getExtension(id);\n if (!result) return `Error: extension not found: ${id}`;\n const hiddenIds = await getHiddenExtensionIdsForCurrentUser();\n return {\n ok: true,\n extension: await summarizeExtension(result, hiddenIds, false),\n };\n },\n },\n\n \"delete-extension\": {\n tool: {\n description:\n \"Permanently delete an extension everywhere it is shared. Requires owner/admin access. If the user only wants a shared extension removed from their own sidebar/list, use hide-extension instead.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description:\n \"Extension id to permanently delete. Use list-extensions first if you only know the display name.\",\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n const extension = await getExtension(id);\n if (!extension) return `Error: extension not found: ${id}`;\n\n try {\n const ok = await deleteExtension(id);\n if (!ok) return `Error: extension not found: ${id}`;\n return { ok: true, deleted: summarizeDeletedExtension(extension) };\n } catch (err: any) {\n return {\n ok: false,\n error: err?.message ?? String(err),\n next: \"If the user wants this gone only from their own view, call hide-extension with the same id.\",\n };\n }\n },\n },\n\n \"hide-extension\": {\n tool: {\n description:\n \"Hide an accessible extension from the current user's Extensions list/sidebar without deleting it for anyone else. Use this when the user says to remove a shared extension from their view, or when delete-extension reports that the current user is not owner/admin.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description:\n \"Extension id to hide for the current user. Use list-extensions first if you only know the display name.\",\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n const extension = await getExtension(id);\n if (!extension) return `Error: extension not found: ${id}`;\n\n await hideExtension(id);\n return { ok: true, hidden: summarizeDeletedExtension(extension) };\n },\n },\n\n \"unhide-extension\": {\n tool: {\n description:\n \"Restore an extension the current user previously hid so it appears in their Extensions list/sidebar again. Use list-extensions with includeHidden=true to find hidden ids.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Extension id to restore for the current user.\",\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n await unhideExtension(id);\n return { ok: true, id };\n },\n },\n\n \"add-extension-slot-target\": {\n tool: {\n description:\n 'Declare that an extension can render in a UI extension-point slot of an app (e.g. \"mail.contact-sidebar.bottom\"). Apps drop ExtensionSlot components in their UI; this action registers an extension as installable into one of those slots. Slot IDs follow the convention <app>.<area>.<position>. Caller must have editor access to the extension.',\n parameters: {\n type: \"object\",\n properties: {\n extensionId: { type: \"string\", description: \"Extension id.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with slot-specific config (defaults, hints, etc.).\",\n },\n },\n required: [\"extensionId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const row = await addExtensionSlotTarget(\n extensionId,\n slotId,\n args?.config ? String(args.config) : undefined,\n );\n return { ok: true, slot: row };\n },\n },\n\n \"install-extension\": {\n tool: {\n description:\n \"Install an extension as a widget in an extension-point slot for the current user. The extension must already declare the slot via add-extension-slot-target. Per-user installation — only affects the calling user's view. Use after creating an extension that targets a slot, or when the user asks to add an existing widget to a slot.\",\n parameters: {\n type: \"object\",\n properties: {\n extensionId: {\n type: \"string\",\n description: \"Extension id to install.\",\n },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n position: {\n type: \"number\",\n description:\n \"Optional integer position within the slot (lower = earlier). Defaults to end.\",\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with per-install config (overrides, settings).\",\n },\n },\n required: [\"extensionId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const position =\n args?.position !== undefined && args.position !== null\n ? Number(args.position)\n : undefined;\n const row = await installExtensionSlot(extensionId, slotId, {\n position: Number.isFinite(position as number) ? position : undefined,\n config: args?.config ? String(args.config) : undefined,\n });\n return { ok: true, install: row };\n },\n },\n\n \"uninstall-extension\": {\n tool: {\n description:\n \"Remove an extension from an extension-point slot for the current user. Does not delete the extension itself.\",\n parameters: {\n type: \"object\",\n properties: {\n extensionId: { type: \"string\", description: \"Extension id.\" },\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"extensionId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n await uninstallExtensionSlot(extensionId, slotId);\n return { ok: true };\n },\n },\n\n \"list-extensions-for-slot\": {\n tool: {\n description:\n \"List extensions the current user has access to that declare a given extension-point slot. Use to discover what's available to install into a slot the user mentioned.\",\n parameters: {\n type: \"object\",\n properties: {\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"slotId\"],\n },\n },\n run: async (args) => {\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!slotId) return \"Error: slotId is required.\";\n return { extensions: await listExtensionsForSlot(slotId) };\n },\n readOnly: true,\n },\n\n \"list-extension-slots\": {\n tool: {\n description:\n \"List the extension-point slots a specific extension declares it can render in. Caller must have viewer access to the extension.\",\n parameters: {\n type: \"object\",\n properties: {\n extensionId: { type: \"string\", description: \"Extension id.\" },\n },\n required: [\"extensionId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n return { slots: await listSlotsForExtension(extensionId) };\n },\n readOnly: true,\n },\n };\n}\n\nasync function summarizeExtension(\n row: ExtensionRow,\n hiddenIds: Set<string>,\n includeContent: boolean,\n) {\n const access = await resolveAccess(\"extension\", row.id).catch(() => null);\n return {\n id: row.id,\n name: row.name,\n description: row.description,\n icon: row.icon,\n ownerEmail: row.ownerEmail,\n visibility: row.visibility,\n role: access?.role ?? null,\n canEdit: access\n ? [\"owner\", \"admin\", \"editor\"].includes(access.role)\n : false,\n canDelete: access ? [\"owner\", \"admin\"].includes(access.role) : false,\n hidden: hiddenIds.has(row.id),\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n ...(includeContent ? { content: row.content } : {}),\n };\n}\n\nfunction summarizeDeletedExtension(row: ExtensionRow) {\n return {\n id: row.id,\n name: row.name,\n ownerEmail: row.ownerEmail,\n visibility: row.visibility,\n };\n}\n\nfunction coerceBoolean(value: unknown): boolean {\n return value === true || value === \"true\";\n}\n\nfunction coerceLimit(value: unknown): number {\n const limit = Number(value ?? 100);\n if (!Number.isFinite(limit)) return 100;\n return Math.min(Math.max(1, Math.floor(limit)), 500);\n}\n\nfunction parsePatches(value: unknown): ExtensionPatch[] | undefined {\n if (value === undefined) return undefined;\n const parsed = typeof value === \"string\" ? JSON.parse(value) : value;\n if (!Array.isArray(parsed)) return undefined;\n if (\n parsed.some(\n (patch) =>\n !patch ||\n typeof patch.find !== \"string\" ||\n typeof patch.replace !== \"string\",\n )\n ) {\n return undefined;\n }\n return parsed;\n}\n"]}
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/extensions/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionEntry } from \"../agent/production-agent.js\";\nimport { writeAppState } from \"../application-state/script-helpers.js\";\nimport {\n createExtension,\n deleteExtension,\n getHiddenExtensionIdsForCurrentUser,\n getExtension,\n hideExtension,\n listExtensions,\n unhideExtension,\n updateExtension,\n updateExtensionContent,\n type ExtensionRow,\n} from \"./store.js\";\nimport { resolveAccess } from \"../sharing/access.js\";\nimport {\n addExtensionSlotTarget,\n installExtensionSlot,\n uninstallExtensionSlot,\n listExtensionsForSlot,\n listSlotsForExtension,\n} from \"./slots/store.js\";\n\ntype ExtensionPatch = { find: string; replace: string };\n\nexport function createExtensionActionEntries(): Record<string, ActionEntry> {\n return {\n \"list-extensions\": {\n tool: {\n description:\n \"List extensions visible in the current user's Extensions list/sidebar. Use this before updating, hiding, or deleting existing extensions; do not query the legacy tools table directly for extension management.\",\n parameters: {\n type: \"object\",\n properties: {\n search: {\n type: \"string\",\n description:\n \"Optional case-insensitive filter matched against id, name, description, and owner email. Example: Connect Zoom.\",\n },\n includeHidden: {\n type: \"boolean\",\n description:\n \"Include extensions the current user has hidden from their list. Defaults to false.\",\n },\n includeContent: {\n type: \"boolean\",\n description:\n \"Include full Alpine.js content. Defaults to false to keep results concise.\",\n },\n limit: {\n type: \"number\",\n description: \"Maximum results to return. Defaults to 100.\",\n },\n },\n },\n },\n run: async (args) => {\n const includeHidden = coerceBoolean(args?.includeHidden);\n const includeContent = coerceBoolean(args?.includeContent);\n const search = String(args?.search ?? \"\")\n .trim()\n .toLowerCase();\n const limit = coerceLimit(args?.limit);\n const hiddenIds = await getHiddenExtensionIdsForCurrentUser();\n\n let rows = await listExtensions({ includeHidden });\n if (search) {\n rows = rows.filter((row) =>\n [row.id, row.name, row.description, row.ownerEmail]\n .join(\"\\n\")\n .toLowerCase()\n .includes(search),\n );\n }\n\n rows = rows.slice(0, limit);\n const extensions = await Promise.all(\n rows.map((row) => summarizeExtension(row, hiddenIds, includeContent)),\n );\n return {\n ok: true,\n count: extensions.length,\n extensions,\n };\n },\n readOnly: true,\n },\n\n \"create-extension\": {\n tool: {\n description:\n \"Create a sandboxed Alpine.js mini-app extension. Use this when the user asks to create, build, or make an extension/widget/dashboard/calculator. Call this action exactly once per requested extension. The content must be a self-contained Alpine.js HTML body snippet that can use appAction(), appFetch(), dbQuery(), dbExec(), extensionFetch(), and extensionData. Prefer appAction(name, params) for app data and actions, including read actions mounted as GET; do not call template /api/* routes from appFetch because the extension bridge only allows framework /_agent-native/* paths. Parse JSON string action results before aggregating; use dbQuery()/dbExec() only for known existing SQL tables. For any non-trivial component (more than a couple of state fields, any methods, any string formatting, any branching) put the component in a <script> block via Alpine.data('name', () => ({...})) and reference it with x-data=\\\"name\\\" — do NOT cram methods, template literals, or branching logic into an inline x-data=\\\"{...}\\\" attribute (HTML parser pitfalls cause ReferenceError failures). Define every variable referenced from x-text/x-show/x-if/x-for on the data object's initial state. If the extension's value depends on an LLM call, require a real key via ${keys.OPENAI_API_KEY}/${keys.ANTHROPIC_API_KEY} (and tell the user to add it in Settings → Secrets if missing) or route the AI work to the agent chat — never ship a stubbed analysis step that renders a placeholder/boolean as the result.\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n 'Short display name for the extension. Do not include \"app\" — e.g. name a todo app \"Todos\", a weather app \"Weather\".',\n },\n description: {\n type: \"string\",\n description: \"One-sentence summary of what the extension does.\",\n },\n content: {\n type: \"string\",\n description:\n \"Self-contained Alpine.js HTML body snippet. The iframe canvas already has modest default padding, so avoid duplicate outer padding unless the design needs it. Use semantic Tailwind colors (bg-background, text-foreground, bg-primary, etc.) for native theming. Do not include a full app build, React code, or source files.\",\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n },\n required: [\"name\", \"content\"],\n },\n },\n run: async (args) => {\n const name = String(args?.name ?? \"\").trim();\n const content = String(args?.content ?? \"\").trim();\n if (!name) return \"Error: name is required.\";\n if (!content) return \"Error: content is required.\";\n\n const extension = await createExtension({\n name,\n description: String(args?.description ?? \"\").trim(),\n content,\n icon: args?.icon ? String(args.icon) : undefined,\n });\n\n // Auto-navigate so the user lands on the new extension instead of\n // having to read the JSON response and click a link. Writes a\n // one-shot `navigate` app-state command the UI consumes and clears.\n try {\n await writeAppState(\"navigate\", {\n view: \"extensions\",\n extensionId: extension.id,\n path: `/extensions/${extension.id}`,\n });\n } catch {\n // Non-fatal — agent can still mention the path in its reply.\n }\n\n return {\n ok: true,\n extension,\n next: `Created. The user is being navigated to the new extension automatically — no further navigation tool calls needed.`,\n };\n },\n },\n\n \"update-extension\": {\n tool: {\n description:\n \"Update an existing sandboxed Alpine.js mini-app extension. Prefer patches for surgical edits; use full content replacement only when necessary.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Extension id to update.\",\n },\n name: {\n type: \"string\",\n description: \"Optional new display name.\",\n },\n description: {\n type: \"string\",\n description: \"Optional new description.\",\n },\n content: {\n type: \"string\",\n description:\n \"Optional full replacement Alpine.js HTML body snippet.\",\n },\n patches: {\n type: \"string\",\n description:\n 'Optional JSON array of { \"find\": \"...\", \"replace\": \"...\" } patches to apply to the current content.',\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n visibility: {\n type: \"string\",\n description: \"Optional sharing visibility.\",\n enum: [\"private\", \"org\", \"public\"],\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n\n let result = null;\n if (args?.content !== undefined || args?.patches !== undefined) {\n const patches = parsePatches((args as any).patches);\n if (args?.patches !== undefined && !patches) {\n return \"Error: patches must be a JSON array of { find, replace } objects.\";\n }\n result = await updateExtensionContent(id, {\n content:\n args?.content !== undefined ? String(args.content) : undefined,\n patches,\n });\n }\n\n const meta: Record<string, string> = {};\n if (args?.name !== undefined) meta.name = String(args.name).trim();\n if (args?.description !== undefined) {\n meta.description = String(args.description).trim();\n }\n if (args?.icon !== undefined) meta.icon = String(args.icon);\n if (args?.visibility !== undefined) {\n meta.visibility = String(args.visibility);\n }\n if (Object.keys(meta).length > 0) {\n result = await updateExtension(id, meta as any);\n }\n\n if (!result) result = await getExtension(id);\n if (!result) return `Error: extension not found: ${id}`;\n const hiddenIds = await getHiddenExtensionIdsForCurrentUser();\n return {\n ok: true,\n extension: await summarizeExtension(result, hiddenIds, false),\n };\n },\n },\n\n \"delete-extension\": {\n tool: {\n description:\n \"Permanently delete an extension everywhere it is shared. Requires owner/admin access. If the user only wants a shared extension removed from their own sidebar/list, use hide-extension instead.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description:\n \"Extension id to permanently delete. Use list-extensions first if you only know the display name.\",\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n const extension = await getExtension(id);\n if (!extension) return `Error: extension not found: ${id}`;\n\n try {\n const ok = await deleteExtension(id);\n if (!ok) return `Error: extension not found: ${id}`;\n return { ok: true, deleted: summarizeDeletedExtension(extension) };\n } catch (err: any) {\n return {\n ok: false,\n error: err?.message ?? String(err),\n next: \"If the user wants this gone only from their own view, call hide-extension with the same id.\",\n };\n }\n },\n },\n\n \"hide-extension\": {\n tool: {\n description:\n \"Hide an accessible extension from the current user's Extensions list/sidebar without deleting it for anyone else. Use this when the user says to remove a shared extension from their view, or when delete-extension reports that the current user is not owner/admin.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description:\n \"Extension id to hide for the current user. Use list-extensions first if you only know the display name.\",\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n const extension = await getExtension(id);\n if (!extension) return `Error: extension not found: ${id}`;\n\n await hideExtension(id);\n return { ok: true, hidden: summarizeDeletedExtension(extension) };\n },\n },\n\n \"unhide-extension\": {\n tool: {\n description:\n \"Restore an extension the current user previously hid so it appears in their Extensions list/sidebar again. Use list-extensions with includeHidden=true to find hidden ids.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Extension id to restore for the current user.\",\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n await unhideExtension(id);\n return { ok: true, id };\n },\n },\n\n \"add-extension-slot-target\": {\n tool: {\n description:\n 'Declare that an extension can render in a UI extension-point slot of an app (e.g. \"mail.contact-sidebar.bottom\"). Apps drop ExtensionSlot components in their UI; this action registers an extension as installable into one of those slots. Slot IDs follow the convention <app>.<area>.<position>. Caller must have editor access to the extension.',\n parameters: {\n type: \"object\",\n properties: {\n extensionId: { type: \"string\", description: \"Extension id.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with slot-specific config (defaults, hints, etc.).\",\n },\n },\n required: [\"extensionId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const row = await addExtensionSlotTarget(\n extensionId,\n slotId,\n args?.config ? String(args.config) : undefined,\n );\n return { ok: true, slot: row };\n },\n },\n\n \"install-extension\": {\n tool: {\n description:\n \"Install an extension as a widget in an extension-point slot for the current user. The extension must already declare the slot via add-extension-slot-target. Per-user installation — only affects the calling user's view. Use after creating an extension that targets a slot, or when the user asks to add an existing widget to a slot.\",\n parameters: {\n type: \"object\",\n properties: {\n extensionId: {\n type: \"string\",\n description: \"Extension id to install.\",\n },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n position: {\n type: \"number\",\n description:\n \"Optional integer position within the slot (lower = earlier). Defaults to end.\",\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with per-install config (overrides, settings).\",\n },\n },\n required: [\"extensionId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const position =\n args?.position !== undefined && args.position !== null\n ? Number(args.position)\n : undefined;\n const row = await installExtensionSlot(extensionId, slotId, {\n position: Number.isFinite(position as number) ? position : undefined,\n config: args?.config ? String(args.config) : undefined,\n });\n return { ok: true, install: row };\n },\n },\n\n \"uninstall-extension\": {\n tool: {\n description:\n \"Remove an extension from an extension-point slot for the current user. Does not delete the extension itself.\",\n parameters: {\n type: \"object\",\n properties: {\n extensionId: { type: \"string\", description: \"Extension id.\" },\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"extensionId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n await uninstallExtensionSlot(extensionId, slotId);\n return { ok: true };\n },\n },\n\n \"list-extensions-for-slot\": {\n tool: {\n description:\n \"List extensions the current user has access to that declare a given extension-point slot. Use to discover what's available to install into a slot the user mentioned.\",\n parameters: {\n type: \"object\",\n properties: {\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"slotId\"],\n },\n },\n run: async (args) => {\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!slotId) return \"Error: slotId is required.\";\n return { extensions: await listExtensionsForSlot(slotId) };\n },\n readOnly: true,\n },\n\n \"list-extension-slots\": {\n tool: {\n description:\n \"List the extension-point slots a specific extension declares it can render in. Caller must have viewer access to the extension.\",\n parameters: {\n type: \"object\",\n properties: {\n extensionId: { type: \"string\", description: \"Extension id.\" },\n },\n required: [\"extensionId\"],\n },\n },\n run: async (args) => {\n const extensionId = String(args?.extensionId ?? \"\").trim();\n if (!extensionId) return \"Error: extensionId is required.\";\n return { slots: await listSlotsForExtension(extensionId) };\n },\n readOnly: true,\n },\n };\n}\n\nasync function summarizeExtension(\n row: ExtensionRow,\n hiddenIds: Set<string>,\n includeContent: boolean,\n) {\n const access = await resolveAccess(\"extension\", row.id).catch(() => null);\n return {\n id: row.id,\n name: row.name,\n description: row.description,\n icon: row.icon,\n ownerEmail: row.ownerEmail,\n visibility: row.visibility,\n role: access?.role ?? null,\n canEdit: access\n ? [\"owner\", \"admin\", \"editor\"].includes(access.role)\n : false,\n canDelete: access ? [\"owner\", \"admin\"].includes(access.role) : false,\n hidden: hiddenIds.has(row.id),\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n ...(includeContent ? { content: row.content } : {}),\n };\n}\n\nfunction summarizeDeletedExtension(row: ExtensionRow) {\n return {\n id: row.id,\n name: row.name,\n ownerEmail: row.ownerEmail,\n visibility: row.visibility,\n };\n}\n\nfunction coerceBoolean(value: unknown): boolean {\n return value === true || value === \"true\";\n}\n\nfunction coerceLimit(value: unknown): number {\n const limit = Number(value ?? 100);\n if (!Number.isFinite(limit)) return 100;\n return Math.min(Math.max(1, Math.floor(limit)), 500);\n}\n\nfunction parsePatches(value: unknown): ExtensionPatch[] | undefined {\n if (value === undefined) return undefined;\n const parsed = typeof value === \"string\" ? JSON.parse(value) : value;\n if (!Array.isArray(parsed)) return undefined;\n if (\n parsed.some(\n (patch) =>\n !patch ||\n typeof patch.find !== \"string\" ||\n typeof patch.replace !== \"string\",\n )\n ) {\n return undefined;\n }\n return parsed;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-tool.d.ts","sourceRoot":"","sources":["../../src/extensions/fetch-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAchE,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QACtC,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,+CAA+C;IAC/C,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,GAAE,gBAAqB,GAC1B,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAmM7B"}
1
+ {"version":3,"file":"fetch-tool.d.ts","sourceRoot":"","sources":["../../src/extensions/fetch-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAqDhE,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QACtC,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,+CAA+C;IAC/C,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,GAAE,gBAAqB,GAC1B,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CA2M7B"}
@@ -12,6 +12,39 @@
12
12
  import { collectSecretValues, MAX_EXTENSION_PROXY_RESPONSE_SIZE, normalizeExtensionProxyMethod, readResponseTextWithLimit, redactSecrets, redactString, sanitizeOutboundHeaders, } from "./proxy-security.js";
13
13
  import { isBlockedExtensionUrlWithDns } from "./url-safety.js";
14
14
  const DEFAULT_TIMEOUT_MS = 15_000;
15
+ /**
16
+ * Headers that mimic a current Chrome on macOS so anti-bot middleware (Cloudflare,
17
+ * PerimeterX, Akamai) treats the request as a real user. We only fill in fields
18
+ * the caller hasn't supplied — explicit headers (e.g. an `Authorization` header
19
+ * for an API call) always win.
20
+ *
21
+ * `Accept-Encoding` deliberately omits `zstd` because Node's undici fetch only
22
+ * decompresses `gzip`, `deflate`, and `br`. Advertising `zstd` would let some
23
+ * servers send bytes we can't decode.
24
+ */
25
+ const BROWSER_DEFAULT_HEADERS = {
26
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
27
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
28
+ "Accept-Language": "en-US,en;q=0.9",
29
+ "Accept-Encoding": "gzip, deflate, br",
30
+ "Sec-Ch-Ua": '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
31
+ "Sec-Ch-Ua-Mobile": "?0",
32
+ "Sec-Ch-Ua-Platform": '"macOS"',
33
+ "Sec-Fetch-Dest": "document",
34
+ "Sec-Fetch-Mode": "navigate",
35
+ "Sec-Fetch-Site": "none",
36
+ "Sec-Fetch-User": "?1",
37
+ "Upgrade-Insecure-Requests": "1",
38
+ };
39
+ function applyBrowserDefaults(headers) {
40
+ const seen = new Set(Object.keys(headers).map((k) => k.toLowerCase()));
41
+ const merged = { ...headers };
42
+ for (const [name, value] of Object.entries(BROWSER_DEFAULT_HEADERS)) {
43
+ if (!seen.has(name.toLowerCase()))
44
+ merged[name] = value;
45
+ }
46
+ return merged;
47
+ }
15
48
  /**
16
49
  * Create the fetch tool entry for the agent tool registry.
17
50
  */
@@ -19,7 +52,7 @@ export function createFetchToolEntry(opts = {}) {
19
52
  return {
20
53
  "web-request": {
21
54
  tool: {
22
- description: `Make an outbound HTTP request to EXTERNAL APIs, webhooks, and services only. Supports \${keys.NAME} placeholders in url, headers, and body — these are resolved server-side from the user's saved keys (the raw value never enters your context). Example: \${keys.SLACK_WEBHOOK} in the url field. IMPORTANT: Never use this to call internal /_agent-native/ endpoints or localhost action URLs — use the registered actions directly (e.g. \`log-meal\`, \`bigquery\`, \`hubspot-deals\`). Actions are already available as native tools; calling them via HTTP is slower and bypasses validation.`,
55
+ description: `Make an outbound HTTP request to any EXTERNAL URL — APIs, webhooks, and arbitrary web pages (HTML, RSS, JSON, etc.). Use this to fetch the contents of a URL the user pastes in chat. Sends realistic Chrome-on-macOS headers by default (User-Agent, Accept, Sec-Fetch-*) so most sites that block obvious bots will respond normally; pass an explicit header to override any default. Supports \${keys.NAME} placeholders in url, headers, and body — these are resolved server-side from the user's saved keys (the raw value never enters your context). Example: \${keys.SLACK_WEBHOOK} in the url field. IMPORTANT: Never use this to call internal /_agent-native/ endpoints or localhost action URLs — use the registered actions directly (e.g. \`log-meal\`, \`bigquery\`, \`hubspot-deals\`). Actions are already available as native tools; calling them via HTTP is slower and bypasses validation.`,
23
56
  parameters: {
24
57
  type: "object",
25
58
  properties: {
@@ -102,7 +135,12 @@ export function createFetchToolEntry(opts = {}) {
102
135
  return `URL validation error: ${err?.message ?? err}`;
103
136
  }
104
137
  }
105
- // Parse headers
138
+ // Parse headers, then merge in browser-like defaults for any header the
139
+ // caller didn't already specify. Real-browser headers (User-Agent,
140
+ // Accept, Sec-Fetch-*) are what gets you past Cloudflare / PerimeterX /
141
+ // generic UA-sniffing middleware on sites the user pastes in chat;
142
+ // explicit caller headers always win so API calls keep their auth
143
+ // headers untouched.
106
144
  let headers;
107
145
  try {
108
146
  headers = sanitizeOutboundHeaders(JSON.parse(resolvedHeaders));
@@ -110,6 +148,7 @@ export function createFetchToolEntry(opts = {}) {
110
148
  catch {
111
149
  return `Invalid headers JSON: ${rawHeaders}`;
112
150
  }
151
+ headers = applyBrowserDefaults(headers);
113
152
  // Make the request
114
153
  const controller = new AbortController();
115
154
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
@@ -154,9 +193,11 @@ export function createFetchToolEntry(opts = {}) {
154
193
  body = "(could not read response body)";
155
194
  }
156
195
  body = redactString(body, secretValues);
157
- // Truncate very long responses for the agent
158
- if (body.length > 8000) {
159
- body = body.slice(0, 8000) + "\n... (truncated)";
196
+ // Truncate very long responses for the agent. 32k chars (~8k tokens)
197
+ // is enough to read a full article or scrape a stats table without
198
+ // blowing out the model's context window.
199
+ if (body.length > 32_000) {
200
+ body = body.slice(0, 32_000) + "\n... (truncated)";
160
201
  }
161
202
  // Audit log
162
203
  console.log(`[fetch-tool] ${method} ${rawUrl} → ${response.status} (${elapsed}ms, keys: ${allUsedKeys.join(",") || "none"})`);
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-tool.js","sourceRoot":"","sources":["../../src/extensions/fetch-tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Fetch tool — outbound HTTP for automations and agent use.\n *\n * NOTE: this is an *agent* tool (LLM function call), not an *extension* (the\n * sandboxed Alpine.js mini-app primitive). It lives in this directory because\n * it shares SSRF-safe URL/proxy helpers with the extension iframe proxy.\n *\n * Supports ${keys.NAME} reference substitution in URL, headers, and body.\n * Values are resolved server-side AFTER the model emits the tool call —\n * the raw secret never enters the model's context.\n */\n\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport {\n collectSecretValues,\n MAX_EXTENSION_PROXY_RESPONSE_SIZE,\n normalizeExtensionProxyMethod,\n readResponseTextWithLimit,\n redactSecrets,\n redactString,\n sanitizeOutboundHeaders,\n} from \"./proxy-security.js\";\nimport { isBlockedExtensionUrlWithDns } from \"./url-safety.js\";\n\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\nexport interface FetchToolOptions {\n /** Resolve ${keys.NAME} references. Injected by the plugin at setup time. */\n resolveKeys?: (text: string) => Promise<{\n resolved: string;\n usedKeys: string[];\n secretValues?: string[];\n }>;\n /** Validate URL against per-key allowlists. */\n validateUrl?: (url: string, usedKeys: string[]) => Promise<boolean>;\n}\n\n/**\n * Create the fetch tool entry for the agent tool registry.\n */\nexport function createFetchToolEntry(\n opts: FetchToolOptions = {},\n): Record<string, ActionEntry> {\n return {\n \"web-request\": {\n tool: {\n description: `Make an outbound HTTP request to EXTERNAL APIs, webhooks, and services only. Supports \\${keys.NAME} placeholders in url, headers, and body — these are resolved server-side from the user's saved keys (the raw value never enters your context). Example: \\${keys.SLACK_WEBHOOK} in the url field. IMPORTANT: Never use this to call internal /_agent-native/ endpoints or localhost action URLs — use the registered actions directly (e.g. \\`log-meal\\`, \\`bigquery\\`, \\`hubspot-deals\\`). Actions are already available as native tools; calling them via HTTP is slower and bypasses validation.`,\n parameters: {\n type: \"object\" as const,\n properties: {\n url: {\n type: \"string\",\n description:\n 'Full URL. May contain ${keys.NAME} references, e.g. \"${keys.SLACK_WEBHOOK}\".',\n },\n method: {\n type: \"string\",\n description: \"HTTP method. Default: GET.\",\n enum: [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\"],\n },\n headers: {\n type: \"string\",\n description:\n 'JSON object of headers. May contain ${keys.NAME} references. Example: \\'{\"Authorization\": \"Bearer ${keys.API_TOKEN}\"}\\'.',\n },\n body: {\n type: \"string\",\n description:\n \"Request body (for POST/PUT/PATCH). May contain ${keys.NAME} references.\",\n },\n timeout_ms: {\n type: \"number\",\n description: `Timeout in milliseconds. Default: ${DEFAULT_TIMEOUT_MS}. Max: 30000.`,\n },\n },\n required: [\"url\"],\n },\n },\n run: async (args: Record<string, string>) => {\n const startTime = Date.now();\n const rawUrl = args.url;\n const method = normalizeExtensionProxyMethod(args.method || \"GET\");\n if (!method) {\n return \"Unsupported HTTP method. Allowed methods: GET, POST, PUT, PATCH, DELETE, HEAD.\";\n }\n const rawHeaders = args.headers || \"{}\";\n const rawBody = args.body;\n const timeoutMs = Math.min(\n Number(args.timeout_ms) || DEFAULT_TIMEOUT_MS,\n 30_000,\n );\n\n // Resolve key references\n let resolvedUrl = rawUrl;\n let resolvedHeaders = rawHeaders;\n let resolvedBody = rawBody;\n const allUsedKeys: string[] = [];\n const allSecretValues: string[] = [];\n\n if (opts.resolveKeys) {\n try {\n const urlResult = await opts.resolveKeys(rawUrl);\n resolvedUrl = urlResult.resolved;\n allUsedKeys.push(...urlResult.usedKeys);\n allSecretValues.push(...(urlResult.secretValues ?? []));\n\n const headerResult = await opts.resolveKeys(rawHeaders);\n resolvedHeaders = headerResult.resolved;\n allUsedKeys.push(...headerResult.usedKeys);\n allSecretValues.push(...(headerResult.secretValues ?? []));\n\n if (rawBody) {\n const bodyResult = await opts.resolveKeys(rawBody);\n resolvedBody = bodyResult.resolved;\n allUsedKeys.push(...bodyResult.usedKeys);\n allSecretValues.push(...(bodyResult.secretValues ?? []));\n }\n } catch (err: any) {\n return `Error resolving key references: ${err?.message ?? err}`;\n }\n }\n const secretValues = collectSecretValues(allSecretValues);\n\n // Block SSRF targets regardless of key usage\n if (await isBlockedExtensionUrlWithDns(resolvedUrl)) {\n return `Requests to private/internal addresses are not allowed: \"${rawUrl}\".`;\n }\n\n // Validate URL against per-key allowlists\n if (opts.validateUrl && allUsedKeys.length > 0) {\n try {\n const allowed = await opts.validateUrl(resolvedUrl, allUsedKeys);\n if (!allowed) {\n return `URL \"${rawUrl}\" is not in the allowlist for the referenced keys. Check your key settings.`;\n }\n } catch (err: any) {\n return `URL validation error: ${err?.message ?? err}`;\n }\n }\n\n // Parse headers\n let headers: Record<string, string>;\n try {\n headers = sanitizeOutboundHeaders(JSON.parse(resolvedHeaders));\n } catch {\n return `Invalid headers JSON: ${rawHeaders}`;\n }\n\n // Make the request\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const fetchOpts: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n redirect: \"manual\",\n };\n if (resolvedBody && [\"POST\", \"PUT\", \"PATCH\"].includes(method)) {\n fetchOpts.body = resolvedBody;\n if (!headers[\"content-type\"] && !headers[\"Content-Type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n }\n\n const response = await fetch(resolvedUrl, fetchOpts);\n const elapsed = Date.now() - startTime;\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get(\"location\");\n const redirectUrl = location\n ? new URL(location, resolvedUrl).href\n : null;\n if (\n redirectUrl &&\n (await isBlockedExtensionUrlWithDns(redirectUrl))\n ) {\n return \"Redirect to private/internal address blocked.\";\n }\n if (redirectUrl && opts.validateUrl && allUsedKeys.length > 0) {\n const allowed = await opts.validateUrl(redirectUrl, allUsedKeys);\n if (!allowed) {\n return \"Redirect URL is not in the allowlist for the referenced keys.\";\n }\n }\n return `HTTP ${response.status} ${response.statusText}\\n\\nRedirect: ${\n redirectUrl ? redactString(redirectUrl, secretValues) : \"(none)\"\n }`;\n }\n\n let body: string;\n try {\n const result = await readResponseTextWithLimit(\n response,\n MAX_EXTENSION_PROXY_RESPONSE_SIZE,\n );\n body = result.text;\n } catch {\n body = \"(could not read response body)\";\n }\n body = redactString(body, secretValues);\n\n // Truncate very long responses for the agent\n if (body.length > 8000) {\n body = body.slice(0, 8000) + \"\\n... (truncated)\";\n }\n\n // Audit log\n console.log(\n `[fetch-tool] ${method} ${rawUrl} → ${response.status} (${elapsed}ms, keys: ${allUsedKeys.join(\",\") || \"none\"})`,\n );\n\n return `HTTP ${response.status} ${response.statusText}\\n\\n${body}`;\n } catch (err: any) {\n const elapsed = Date.now() - startTime;\n if (err?.name === \"AbortError\") {\n console.log(\n `[fetch-tool] ${method} ${rawUrl} → TIMEOUT (${elapsed}ms)`,\n );\n return `Request timed out after ${timeoutMs}ms.`;\n }\n const message = redactSecrets(\n err?.message ?? String(err),\n secretValues,\n );\n console.log(\n `[fetch-tool] ${method} ${rawUrl} → ERROR: ${message} (${elapsed}ms)`,\n );\n return `Request failed: ${message}`;\n } finally {\n clearTimeout(timeout);\n }\n },\n readOnly: true,\n },\n };\n}\n"]}
1
+ {"version":3,"file":"fetch-tool.js","sourceRoot":"","sources":["../../src/extensions/fetch-tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Fetch tool — outbound HTTP for automations and agent use.\n *\n * NOTE: this is an *agent* tool (LLM function call), not an *extension* (the\n * sandboxed Alpine.js mini-app primitive). It lives in this directory because\n * it shares SSRF-safe URL/proxy helpers with the extension iframe proxy.\n *\n * Supports ${keys.NAME} reference substitution in URL, headers, and body.\n * Values are resolved server-side AFTER the model emits the tool call —\n * the raw secret never enters the model's context.\n */\n\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport {\n collectSecretValues,\n MAX_EXTENSION_PROXY_RESPONSE_SIZE,\n normalizeExtensionProxyMethod,\n readResponseTextWithLimit,\n redactSecrets,\n redactString,\n sanitizeOutboundHeaders,\n} from \"./proxy-security.js\";\nimport { isBlockedExtensionUrlWithDns } from \"./url-safety.js\";\n\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\n/**\n * Headers that mimic a current Chrome on macOS so anti-bot middleware (Cloudflare,\n * PerimeterX, Akamai) treats the request as a real user. We only fill in fields\n * the caller hasn't supplied — explicit headers (e.g. an `Authorization` header\n * for an API call) always win.\n *\n * `Accept-Encoding` deliberately omits `zstd` because Node's undici fetch only\n * decompresses `gzip`, `deflate`, and `br`. Advertising `zstd` would let some\n * servers send bytes we can't decode.\n */\nconst BROWSER_DEFAULT_HEADERS: Record<string, string> = {\n \"User-Agent\":\n \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\",\n Accept:\n \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8\",\n \"Accept-Language\": \"en-US,en;q=0.9\",\n \"Accept-Encoding\": \"gzip, deflate, br\",\n \"Sec-Ch-Ua\":\n '\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"',\n \"Sec-Ch-Ua-Mobile\": \"?0\",\n \"Sec-Ch-Ua-Platform\": '\"macOS\"',\n \"Sec-Fetch-Dest\": \"document\",\n \"Sec-Fetch-Mode\": \"navigate\",\n \"Sec-Fetch-Site\": \"none\",\n \"Sec-Fetch-User\": \"?1\",\n \"Upgrade-Insecure-Requests\": \"1\",\n};\n\nfunction applyBrowserDefaults(\n headers: Record<string, string>,\n): Record<string, string> {\n const seen = new Set(Object.keys(headers).map((k) => k.toLowerCase()));\n const merged = { ...headers };\n for (const [name, value] of Object.entries(BROWSER_DEFAULT_HEADERS)) {\n if (!seen.has(name.toLowerCase())) merged[name] = value;\n }\n return merged;\n}\n\nexport interface FetchToolOptions {\n /** Resolve ${keys.NAME} references. Injected by the plugin at setup time. */\n resolveKeys?: (text: string) => Promise<{\n resolved: string;\n usedKeys: string[];\n secretValues?: string[];\n }>;\n /** Validate URL against per-key allowlists. */\n validateUrl?: (url: string, usedKeys: string[]) => Promise<boolean>;\n}\n\n/**\n * Create the fetch tool entry for the agent tool registry.\n */\nexport function createFetchToolEntry(\n opts: FetchToolOptions = {},\n): Record<string, ActionEntry> {\n return {\n \"web-request\": {\n tool: {\n description: `Make an outbound HTTP request to any EXTERNAL URL — APIs, webhooks, and arbitrary web pages (HTML, RSS, JSON, etc.). Use this to fetch the contents of a URL the user pastes in chat. Sends realistic Chrome-on-macOS headers by default (User-Agent, Accept, Sec-Fetch-*) so most sites that block obvious bots will respond normally; pass an explicit header to override any default. Supports \\${keys.NAME} placeholders in url, headers, and body — these are resolved server-side from the user's saved keys (the raw value never enters your context). Example: \\${keys.SLACK_WEBHOOK} in the url field. IMPORTANT: Never use this to call internal /_agent-native/ endpoints or localhost action URLs — use the registered actions directly (e.g. \\`log-meal\\`, \\`bigquery\\`, \\`hubspot-deals\\`). Actions are already available as native tools; calling them via HTTP is slower and bypasses validation.`,\n parameters: {\n type: \"object\" as const,\n properties: {\n url: {\n type: \"string\",\n description:\n 'Full URL. May contain ${keys.NAME} references, e.g. \"${keys.SLACK_WEBHOOK}\".',\n },\n method: {\n type: \"string\",\n description: \"HTTP method. Default: GET.\",\n enum: [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\"],\n },\n headers: {\n type: \"string\",\n description:\n 'JSON object of headers. May contain ${keys.NAME} references. Example: \\'{\"Authorization\": \"Bearer ${keys.API_TOKEN}\"}\\'.',\n },\n body: {\n type: \"string\",\n description:\n \"Request body (for POST/PUT/PATCH). May contain ${keys.NAME} references.\",\n },\n timeout_ms: {\n type: \"number\",\n description: `Timeout in milliseconds. Default: ${DEFAULT_TIMEOUT_MS}. Max: 30000.`,\n },\n },\n required: [\"url\"],\n },\n },\n run: async (args: Record<string, string>) => {\n const startTime = Date.now();\n const rawUrl = args.url;\n const method = normalizeExtensionProxyMethod(args.method || \"GET\");\n if (!method) {\n return \"Unsupported HTTP method. Allowed methods: GET, POST, PUT, PATCH, DELETE, HEAD.\";\n }\n const rawHeaders = args.headers || \"{}\";\n const rawBody = args.body;\n const timeoutMs = Math.min(\n Number(args.timeout_ms) || DEFAULT_TIMEOUT_MS,\n 30_000,\n );\n\n // Resolve key references\n let resolvedUrl = rawUrl;\n let resolvedHeaders = rawHeaders;\n let resolvedBody = rawBody;\n const allUsedKeys: string[] = [];\n const allSecretValues: string[] = [];\n\n if (opts.resolveKeys) {\n try {\n const urlResult = await opts.resolveKeys(rawUrl);\n resolvedUrl = urlResult.resolved;\n allUsedKeys.push(...urlResult.usedKeys);\n allSecretValues.push(...(urlResult.secretValues ?? []));\n\n const headerResult = await opts.resolveKeys(rawHeaders);\n resolvedHeaders = headerResult.resolved;\n allUsedKeys.push(...headerResult.usedKeys);\n allSecretValues.push(...(headerResult.secretValues ?? []));\n\n if (rawBody) {\n const bodyResult = await opts.resolveKeys(rawBody);\n resolvedBody = bodyResult.resolved;\n allUsedKeys.push(...bodyResult.usedKeys);\n allSecretValues.push(...(bodyResult.secretValues ?? []));\n }\n } catch (err: any) {\n return `Error resolving key references: ${err?.message ?? err}`;\n }\n }\n const secretValues = collectSecretValues(allSecretValues);\n\n // Block SSRF targets regardless of key usage\n if (await isBlockedExtensionUrlWithDns(resolvedUrl)) {\n return `Requests to private/internal addresses are not allowed: \"${rawUrl}\".`;\n }\n\n // Validate URL against per-key allowlists\n if (opts.validateUrl && allUsedKeys.length > 0) {\n try {\n const allowed = await opts.validateUrl(resolvedUrl, allUsedKeys);\n if (!allowed) {\n return `URL \"${rawUrl}\" is not in the allowlist for the referenced keys. Check your key settings.`;\n }\n } catch (err: any) {\n return `URL validation error: ${err?.message ?? err}`;\n }\n }\n\n // Parse headers, then merge in browser-like defaults for any header the\n // caller didn't already specify. Real-browser headers (User-Agent,\n // Accept, Sec-Fetch-*) are what gets you past Cloudflare / PerimeterX /\n // generic UA-sniffing middleware on sites the user pastes in chat;\n // explicit caller headers always win so API calls keep their auth\n // headers untouched.\n let headers: Record<string, string>;\n try {\n headers = sanitizeOutboundHeaders(JSON.parse(resolvedHeaders));\n } catch {\n return `Invalid headers JSON: ${rawHeaders}`;\n }\n headers = applyBrowserDefaults(headers);\n\n // Make the request\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const fetchOpts: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n redirect: \"manual\",\n };\n if (resolvedBody && [\"POST\", \"PUT\", \"PATCH\"].includes(method)) {\n fetchOpts.body = resolvedBody;\n if (!headers[\"content-type\"] && !headers[\"Content-Type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n }\n\n const response = await fetch(resolvedUrl, fetchOpts);\n const elapsed = Date.now() - startTime;\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get(\"location\");\n const redirectUrl = location\n ? new URL(location, resolvedUrl).href\n : null;\n if (\n redirectUrl &&\n (await isBlockedExtensionUrlWithDns(redirectUrl))\n ) {\n return \"Redirect to private/internal address blocked.\";\n }\n if (redirectUrl && opts.validateUrl && allUsedKeys.length > 0) {\n const allowed = await opts.validateUrl(redirectUrl, allUsedKeys);\n if (!allowed) {\n return \"Redirect URL is not in the allowlist for the referenced keys.\";\n }\n }\n return `HTTP ${response.status} ${response.statusText}\\n\\nRedirect: ${\n redirectUrl ? redactString(redirectUrl, secretValues) : \"(none)\"\n }`;\n }\n\n let body: string;\n try {\n const result = await readResponseTextWithLimit(\n response,\n MAX_EXTENSION_PROXY_RESPONSE_SIZE,\n );\n body = result.text;\n } catch {\n body = \"(could not read response body)\";\n }\n body = redactString(body, secretValues);\n\n // Truncate very long responses for the agent. 32k chars (~8k tokens)\n // is enough to read a full article or scrape a stats table without\n // blowing out the model's context window.\n if (body.length > 32_000) {\n body = body.slice(0, 32_000) + \"\\n... (truncated)\";\n }\n\n // Audit log\n console.log(\n `[fetch-tool] ${method} ${rawUrl} → ${response.status} (${elapsed}ms, keys: ${allUsedKeys.join(\",\") || \"none\"})`,\n );\n\n return `HTTP ${response.status} ${response.statusText}\\n\\n${body}`;\n } catch (err: any) {\n const elapsed = Date.now() - startTime;\n if (err?.name === \"AbortError\") {\n console.log(\n `[fetch-tool] ${method} ${rawUrl} → TIMEOUT (${elapsed}ms)`,\n );\n return `Request timed out after ${timeoutMs}ms.`;\n }\n const message = redactSecrets(\n err?.message ?? String(err),\n secretValues,\n );\n console.log(\n `[fetch-tool] ${method} ${rawUrl} → ERROR: ${message} (${elapsed}ms)`,\n );\n return `Request failed: ${message}`;\n } finally {\n clearTimeout(timeout);\n }\n },\n readOnly: true,\n },\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-chat-plugin.d.ts","sourceRoot":"","sources":["../../src/server/agent-chat-plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-chat-plugin.d.ts","sourceRoot":"","sources":["../../src/server/agent-chat-plugin.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { runWithRequestContext, getRequestOrgId, getRequestUserEmail, getRequestRunContext, ensureRequestRunContext, } from "./request-context.js";
2
2
  import { getSetting, putSetting } from "../settings/store.js";
3
3
  import { getH3App, markDefaultPluginProvided, trackPluginInit, } from "./framework-request-handler.js";
4
- import { createProductionAgentHandler, runAgentLoop, actionsToEngineTools, getActiveRunForThreadAsync, abortRun, subscribeToRun, appendAgentLoopContinuation, } from "../agent/production-agent.js";
4
+ import { createProductionAgentHandler, runAgentLoop, actionsToEngineTools, getActiveRunForThreadAsync, abortRun, subscribeToRun, appendAgentLoopContinuation, isResumableEngineError, continuationReasonForResumableError, } from "../agent/production-agent.js";
5
5
  import { resolveRunSoftTimeoutMs } from "../agent/run-manager.js";
6
6
  import { resolveEngine, createAnthropicEngine, getStoredModelForEngine, } from "../agent/engine/index.js";
7
7
  import { DEFAULT_ANTHROPIC_MODEL } from "../agent/default-model.js";
@@ -77,6 +77,18 @@ function resolveArtifactBaseUrl(event) {
77
77
  catch { }
78
78
  return undefined;
79
79
  }
80
+ /**
81
+ * Cap on continuation iterations inside a single runAgentLoopDirectWithSoftTimeout
82
+ * invocation. Each iteration runs a fresh LLM call after the previous one was
83
+ * cut off (soft timeout, gateway timeout, network blip). The host's hard
84
+ * function timeout (e.g., Lambda's 75s) usually bounds this naturally — but
85
+ * a defensive cap prevents an instant-error spiral from looping forever
86
+ * inside a hosting environment with a generous budget.
87
+ *
88
+ * 6 leaves room for: 1 normal completion + a few resume rounds for design
89
+ * generation (prompt + 3 variants ≈ 4 LLM calls), with a small safety margin.
90
+ */
91
+ const MAX_RUN_LOOP_CONTINUATIONS = 6;
80
92
  async function runAgentLoopDirectWithSoftTimeout(opts, softTimeoutMs) {
81
93
  const timeoutMs = resolveRunSoftTimeoutMs(softTimeoutMs);
82
94
  if (timeoutMs <= 0)
@@ -96,7 +108,9 @@ async function runAgentLoopDirectWithSoftTimeout(opts, softTimeoutMs) {
96
108
  usage.cacheWriteTokens += next.cacheWriteTokens;
97
109
  usage.model = next.model;
98
110
  };
99
- while (!upstreamSignal.aborted) {
111
+ let attempts = 0;
112
+ while (!upstreamSignal.aborted && attempts < MAX_RUN_LOOP_CONTINUATIONS) {
113
+ attempts++;
100
114
  const controller = new AbortController();
101
115
  const abortFromUpstream = () => controller.abort();
102
116
  if (upstreamSignal.aborted) {
@@ -131,6 +145,17 @@ async function runAgentLoopDirectWithSoftTimeout(opts, softTimeoutMs) {
131
145
  appendAgentLoopContinuation(opts.messages, "run_timeout");
132
146
  continue;
133
147
  }
148
+ // Resumable transport / gateway interruptions: the LLM call was cut off
149
+ // mid-stream (gateway 45s timeout, socket hang up, function-level
150
+ // timeout that didn't trip our soft timer first). Treat it the same
151
+ // way as a soft timeout — append a "continue from where you left off"
152
+ // nudge and let the loop run another LLM call. The conversation prefix
153
+ // up to the cut-off is preserved in opts.messages, and Anthropic's
154
+ // prompt cache makes the resume call much faster.
155
+ if (!upstreamSignal.aborted && isResumableEngineError(err)) {
156
+ appendAgentLoopContinuation(opts.messages, continuationReasonForResumableError(err));
157
+ continue;
158
+ }
134
159
  throw err;
135
160
  }
136
161
  finally {
@@ -1148,7 +1173,19 @@ Convert natural language to 5-field cron format:
1148
1173
  - "every morning" / "daily at 9am" → \`0 9 * * *\`
1149
1174
  - "every weekday at 9am" → \`0 9 * * 1-5\`
1150
1175
  - "every hour" → \`0 * * * *\`
1151
- - "every monday at 9am" → \`0 9 * * 1\``,
1176
+ - "every monday at 9am" → \`0 9 * * 1\`
1177
+
1178
+ #### Suggesting "Save as automation"
1179
+
1180
+ When you finish a task that has obvious recurring value — daily inbox triage, weekly metrics summaries, archive sweeps, status digests, anything the user would plausibly want re-run on a fresh cadence — close the response with ONE short line offering to save it. Examples:
1181
+
1182
+ - After "Summarize my unread emails": _"Want me to run this every morning?"_
1183
+ - After "What's our top traffic source this week": _"Want a weekly digest on Mondays?"_
1184
+ - After "Archive emails older than 30 days": _"Should I run this every Sunday?"_
1185
+
1186
+ If the user says yes, call \`manage-jobs\` (action: "create") with the original prompt as the job's instructions and the cadence they confirmed.
1187
+
1188
+ Do NOT add this offer for one-shot work: lookups (find Alice, what's the schema, who reported X), single drafts/replies, navigation requests, or any task whose value is in the moment. Skip it when the prompt is already explicitly recurring (the user said "every morning…" — you'd be asking what they already told you). One short sentence at most; do not turn it into a list of cadence options.`,
1152
1189
  builder: `### Connecting Builder.io
1153
1190
 
1154
1191
  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.`,
@@ -1342,6 +1379,12 @@ When the user asks for something recurring ("every morning", "daily at 9am", "we
1342
1379
 
1343
1380
  Job instructions should be self-contained — include which actions to call, what conditions to check, and what to do with results. The agent executing the job has access to all the same tools you do.
1344
1381
 
1382
+ #### Offering "Save as automation"
1383
+
1384
+ After completing a task with obvious recurring value (daily triage, weekly digests, archive sweeps, status summaries, anything the user would plausibly re-run on a fresh cadence), close the reply with ONE short line offering to save it: _"Want me to run this every morning?"_, _"Want a weekly digest on Mondays?"_, _"Should I run this every Sunday?"_. If they say yes, call \`manage-jobs\` (action: "create") with the original prompt as the job instructions and the cadence they picked.
1385
+
1386
+ Skip this offer for one-shot work — single lookups (find X, who is Y), one-off drafts/replies, navigation, anything whose value is in the moment. Also skip it when the prompt was already explicitly recurring (the user said "every morning…"; offering again would just be asking what they already told you). Keep it to one sentence; do not enumerate cadence options.
1387
+
1345
1388
  ### Connecting Builder.io
1346
1389
 
1347
1390
  When the user asks to connect Builder.io, needs Builder for LLM access / browser automation, or you hit a "Builder not configured" error, call the \`connect-builder\` tool. It renders a one-click Connect card inline in the chat — do NOT write out multi-step setup instructions yourself (no "Option 1 / Option 2", no terminal commands). Just call the tool and let the card handle the rest.
@@ -1421,14 +1464,33 @@ Note: "extension" is the user-facing primitive (the sandboxed Alpine.js mini-app
1421
1464
 
1422
1465
  For existing extensions, use \`list-extensions\` to find what the user can see, then \`update-extension\`, \`hide-extension\`, or \`delete-extension\` as appropriate. If the user wants a shared extension removed only from their view, use \`hide-extension\` — do not query or mutate the legacy \`tools\` table directly.
1423
1466
 
1467
+ ### Extensions vs. Code Changes — Pick the Right Path
1468
+
1469
+ Before routing anything to \`connect-builder\`, check whether the request is genuinely a **new self-contained thing** the user wants — a custom widget, dashboard, calculator, viewer, list, or any standalone interactive surface. If yes, an extension can deliver it without a code change. Examples that should go to \`create-extension\`, not \`connect-builder\`:
1470
+
1471
+ - "Build me a widget that shows my unread emails grouped by sender"
1472
+ - "Make a dashboard that summarizes my pipeline"
1473
+ - "Give me a tool that reviews my drafts against a checklist"
1474
+ - "Create a tracker for my newsletter subscriptions"
1475
+
1476
+ Use \`connect-builder\` (a real source-code change) when the request **modifies the host app's existing chrome** — its nav bar, sidebar, current components, layout, styles, routes, or behavior in shipped UI. Extensions render in their own sandboxed iframe and CANNOT change the host app's nav, restyle existing components, or replace built-in views. Examples that genuinely need \`connect-builder\`:
1477
+
1478
+ - "Add an Unread tab to the left navigation"
1479
+ - "Make the email subject lines wrap"
1480
+ - "Change the inbox grouping logic"
1481
+ - "Add a new field to the compose form"
1482
+
1483
+ If the user's request could be satisfied either way (e.g. "give me an unread view"), prefer \`create-extension\` — it ships instantly and doesn't require a PR.
1484
+
1424
1485
  ### Code Changes Not Available — Call \`connect-builder\` Immediately
1425
1486
 
1426
- If the request matches the Extensions section above (extension / widget / dashboard / calculator / mini-app), use \`create-extension\` or \`update-extension\` instead — do NOT route it to \`connect-builder\`.
1487
+ If the request matches the Extensions section above, use \`create-extension\` or \`update-extension\` instead — do NOT route it to \`connect-builder\`.
1427
1488
 
1428
1489
  In Act mode, when the user asks you to change the UI, modify code, add a feature, fix a bug in the app itself, change styles, add a hook, create a component, add a route, add an integration, or anything else that requires editing source files — you MUST take exactly these steps, in order:
1429
1490
 
1430
- 1. Call the \`connect-builder\` tool, passing the user's full request verbatim as the \`prompt\` argument. This renders an inline card. If Builder is connected and \`builderEnabled\` is true, the card hands the prompt off to Builder's cloud agent on one click and returns a branch URL. If Builder is not connected, it shows the Connect Builder flow. If \`builderEnabled\` is false, it shows a waitlist/local-dev fallback instead of a cloud handoff.
1431
- 2. After the card renders, inspect the tool result. If \`builderEnabled\` is false, write one short sentence saying Builder Cloud Agents are not available for this workspace yet, they can still do the code change locally, and if they are running on localhost in a browser they can use the Agent Native Desktop app: https://www.agent-native.com/download. Do NOT say the card is pre-loaded, has everything, or that they should click Send to Builder. If \`builderEnabled\` is true and Builder is connected, tell them to click Send to Builder. If \`builderEnabled\` is true and Builder is not connected, tell them to click Connect Builder.
1491
+ 1. Briefly acknowledge the user's specific request in their own terms one short clause naming what they asked for (e.g. "Got it wider subject lines in the email list."). Do NOT restate the request verbatim, do NOT add a generic preamble, and do NOT promise outcomes. Skip this step entirely if the user already knows you're handing off (e.g. they said "send this to Builder").
1492
+ 2. Call the \`connect-builder\` tool, passing the user's full request verbatim as the \`prompt\` argument. This renders an inline card. If Builder is connected and \`builderEnabled\` is true, the card hands the prompt off to Builder's cloud agent on one click and returns a branch URL. If Builder is not connected, it shows the Connect Builder flow. If \`builderEnabled\` is false, it shows a waitlist/local-dev fallback instead of a cloud handoff.
1493
+ 3. After the card renders, inspect the tool result and write one sentence that frames the next click around what the user just asked — not as a Builder pitch. Examples: "Click Send to Builder and it'll wire that up for you." / "Connect Builder once and it'll handle this and future changes." / "Builder Cloud Agents aren't enabled here yet — you can still do this locally, and the Agent Native Desktop app handles it: https://www.agent-native.com/download." Do NOT say the card is pre-loaded, has everything, or lead with "Builder Cloud Agents are…" as if it were the headline.
1432
1494
 
1433
1495
  **Act-mode hard rules — do NOT break these:**
1434
1496
  - 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.
@@ -1484,9 +1546,13 @@ If the user asks to change, edit, fix, style, rename, or add behavior to an exis
1484
1546
 
1485
1547
  For existing extensions, use \`list-extensions\`, \`update-extension\`, \`hide-extension\`, and \`delete-extension\`. Use \`hide-extension\` when the user wants a shared extension removed only from their own view. Do not query the legacy \`tools\` table directly.
1486
1548
 
1549
+ ### Extensions vs. Code Changes — Pick the Right Path
1550
+
1551
+ If the user wants a **new self-contained surface** (custom widget, dashboard, list, viewer, calculator), use \`create-extension\` — extensions ship instantly without a PR. Use \`connect-builder\` only when the request **modifies the host app's existing chrome** (nav bar, sidebar, current components, layout, styles, routes). Extensions cannot change the host nav or restyle existing components.
1552
+
1487
1553
  ### Code Changes — Call \`connect-builder\`
1488
1554
 
1489
- In Act mode, 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\`. (Extension / widget / dashboard requests use \`create-extension\` or \`update-extension\` instead see above.) 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.
1555
+ In Act mode, when a request genuinely needs a source-code edit (per the rules above), do this in order: (1) briefly acknowledge the user's specific ask in their own termsone short clause, no preamble — then (2) call \`connect-builder\` with the user's request as the \`prompt\`, then (3) write one sentence framing the next click around what they asked for, not a Builder pitch. Do NOT write code, list files, make plans, or spawn sub-agents. Mention \`npx agent-native create <app-name>\` as an offline fallback when Builder Cloud Agents aren't available.
1490
1556
  ${FRAMEWORK_CORE_COMPACT}`;
1491
1557
  const DEV_FRAMEWORK_PROMPT_COMPACT = `## Agent-Native Framework — Development Mode
1492
1558