@agent-native/core 0.154.5 → 0.157.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 (263) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/account-health/SKILL.md +76 -0
  3. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
  4. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
  5. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
  6. package/corpus/templates/analytics/AGENTS.md +3 -0
  7. package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
  8. package/corpus/templates/analytics/actions/bigquery.ts +1 -1
  9. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
  10. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  11. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
  12. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
  13. package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
  14. package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
  15. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
  16. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
  17. package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
  18. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
  19. package/corpus/templates/assets/app/i18n-data.ts +21 -1
  20. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
  21. package/corpus/templates/calendar/AGENTS.md +2 -0
  22. package/corpus/templates/calendar/DEVELOPING.md +4 -4
  23. package/corpus/templates/calendar/actions/get-settings.ts +4 -11
  24. package/corpus/templates/calendar/actions/update-availability.ts +15 -4
  25. package/corpus/templates/calendar/actions/update-settings.ts +15 -4
  26. package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
  27. package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
  28. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
  29. package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
  30. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
  31. package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
  32. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
  33. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
  34. package/corpus/templates/calendar/app/i18n-data.ts +30 -0
  35. package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
  36. package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
  37. package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
  38. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
  39. package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
  40. package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
  41. package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
  42. package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
  43. package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
  44. package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
  45. package/corpus/templates/calendar/shared/api.ts +1 -0
  46. package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
  47. package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
  48. package/corpus/templates/calendar/shared/settings.ts +44 -0
  49. package/corpus/templates/clips/AGENTS.md +2 -0
  50. package/corpus/templates/clips/actions/add-comment.ts +5 -2
  51. package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
  52. package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
  53. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
  54. package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
  55. package/corpus/templates/clips/actions/update-comment.ts +9 -2
  56. package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
  57. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
  58. package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
  59. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
  60. package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
  61. package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
  62. package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
  63. package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
  64. package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
  65. package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
  66. package/corpus/templates/clips/app/root.tsx +2 -1
  67. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
  68. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
  69. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
  70. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +29 -8
  71. package/corpus/templates/clips/app/routes/share.$shareId.tsx +24 -6
  72. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
  73. package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
  74. package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
  75. package/corpus/templates/clips/desktop/src/app.tsx +116 -19
  76. package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
  77. package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
  78. package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
  79. package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
  80. package/corpus/templates/clips/desktop/src/styles.css +117 -0
  81. package/corpus/templates/clips/server/db/index.ts +10 -0
  82. package/corpus/templates/clips/server/db/schema.ts +1 -0
  83. package/corpus/templates/clips/server/lib/recordings.ts +3 -1
  84. package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
  85. package/corpus/templates/clips/server/plugins/db.ts +5 -0
  86. package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
  87. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
  88. package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
  89. package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
  90. package/corpus/templates/content/actions/add-comment.ts +2 -1
  91. package/corpus/templates/content/actions/update-comment.ts +1 -1
  92. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
  93. package/corpus/templates/design/actions/generate-design.ts +10 -7
  94. package/corpus/templates/design/actions/present-design-variants.ts +35 -6
  95. package/corpus/templates/design/actions/run-design-audit.ts +33 -0
  96. package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
  97. package/corpus/templates/design/shared/design-review.ts +1 -0
  98. package/corpus/templates/design/shared/html-integrity.ts +66 -0
  99. package/corpus/templates/dispatch/.env.example +5 -0
  100. package/corpus/templates/dispatch/AGENTS.md +24 -19
  101. package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
  102. package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
  103. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
  104. package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
  105. package/corpus/templates/factory/AGENTS.md +5 -1
  106. package/corpus/templates/factory/README.md +23 -0
  107. package/corpus/templates/factory/actions/view-screen.ts +17 -0
  108. package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
  109. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
  110. package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
  111. package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
  112. package/corpus/templates/factory/app/routes/factory.tsx +41 -0
  113. package/corpus/templates/factory/package.json +1 -0
  114. package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
  115. package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
  116. package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
  117. package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
  118. package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
  119. package/corpus/templates/mail/vite.config.ts +7 -0
  120. package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
  121. package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
  122. package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
  123. package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
  124. package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
  125. package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
  126. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
  127. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
  128. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
  129. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
  130. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
  131. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
  132. package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
  133. package/corpus/templates/slides/app/global.css +7 -40
  134. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  135. package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
  136. package/dist/agent/index.d.ts +1 -1
  137. package/dist/agent/production-agent.d.ts +30 -0
  138. package/dist/agent/production-agent.js +105 -9
  139. package/dist/agent/thread-data-builder.js +17 -1
  140. package/dist/agent/types.d.ts +9 -0
  141. package/dist/cli/skills-content/help.js +6 -4
  142. package/dist/cli/skills.js +17 -2
  143. package/dist/cli/workspacify.d.ts +5 -0
  144. package/dist/cli/workspacify.js +65 -8
  145. package/dist/client/AgentPanel.d.ts +5 -0
  146. package/dist/client/AgentPanel.js +32 -13
  147. package/dist/client/AssistantChat.d.ts +36 -1
  148. package/dist/client/AssistantChat.js +175 -110
  149. package/dist/client/MultiTabAssistantChat.js +44 -27
  150. package/dist/client/active-run-state.d.ts +14 -1
  151. package/dist/client/active-run-state.js +0 -0
  152. package/dist/client/agent-chat-adapter.js +107 -5
  153. package/dist/client/analytics.js +9 -2
  154. package/dist/client/chat/markdown-renderer.js +4 -2
  155. package/dist/client/chat/message-components.d.ts +2 -2
  156. package/dist/client/chat/message-components.js +69 -35
  157. package/dist/client/chat/run-recovery.d.ts +4 -1
  158. package/dist/client/chat/run-recovery.js +62 -30
  159. package/dist/client/chat/tool-call-display.d.ts +12 -3
  160. package/dist/client/chat/tool-call-display.js +79 -40
  161. package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
  162. package/dist/client/chat/widgets/DataChartWidget.js +8 -2
  163. package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
  164. package/dist/client/chat/widgets/DataTableWidget.js +23 -9
  165. package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
  166. package/dist/client/chat-first/apps-rail.js +9 -4
  167. package/dist/client/chat-first/primary-nav.d.ts +2 -1
  168. package/dist/client/chat-first/primary-nav.js +3 -3
  169. package/dist/client/chat-first/types.d.ts +5 -1
  170. package/dist/client/components/ui/message-scroller.d.ts +1 -1
  171. package/dist/client/components/ui/message-scroller.js +7 -3
  172. package/dist/client/composer/runtime-adapters.js +3 -2
  173. package/dist/client/context-xray/ContextMeter.js +5 -1
  174. package/dist/client/context-xray/ContextXRayPanel.js +5 -5
  175. package/dist/client/error-format.d.ts +4 -0
  176. package/dist/client/error-format.js +93 -5
  177. package/dist/client/i18n.js +83 -17
  178. package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
  179. package/dist/client/markdown/InlineMarkdown.js +65 -0
  180. package/dist/client/markdown/index.d.ts +1 -0
  181. package/dist/client/markdown/index.js +1 -0
  182. package/dist/client/observability/ThumbsFeedback.js +10 -8
  183. package/dist/client/review/ReviewThreadPanel.js +2 -1
  184. package/dist/client/run-stream-ownership.d.ts +39 -0
  185. package/dist/client/run-stream-ownership.js +65 -0
  186. package/dist/client/sharing/ShareButton.js +160 -54
  187. package/dist/coding-tools/run-code.js +2 -1
  188. package/dist/coding-tools/sandbox/background.d.ts +1 -0
  189. package/dist/coding-tools/sandbox/background.js +8 -1
  190. package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
  191. package/dist/coding-tools/sandbox/executions-store.js +41 -3
  192. package/dist/collab/awareness.d.ts +2 -2
  193. package/dist/collab/routes.d.ts +1 -1
  194. package/dist/collab/struct-routes.d.ts +1 -1
  195. package/dist/feature-flags/index.d.ts +1 -1
  196. package/dist/feature-flags/index.js +1 -1
  197. package/dist/feature-flags/store.d.ts +10 -0
  198. package/dist/feature-flags/store.js +112 -1
  199. package/dist/guards/no-env-credentials.js +4 -0
  200. package/dist/index.d.ts +2 -2
  201. package/dist/index.js +1 -1
  202. package/dist/integrations/adapters/slack.js +5 -1
  203. package/dist/localization/core-messages/ar-SA.d.ts +3 -0
  204. package/dist/localization/core-messages/ar-SA.js +541 -0
  205. package/dist/localization/core-messages/de-DE.d.ts +3 -0
  206. package/dist/localization/core-messages/de-DE.js +513 -0
  207. package/dist/localization/core-messages/en-US.d.ts +513 -0
  208. package/dist/localization/core-messages/en-US.js +513 -0
  209. package/dist/localization/core-messages/es-ES.d.ts +3 -0
  210. package/dist/localization/core-messages/es-ES.js +520 -0
  211. package/dist/localization/core-messages/fr-FR.d.ts +3 -0
  212. package/dist/localization/core-messages/fr-FR.js +520 -0
  213. package/dist/localization/core-messages/hi-IN.d.ts +3 -0
  214. package/dist/localization/core-messages/hi-IN.js +513 -0
  215. package/dist/localization/core-messages/ja-JP.d.ts +3 -0
  216. package/dist/localization/core-messages/ja-JP.js +506 -0
  217. package/dist/localization/core-messages/ko-KR.d.ts +3 -0
  218. package/dist/localization/core-messages/ko-KR.js +506 -0
  219. package/dist/localization/core-messages/pt-BR.d.ts +3 -0
  220. package/dist/localization/core-messages/pt-BR.js +520 -0
  221. package/dist/localization/core-messages/zh-CN.d.ts +3 -0
  222. package/dist/localization/core-messages/zh-CN.js +506 -0
  223. package/dist/localization/core-messages/zh-TW.d.ts +3 -0
  224. package/dist/localization/core-messages/zh-TW.js +506 -0
  225. package/dist/localization/core-messages.d.ts +524 -0
  226. package/dist/localization/core-messages.js +124 -0
  227. package/dist/localization/default-messages.d.ts +3 -0
  228. package/dist/localization/default-messages.js +3 -0
  229. package/dist/notifications/routes.d.ts +1 -1
  230. package/dist/observability/routes.d.ts +2 -2
  231. package/dist/progress/routes.d.ts +1 -1
  232. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  233. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  234. package/dist/resources/agents.js +40 -5
  235. package/dist/resources/metadata.d.ts +10 -0
  236. package/dist/resources/metadata.js +7 -3
  237. package/dist/review/actions/create-review-comment.js +1 -1
  238. package/dist/review/actions/reply-review-comment.js +1 -1
  239. package/dist/review/actions/resolve-review-thread.js +1 -1
  240. package/dist/secrets/routes.d.ts +6 -6
  241. package/dist/server/action-routes.js +32 -6
  242. package/dist/server/agent-chat/plugin-options.d.ts +7 -2
  243. package/dist/server/agent-chat-plugin.d.ts +10 -0
  244. package/dist/server/agent-chat-plugin.js +144 -41
  245. package/dist/server/agent-discovery.js +14 -3
  246. package/dist/server/agent-run-context.d.ts +7 -1
  247. package/dist/server/agent-run-context.js +9 -2
  248. package/dist/server/agent-teams-run-queue.d.ts +3 -0
  249. package/dist/server/agent-teams.js +38 -9
  250. package/dist/server/core-routes-plugin.js +1 -1
  251. package/dist/server/identity-sso-migrations.d.ts +7 -0
  252. package/dist/server/identity-sso-migrations.js +36 -0
  253. package/dist/server/identity-sso-store.d.ts +3 -2
  254. package/dist/server/identity-sso-store.js +8 -3
  255. package/dist/server/index.d.ts +1 -1
  256. package/dist/server/realtime-token.d.ts +1 -1
  257. package/dist/server/release-migrations.js +4 -0
  258. package/dist/server/request-context.d.ts +7 -0
  259. package/dist/server/request-context.js +15 -0
  260. package/dist/tracking/providers.js +13 -3
  261. package/dist/workspace-files/tool.js +1 -1
  262. package/docs/content/agent-surfaces.mdx +30 -0
  263. package/package.json +3 -2
@@ -1,3 +1,4 @@
1
+ import { useActionQuery } from "@agent-native/core/client/hooks";
1
2
  import { useT } from "@agent-native/core/client/i18n";
2
3
  import { IconArrowRight, IconPlus, IconTrash } from "@tabler/icons-react";
3
4
  import { useMemo, useState } from "react";
@@ -28,6 +29,24 @@ interface FactoryInspectorProps {
28
29
  onConnect: (sourceId: string, targetId: string) => void;
29
30
  }
30
31
 
32
+ interface WorkspaceAgentOption {
33
+ id: string;
34
+ name: string;
35
+ }
36
+
37
+ interface WorkspaceAppOption {
38
+ id: string;
39
+ name: string;
40
+ description?: string;
41
+ status?: "ready" | "pending";
42
+ }
43
+
44
+ interface AgentTargetOption {
45
+ id: string;
46
+ label: string;
47
+ type: "agent" | "app";
48
+ }
49
+
31
50
  export function FactoryInspector({
32
51
  graph,
33
52
  selectedNode,
@@ -44,6 +63,28 @@ export function FactoryInspector({
44
63
  const t = useT();
45
64
  const [searchParams] = useSearchParams();
46
65
  const [connectTarget, setConnectTarget] = useState("");
66
+ const agentsQuery = useActionQuery<WorkspaceAgentOption[]>(
67
+ "list-workspace-resources",
68
+ { kind: "agent" },
69
+ );
70
+ const appsQuery = useActionQuery<WorkspaceAppOption[]>(
71
+ "list-workspace-apps",
72
+ { includeAgentCards: false },
73
+ );
74
+ const agentTargets: AgentTargetOption[] = [
75
+ ...(agentsQuery.data ?? []).map((agent) => ({
76
+ id: agent.id,
77
+ label: agent.name,
78
+ type: "agent" as const,
79
+ })),
80
+ ...(appsQuery.data ?? [])
81
+ .filter((app) => app.id !== "dispatch" && app.status !== "pending")
82
+ .map((app) => ({
83
+ id: app.id,
84
+ label: app.name,
85
+ type: "app" as const,
86
+ })),
87
+ ];
47
88
  const outgoingTargets = graph.nodes.filter(
48
89
  (node) => node.id !== selectedNode?.id,
49
90
  );
@@ -84,6 +125,44 @@ export function FactoryInspector({
84
125
  });
85
126
  }
86
127
 
128
+ function selectedTargetValue() {
129
+ if (!selectedNode?.agentTargetType || !selectedNode.agentTargetId) {
130
+ return selectedNode?.agent ? "custom" : "";
131
+ }
132
+ return `${selectedNode.agentTargetType}:${selectedNode.agentTargetId}`;
133
+ }
134
+
135
+ function updateAgentTarget(value: string) {
136
+ if (!selectedNode) return;
137
+ if (value === "") {
138
+ updateNode({
139
+ agent: undefined,
140
+ agentTargetType: undefined,
141
+ agentTargetId: undefined,
142
+ });
143
+ return;
144
+ }
145
+ if (value === "custom") {
146
+ updateNode({
147
+ agentTargetType: undefined,
148
+ agentTargetId: undefined,
149
+ });
150
+ return;
151
+ }
152
+ const [type, ...idParts] = value.split(":");
153
+ const id = idParts.join(":");
154
+ if ((type !== "agent" && type !== "app") || !id) return;
155
+ const target = agentTargets.find(
156
+ (option) => option.type === type && option.id === id,
157
+ );
158
+ if (!target) return;
159
+ updateNode({
160
+ agent: target.label,
161
+ agentTargetType: target.type,
162
+ agentTargetId: target.id,
163
+ });
164
+ }
165
+
87
166
  return (
88
167
  <aside className="flex min-h-0 flex-col rounded-xl bg-card shadow-sm">
89
168
  <div className="min-h-0 flex-1 space-y-5 overflow-y-auto p-4">
@@ -141,15 +220,59 @@ export function FactoryInspector({
141
220
  </select>
142
221
  </div>
143
222
  <div className="grid gap-1.5">
144
- <Label htmlFor="factory-node-agent">
223
+ <Label htmlFor="factory-node-agent-target">
145
224
  {t("factoryInspector.agentOwner")}
146
225
  </Label>
147
- <Input
148
- id="factory-node-agent"
149
- value={selectedNode.agent ?? ""}
150
- onChange={(event) => updateNode({ agent: event.target.value })}
151
- placeholder={t("factoryInspector.optional")}
152
- />
226
+ <select
227
+ id="factory-node-agent-target"
228
+ value={selectedTargetValue()}
229
+ onChange={(event) => updateAgentTarget(event.target.value)}
230
+ className="h-9 rounded-md border bg-card px-3 text-sm"
231
+ >
232
+ <option value="">{t("factoryInspector.noTarget")}</option>
233
+ <option value="custom">
234
+ {selectedNode.agent &&
235
+ !selectedNode.agentTargetType &&
236
+ !selectedNode.agentTargetId
237
+ ? `${t("factoryInspector.customTarget")}: ${selectedNode.agent}`
238
+ : t("factoryInspector.customTarget")}
239
+ </option>
240
+ {agentTargets.some((target) => target.type === "agent") ? (
241
+ <optgroup label={t("factoryInspector.reusableAgents")}>
242
+ {agentTargets
243
+ .filter((target) => target.type === "agent")
244
+ .map((target) => (
245
+ <option
246
+ key={`${target.type}:${target.id}`}
247
+ value={`${target.type}:${target.id}`}
248
+ >
249
+ {target.label}
250
+ </option>
251
+ ))}
252
+ </optgroup>
253
+ ) : null}
254
+ {agentTargets.some((target) => target.type === "app") ? (
255
+ <optgroup label={t("factoryInspector.agenticApps")}>
256
+ {agentTargets
257
+ .filter((target) => target.type === "app")
258
+ .map((target) => (
259
+ <option
260
+ key={`${target.type}:${target.id}`}
261
+ value={`${target.type}:${target.id}`}
262
+ >
263
+ {target.label}
264
+ </option>
265
+ ))}
266
+ </optgroup>
267
+ ) : null}
268
+ </select>
269
+ <p className="text-xs text-muted-foreground">
270
+ {selectedNode.agentTargetType === "app"
271
+ ? t("factoryInspector.appTargetHint")
272
+ : selectedNode.agentTargetType === "agent"
273
+ ? t("factoryInspector.agentTargetHint")
274
+ : t("factoryInspector.customTargetHint")}
275
+ </p>
153
276
  </div>
154
277
  <div className="rounded-lg bg-muted/25 p-3 shadow-sm">
155
278
  <p className="text-xs font-medium">
@@ -162,6 +162,19 @@ const messages = {
162
162
  metricRuns: "Runs",
163
163
  rulesTab: "Rules",
164
164
  automationsTab: "Automations",
165
+ agentsTab: "Agents",
166
+ agenticAppsTitle: "Agentic apps",
167
+ agenticAppsEmpty: "No agentic apps in this workspace yet.",
168
+ editAppDetails: "Edit app details",
169
+ editAppDetailsDescription:
170
+ "Update the shared display name and description for this workspace app.",
171
+ appName: "Name",
172
+ appDescription: "Description",
173
+ openApp: "Open app",
174
+ saveChanges: "Save changes",
175
+ appDetailsUpdated: "App details updated",
176
+ savingChanges: "Saving...",
177
+ agentsTitle: "Agents",
165
178
  auditTab: "Audit",
166
179
  auditTitle: "Run audit",
167
180
  auditDescription:
@@ -268,6 +281,13 @@ const messages = {
268
281
  stepName: "Step name",
269
282
  stepDescription: "What happens here",
270
283
  agentOwner: "Agent or owner",
284
+ noTarget: "No linked target",
285
+ customTarget: "Custom target",
286
+ reusableAgents: "Reusable agents",
287
+ agenticApps: "Agentic apps",
288
+ agentTargetHint: "This factory step uses the selected reusable agent.",
289
+ appTargetHint: "This factory step delegates to the selected agentic app.",
290
+ customTargetHint: "Link a shared agent or app when this step is ready.",
271
291
  optional: "Optional",
272
292
  connectStep: "Connect this step",
273
293
  connectDescription:
@@ -21,6 +21,7 @@ import {
21
21
  import { useEffect, useMemo, useState } from "react";
22
22
  import { Link, useSearchParams } from "react-router";
23
23
 
24
+ import { FactoryAgentsView } from "@/components/factory/FactoryAgentsView";
24
25
  import { FactoryAuditView } from "@/components/factory/FactoryAuditView";
25
26
  import {
26
27
  FactoryCanvas,
@@ -123,6 +124,7 @@ type WorkspaceTab =
123
124
  | "inbox"
124
125
  | "rules"
125
126
  | "automations"
127
+ | "agents"
126
128
  | "audit"
127
129
  | "settings";
128
130
 
@@ -404,6 +406,28 @@ export default function FactoryRoute() {
404
406
  await Promise.all([graphQuery.refetch(), factoryListQuery.refetch()]);
405
407
  }
406
408
 
409
+ if (!selectedFactoryId && activeTab === "agents") {
410
+ return (
411
+ <div className="flex h-full min-h-0 flex-col overflow-y-auto bg-background">
412
+ <div className="flex items-center gap-3 px-4 py-4 lg:px-6">
413
+ <Button
414
+ type="button"
415
+ variant="ghost"
416
+ size="icon"
417
+ aria-label={t("factoryRoute.backToFactories")}
418
+ onClick={() => setActiveTab("overview")}
419
+ >
420
+ <IconArrowLeft className="size-4" />
421
+ </Button>
422
+ <h1 className="text-sm font-medium sm:text-base">
423
+ {t("factoryRoute.agentsTitle")}
424
+ </h1>
425
+ </div>
426
+ <FactoryAgentsView />
427
+ </div>
428
+ );
429
+ }
430
+
407
431
  if (!selectedFactoryId) {
408
432
  return (
409
433
  <div className="flex h-full min-h-0 flex-col overflow-y-auto bg-background">
@@ -411,6 +435,14 @@ export default function FactoryRoute() {
411
435
  <div className="flex flex-wrap items-end justify-between gap-4">
412
436
  <h1 className="text-2xl font-semibold tracking-tight">Factories</h1>
413
437
  <div className="flex items-center gap-2">
438
+ <Button
439
+ type="button"
440
+ variant="outline"
441
+ size="sm"
442
+ onClick={() => setActiveTab("agents")}
443
+ >
444
+ {t("factoryRoute.agentsTab")}
445
+ </Button>
414
446
  <Button type="button" size="sm" onClick={startNewFactory}>
415
447
  <IconPlus className="size-4" />
416
448
  {t("factoryRoute.newFactory")}
@@ -609,6 +641,12 @@ export default function FactoryRoute() {
609
641
  >
610
642
  {t("factoryRoute.automationsTab")}
611
643
  </TabButton>
644
+ <TabButton
645
+ active={activeTab === "agents"}
646
+ onClick={() => setActiveTab("agents")}
647
+ >
648
+ {t("factoryRoute.agentsTab")}
649
+ </TabButton>
612
650
  <TabButton
613
651
  active={activeTab === "audit"}
614
652
  onClick={() => setActiveTab("audit")}
@@ -696,6 +734,8 @@ export default function FactoryRoute() {
696
734
  <RulesView t={t} />
697
735
  ) : activeTab === "automations" ? (
698
736
  <AutomationsView factoryId={factoryId} t={t} />
737
+ ) : activeTab === "agents" ? (
738
+ <FactoryAgentsView />
699
739
  ) : activeTab === "audit" ? (
700
740
  <FactoryAuditView
701
741
  factoryId={factoryId}
@@ -735,6 +775,7 @@ function parseWorkspaceTab(value: string | null): WorkspaceTab {
735
775
  value === "inbox" ||
736
776
  value === "rules" ||
737
777
  value === "automations" ||
778
+ value === "agents" ||
738
779
  value === "audit" ||
739
780
  value === "settings"
740
781
  ? value
@@ -16,6 +16,7 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@agent-native/core": "workspace:*",
19
+ "@agent-native/dispatch": "workspace:*",
19
20
  "@agent-native/toolkit": "workspace:*",
20
21
  "@fontsource-variable/inter": "^5.2.8",
21
22
  "@libsql/client": "^0.15.8",
@@ -29,6 +29,8 @@ export const factoryGraphNodeSchema = z.object({
29
29
  kind: factoryNodeKindSchema,
30
30
  provider: factoryProviderSchema.optional(),
31
31
  agent: z.string().trim().max(120).optional(),
32
+ agentTargetType: z.enum(["agent", "app"]).optional(),
33
+ agentTargetId: z.string().trim().max(240).optional(),
32
34
  metricsKey: z.string().trim().max(120).optional(),
33
35
  position: z.object({
34
36
  x: z.number().finite().min(0).max(4000),
@@ -1,4 +1,5 @@
1
1
  import { getOrgContext } from "@agent-native/core/org";
2
+ import "@agent-native/dispatch/server";
2
3
  import {
3
4
  createAgentChatPlugin,
4
5
  loadActionsFromStaticRegistry,
@@ -32,6 +33,14 @@ const INITIAL_TOOL_NAMES = [
32
33
  "list-triage-rules",
33
34
  "get-triage-config",
34
35
  "navigate",
36
+ "list-workspace-apps",
37
+ "list-workspace-resources",
38
+ "create-workspace-resource",
39
+ "update-workspace-resource",
40
+ "import-agent",
41
+ "import-agent-pack",
42
+ "list-agent-pack",
43
+ "start-workspace-app-creation",
35
44
  ];
36
45
 
37
46
  const options = {
@@ -0,0 +1 @@
1
+ export { dispatchDbPlugin as default } from "@agent-native/dispatch/server";
@@ -0,0 +1,3 @@
1
+ import { setupDispatch } from "@agent-native/dispatch/server";
2
+
3
+ export default setupDispatch();
@@ -0,0 +1,3 @@
1
+ // Mail owns Gmail and Calendar through first-party actions; exposing the
2
+ // overlapping Google Workspace MCP setup creates a second connection path.
3
+ export const MAIL_NATIVE_MCP_PRESET_EXCLUSIONS = ["google-workspace"] as const;
@@ -2,6 +2,8 @@ import { agentNative } from "@agent-native/core/vite";
2
2
  import { reactRouter } from "@react-router/dev/vite";
3
3
  import { defineConfig } from "vite";
4
4
 
5
+ import { MAIL_NATIVE_MCP_PRESET_EXCLUSIONS } from "./app/lib/native-mcp-exclusions";
6
+
5
7
  const reactRouterPlugins = reactRouter as unknown as () => any[];
6
8
  const agentNativePlugins = agentNative as unknown as (
7
9
  options?: Parameters<typeof agentNative>[0],
@@ -14,6 +16,11 @@ export default defineConfig({
14
16
  // shiki only runs in AssistantChat's useEffect — keep it out of the
15
17
  // CF Pages Functions bundle (25 MiB limit).
16
18
  ssrStubs: ["shiki"],
19
+ // Mail's native Gmail actions own this workflow; don't offer a second,
20
+ // restricted Google Workspace MCP setup from inside the chat.
21
+ mcpIntegrations: {
22
+ defaults: { exclude: [...MAIL_NATIVE_MCP_PRESET_EXCLUSIONS] },
23
+ },
17
24
  }),
18
25
  ],
19
26
  });
@@ -33,7 +33,7 @@ import {
33
33
 
34
34
  export default defineAction({
35
35
  description:
36
- "Append a reply to an existing comment thread on an Agent-Native Plan. Call this when you want to respond to reviewer feedback in-thread, acknowledge a comment, or answer a question pinned to the plan. Requires an authenticated account; anonymous viewers cannot reply.",
36
+ "Append a reply to an existing comment thread on an Agent-Native Plan. Reply text supports inline Markdown for emphasis, inline code, links, and line breaks; headings are flattened. Call this when you want to respond to reviewer feedback in-thread, acknowledge a comment, or answer a question pinned to the plan. Requires an authenticated account; anonymous viewers cannot reply.",
37
37
  schema: z.object({
38
38
  planId: z.string().describe("Plan ID"),
39
39
  commentId: z
@@ -41,7 +41,12 @@ export default defineAction({
41
41
  .describe(
42
42
  "ID of the parent (thread-root) comment to reply to. Use get-plan-feedback to obtain comment IDs.",
43
43
  ),
44
- body: z.string().min(1).describe("Reply message text"),
44
+ body: z
45
+ .string()
46
+ .min(1)
47
+ .describe(
48
+ "Reply message text with optional inline Markdown; no headings",
49
+ ),
45
50
  resolutionTarget: planCommentResolutionTargetSchema
46
51
  .optional()
47
52
  .describe(
@@ -71,7 +71,7 @@ function threadCommentIdsFor(
71
71
 
72
72
  export default defineAction({
73
73
  description:
74
- 'Mark a plan comment thread as resolved or reopen it. Call this after addressing reviewer feedback to signal that the thread is handled. Pass status "resolved" to close the thread, "open" to reopen it. An optional resolutionNote posts a reply before the status change so reviewers see what was done. Resolving marks the thread done for reviewers; it does NOT remove it from get-plan-feedback — also call consume-plan-feedback (or pass consumedCommentIds to update-visual-plan) to stop the thread from appearing as pending work.',
74
+ 'Mark a plan comment thread as resolved or reopen it. An optional resolutionNote supports inline Markdown for emphasis, inline code, links, and line breaks; headings are flattened. Call this after addressing reviewer feedback to signal that the thread is handled. Pass status "resolved" to close the thread, "open" to reopen it. Resolving marks the thread done for reviewers; it does NOT remove it from get-plan-feedback — also call consume-plan-feedback (or pass consumedCommentIds to update-visual-plan) to stop the thread from appearing as pending work.',
75
75
  schema: z.object({
76
76
  planId: z.string().describe("Plan ID"),
77
77
  commentId: z
@@ -88,7 +88,7 @@ export default defineAction({
88
88
  .string()
89
89
  .optional()
90
90
  .describe(
91
- "Optional message to post as a reply before changing the status — use this to briefly explain what was done or why the thread is being closed.",
91
+ "Optional inline Markdown message to post as a reply before changing the status; headings are flattened.",
92
92
  ),
93
93
  }),
94
94
  publicAgent: {
@@ -538,7 +538,7 @@ const updateVisualPlanSchema = z.object({
538
538
  .optional()
539
539
  .default([])
540
540
  .describe(
541
- "Legacy comment array. Prefer reply-to-plan-comment / resolve-plan-comment for new comments.",
541
+ "Legacy comment array. Comment messages support inline Markdown for emphasis, inline code, links, and line breaks; headings are flattened. Prefer reply-to-plan-comment / resolve-plan-comment for new comments.",
542
542
  ),
543
543
  consumedCommentIds: z
544
544
  .array(z.string())
@@ -12,6 +12,10 @@ import { emailToColor, emailToName } from "@agent-native/core/client/collab";
12
12
  import { PromptComposer } from "@agent-native/core/client/composer";
13
13
  import { useActionQuery, useSession } from "@agent-native/core/client/hooks";
14
14
  import { useT } from "@agent-native/core/client/i18n";
15
+ import {
16
+ InlineMarkdown,
17
+ type InlineMarkdownProtectedSpan,
18
+ } from "@agent-native/core/client/markdown";
15
19
  import {
16
20
  useAcceptInvitation,
17
21
  useJoinByDomain,
@@ -976,30 +980,35 @@ function safeDecodeURIComponent(value: string): string {
976
980
  }
977
981
 
978
982
  function renderCommentMessage(message: string) {
979
- const parts: ReactNode[] = [];
980
- let lastIndex = 0;
983
+ const protectedSpans: InlineMarkdownProtectedSpan[] = [];
981
984
  const pattern = /@\[([^\]]+)\]\(mailto:([^)]+)\)/g;
982
985
  let match: RegExpExecArray | null;
983
986
  while ((match = pattern.exec(message)) !== null) {
984
- if (match.index > lastIndex) {
985
- parts.push(message.slice(lastIndex, match.index));
986
- }
987
987
  const label = match[1] ?? "";
988
988
  const email = safeDecodeURIComponent(match[2] ?? "");
989
- parts.push(
990
- <span
991
- key={`${email}-${match.index}`}
992
- className="mx-0.5 inline-flex max-w-[14rem] translate-y-[2px] items-center gap-1 rounded-full border border-primary/20 bg-primary/10 px-1.5 py-0.5 text-xs font-medium text-primary"
993
- title={email}
994
- >
995
- <IconAt className="size-3" />
996
- <span className="truncate">{label || email}</span>
997
- </span>,
998
- );
999
- lastIndex = pattern.lastIndex;
989
+ protectedSpans.push({
990
+ source: match[0],
991
+ label: label || email,
992
+ title: email,
993
+ });
1000
994
  }
1001
- if (lastIndex < message.length) parts.push(message.slice(lastIndex));
1002
- return parts.length > 0 ? parts : message;
995
+ return (
996
+ <InlineMarkdown
997
+ content={message}
998
+ inline
999
+ protectedSpans={protectedSpans}
1000
+ renderProtectedSpan={(span, children) => (
1001
+ <span
1002
+ key={span.source}
1003
+ className="mx-0.5 inline-flex max-w-[14rem] translate-y-[2px] items-center gap-1 rounded-full border border-primary/20 bg-primary/10 px-1.5 py-0.5 text-xs font-medium text-primary"
1004
+ title={span.title}
1005
+ >
1006
+ <IconAt className="size-3" />
1007
+ <span className="truncate">{children}</span>
1008
+ </span>
1009
+ )}
1010
+ />
1011
+ );
1003
1012
  }
1004
1013
 
1005
1014
  function CommentAvatar({
@@ -9066,9 +9075,9 @@ function CommentThreadMessage({
9066
9075
  </p>
9067
9076
  )}
9068
9077
  </div>
9069
- <p className="mt-1 whitespace-pre-wrap text-sm leading-6">
9078
+ <div className="mt-1 text-sm leading-6">
9070
9079
  {renderCommentMessage(comment.message)}
9071
- </p>
9080
+ </div>
9072
9081
  </div>
9073
9082
  {action}
9074
9083
  </div>
@@ -17,7 +17,7 @@ function displayNameFromEmail(email: string): string {
17
17
 
18
18
  export default defineAction({
19
19
  description:
20
- "Add a comment to a slide. Omit threadId to start a new thread; provide threadId to reply.",
20
+ "Add a comment to a slide. Inline Markdown supports emphasis, inline code, links, and line breaks; headings are flattened. Omit threadId to start a new thread; provide threadId to reply.",
21
21
  schema: z.object({
22
22
  deckId: z.string().describe("Deck ID"),
23
23
  slideId: z.string().describe("Slide ID"),
@@ -8,7 +8,7 @@ import { getDb, schema } from "../server/db/index.js";
8
8
 
9
9
  export default defineAction({
10
10
  description:
11
- "Update a slide comment. Resolving or reopening a comment applies to the full thread.",
11
+ "Update a slide comment. Comment text supports inline Markdown without headings. Resolving or reopening a comment applies to the full thread.",
12
12
  schema: z.object({
13
13
  id: z.string().describe("Comment ID"),
14
14
  deckId: z.string().optional().describe("Deck ID"),
@@ -1,4 +1,5 @@
1
1
  import { useT } from "@agent-native/core/client/i18n";
2
+ import { InlineMarkdown } from "@agent-native/core/client/markdown";
2
3
  import {
3
4
  IconX,
4
5
  IconCheck,
@@ -99,9 +100,10 @@ function CommentItem({
99
100
  )}
100
101
  </div>
101
102
  </div>
102
- <p className="text-[12px] text-foreground/90 mt-0.5 break-words leading-relaxed">
103
- {comment.content}
104
- </p>
103
+ <InlineMarkdown
104
+ content={comment.content}
105
+ className="mt-0.5 text-[12px] text-foreground/90 leading-relaxed"
106
+ />
105
107
  </div>
106
108
  </div>
107
109
  );
@@ -374,9 +376,10 @@ function ThreadCard({
374
376
  )}
375
377
  </div>
376
378
  </div>
377
- <p className="text-[12px] text-foreground/90 mt-0.5 break-words leading-relaxed">
378
- {rootComment.content}
379
- </p>
379
+ <InlineMarkdown
380
+ content={rootComment.content}
381
+ className="mt-0.5 text-[12px] text-foreground/90 leading-relaxed"
382
+ />
380
383
  </div>
381
384
  </div>
382
385