@aphexcms/cms-core 9.7.0 → 9.8.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 (326) hide show
  1. package/dist/agent-chat-state.svelte.d.ts +38 -0
  2. package/dist/agent-chat-state.svelte.d.ts.map +1 -0
  3. package/dist/agent-chat-state.svelte.js +86 -0
  4. package/dist/ai/content-workspace-tools.d.ts +3 -0
  5. package/dist/ai/content-workspace-tools.d.ts.map +1 -0
  6. package/dist/ai/content-workspace-tools.js +50 -0
  7. package/dist/ai/default-system-prompt.d.ts +2 -0
  8. package/dist/ai/default-system-prompt.d.ts.map +1 -0
  9. package/dist/ai/default-system-prompt.js +15 -0
  10. package/dist/ai/index.d.ts +2 -0
  11. package/dist/ai/index.d.ts.map +1 -0
  12. package/dist/ai/index.js +4 -0
  13. package/dist/ai/interfaces/ai-provider.d.ts +67 -0
  14. package/dist/ai/interfaces/ai-provider.d.ts.map +1 -0
  15. package/dist/ai/interfaces/ai-provider.js +16 -0
  16. package/dist/ai/run-agent-turn.d.ts +29 -0
  17. package/dist/ai/run-agent-turn.d.ts.map +1 -0
  18. package/dist/ai/run-agent-turn.js +166 -0
  19. package/dist/api/agent-chat.d.ts +27 -0
  20. package/dist/api/agent-chat.d.ts.map +1 -0
  21. package/dist/api/agent-chat.js +64 -0
  22. package/dist/api/documents.d.ts +8 -3
  23. package/dist/api/documents.d.ts.map +1 -1
  24. package/dist/api/documents.js +6 -6
  25. package/dist/api/schemas/agent-chat.d.ts +45 -0
  26. package/dist/api/schemas/agent-chat.d.ts.map +1 -0
  27. package/dist/api/schemas/agent-chat.js +35 -0
  28. package/dist/api/schemas/agent-operations.d.ts +13 -0
  29. package/dist/api/schemas/agent-operations.d.ts.map +1 -0
  30. package/dist/api/schemas/agent-operations.js +15 -0
  31. package/dist/api/schemas/documents.d.ts +22 -0
  32. package/dist/api/schemas/documents.d.ts.map +1 -1
  33. package/dist/api/schemas/documents.js +20 -2
  34. package/dist/chunk-recovery.d.ts +33 -0
  35. package/dist/chunk-recovery.d.ts.map +1 -0
  36. package/dist/chunk-recovery.js +131 -0
  37. package/dist/client/index.d.ts +1 -0
  38. package/dist/client/index.d.ts.map +1 -1
  39. package/dist/client/index.js +1 -0
  40. package/dist/client/ui.d.ts +1 -0
  41. package/dist/client/ui.d.ts.map +1 -1
  42. package/dist/client/ui.js +1 -0
  43. package/dist/components/AdminApp.svelte +37 -3
  44. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  45. package/dist/components/admin/ActivityView.svelte +251 -42
  46. package/dist/components/admin/ActivityView.svelte.d.ts.map +1 -1
  47. package/dist/components/admin/AgentChat.svelte +977 -0
  48. package/dist/components/admin/AgentChat.svelte.d.ts +17 -0
  49. package/dist/components/admin/AgentChat.svelte.d.ts.map +1 -0
  50. package/dist/components/admin/DocumentEditor.svelte +273 -60
  51. package/dist/components/admin/DocumentEditor.svelte.d.ts +6 -0
  52. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  53. package/dist/components/admin/ObjectModal.svelte +4 -2
  54. package/dist/components/admin/fields/ArrayField.svelte +4 -1
  55. package/dist/components/admin/fields/ReferenceField.svelte +12 -1
  56. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  57. package/dist/components/index.d.ts +1 -0
  58. package/dist/components/index.d.ts.map +1 -1
  59. package/dist/components/index.js +1 -0
  60. package/dist/components/layout/Sidebar.svelte +26 -2
  61. package/dist/components/layout/Sidebar.svelte.d.ts +1 -0
  62. package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -1
  63. package/dist/db/interfaces/agent-change-sets.d.ts +17 -0
  64. package/dist/db/interfaces/agent-change-sets.d.ts.map +1 -0
  65. package/dist/db/interfaces/agent-change-sets.js +1 -0
  66. package/dist/db/interfaces/document.d.ts +25 -3
  67. package/dist/db/interfaces/document.d.ts.map +1 -1
  68. package/dist/db/interfaces/document.js +19 -1
  69. package/dist/db/interfaces/index.d.ts +4 -1
  70. package/dist/db/interfaces/index.d.ts.map +1 -1
  71. package/dist/db/interfaces/index.js +1 -1
  72. package/dist/document-refresh.svelte.d.ts +2 -0
  73. package/dist/document-refresh.svelte.d.ts.map +1 -1
  74. package/dist/document-refresh.svelte.js +15 -0
  75. package/dist/document-workspace-registry.svelte.d.ts +15 -0
  76. package/dist/document-workspace-registry.svelte.d.ts.map +1 -0
  77. package/dist/document-workspace-registry.svelte.js +30 -0
  78. package/dist/field-validation/utils.d.ts.map +1 -1
  79. package/dist/field-validation/utils.js +211 -29
  80. package/dist/hooks.d.ts +2 -0
  81. package/dist/hooks.d.ts.map +1 -1
  82. package/dist/hooks.js +2 -0
  83. package/dist/lib/agent-chat-state.svelte.d.ts +38 -0
  84. package/dist/lib/agent-chat-state.svelte.d.ts.map +1 -0
  85. package/dist/lib/agent-chat-state.svelte.js +87 -0
  86. package/dist/lib/agent-chat-state.svelte.js.map +1 -0
  87. package/dist/lib/ai/content-workspace-tools.d.ts +3 -0
  88. package/dist/lib/ai/content-workspace-tools.d.ts.map +1 -0
  89. package/dist/lib/ai/content-workspace-tools.js +51 -0
  90. package/dist/lib/ai/content-workspace-tools.js.map +1 -0
  91. package/dist/lib/ai/default-system-prompt.d.ts +2 -0
  92. package/dist/lib/ai/default-system-prompt.d.ts.map +1 -0
  93. package/dist/lib/ai/default-system-prompt.js +16 -0
  94. package/dist/lib/ai/default-system-prompt.js.map +1 -0
  95. package/dist/lib/ai/index.d.ts +2 -0
  96. package/dist/lib/ai/index.d.ts.map +1 -0
  97. package/dist/lib/ai/index.js +5 -0
  98. package/dist/lib/ai/index.js.map +1 -0
  99. package/dist/lib/ai/interfaces/ai-provider.d.ts +67 -0
  100. package/dist/lib/ai/interfaces/ai-provider.d.ts.map +1 -0
  101. package/dist/lib/ai/interfaces/ai-provider.js +17 -0
  102. package/dist/lib/ai/interfaces/ai-provider.js.map +1 -0
  103. package/dist/lib/ai/run-agent-turn.d.ts +29 -0
  104. package/dist/lib/ai/run-agent-turn.d.ts.map +1 -0
  105. package/dist/lib/ai/run-agent-turn.js +167 -0
  106. package/dist/lib/ai/run-agent-turn.js.map +1 -0
  107. package/dist/lib/api/agent-chat.d.ts +27 -0
  108. package/dist/lib/api/agent-chat.d.ts.map +1 -0
  109. package/dist/lib/api/agent-chat.js +65 -0
  110. package/dist/lib/api/agent-chat.js.map +1 -0
  111. package/dist/lib/api/documents.d.ts +8 -3
  112. package/dist/lib/api/documents.d.ts.map +1 -1
  113. package/dist/lib/api/documents.js +6 -6
  114. package/dist/lib/api/documents.js.map +1 -1
  115. package/dist/lib/api/schemas/agent-chat.d.ts +45 -0
  116. package/dist/lib/api/schemas/agent-chat.d.ts.map +1 -0
  117. package/dist/lib/api/schemas/agent-chat.js +36 -0
  118. package/dist/lib/api/schemas/agent-chat.js.map +1 -0
  119. package/dist/lib/api/schemas/agent-operations.d.ts +13 -0
  120. package/dist/lib/api/schemas/agent-operations.d.ts.map +1 -0
  121. package/dist/lib/api/schemas/agent-operations.js +16 -0
  122. package/dist/lib/api/schemas/agent-operations.js.map +1 -0
  123. package/dist/lib/api/schemas/documents.d.ts +22 -0
  124. package/dist/lib/api/schemas/documents.d.ts.map +1 -1
  125. package/dist/lib/api/schemas/documents.js +20 -2
  126. package/dist/lib/api/schemas/documents.js.map +1 -1
  127. package/dist/lib/chunk-recovery.d.ts +33 -0
  128. package/dist/lib/chunk-recovery.d.ts.map +1 -0
  129. package/dist/lib/chunk-recovery.js +132 -0
  130. package/dist/lib/chunk-recovery.js.map +1 -0
  131. package/dist/lib/client/index.d.ts +1 -0
  132. package/dist/lib/client/index.d.ts.map +1 -1
  133. package/dist/lib/client/index.js +1 -0
  134. package/dist/lib/client/index.js.map +1 -1
  135. package/dist/lib/client/ui.d.ts +1 -0
  136. package/dist/lib/client/ui.d.ts.map +1 -1
  137. package/dist/lib/client/ui.js +1 -0
  138. package/dist/lib/client/ui.js.map +1 -1
  139. package/dist/lib/components/index.d.ts +1 -0
  140. package/dist/lib/components/index.d.ts.map +1 -1
  141. package/dist/lib/components/index.js +1 -0
  142. package/dist/lib/components/index.js.map +1 -1
  143. package/dist/lib/db/interfaces/agent-change-sets.d.ts +17 -0
  144. package/dist/lib/db/interfaces/agent-change-sets.d.ts.map +1 -0
  145. package/dist/lib/db/interfaces/agent-change-sets.js +2 -0
  146. package/dist/lib/db/interfaces/agent-change-sets.js.map +1 -0
  147. package/dist/lib/db/interfaces/document.d.ts +25 -3
  148. package/dist/lib/db/interfaces/document.d.ts.map +1 -1
  149. package/dist/lib/db/interfaces/document.js +19 -1
  150. package/dist/lib/db/interfaces/document.js.map +1 -1
  151. package/dist/lib/db/interfaces/index.d.ts +4 -1
  152. package/dist/lib/db/interfaces/index.d.ts.map +1 -1
  153. package/dist/lib/db/interfaces/index.js +1 -1
  154. package/dist/lib/db/interfaces/index.js.map +1 -1
  155. package/dist/lib/document-refresh.svelte.d.ts +2 -0
  156. package/dist/lib/document-refresh.svelte.d.ts.map +1 -1
  157. package/dist/lib/document-refresh.svelte.js +15 -0
  158. package/dist/lib/document-refresh.svelte.js.map +1 -1
  159. package/dist/lib/document-workspace-registry.svelte.d.ts +15 -0
  160. package/dist/lib/document-workspace-registry.svelte.d.ts.map +1 -0
  161. package/dist/lib/document-workspace-registry.svelte.js +31 -0
  162. package/dist/lib/document-workspace-registry.svelte.js.map +1 -0
  163. package/dist/lib/field-validation/utils.d.ts.map +1 -1
  164. package/dist/lib/field-validation/utils.js +211 -29
  165. package/dist/lib/field-validation/utils.js.map +1 -1
  166. package/dist/lib/hooks.d.ts +2 -0
  167. package/dist/lib/hooks.d.ts.map +1 -1
  168. package/dist/lib/hooks.js +2 -0
  169. package/dist/lib/hooks.js.map +1 -1
  170. package/dist/lib/local-api/collection-api.d.ts +7 -2
  171. package/dist/lib/local-api/collection-api.d.ts.map +1 -1
  172. package/dist/lib/local-api/collection-api.js +17 -10
  173. package/dist/lib/local-api/collection-api.js.map +1 -1
  174. package/dist/lib/mcp/tools.d.ts +39 -4
  175. package/dist/lib/mcp/tools.d.ts.map +1 -1
  176. package/dist/lib/mcp/tools.js +546 -362
  177. package/dist/lib/mcp/tools.js.map +1 -1
  178. package/dist/lib/plugins/resolver.d.ts +8 -1
  179. package/dist/lib/plugins/resolver.d.ts.map +1 -1
  180. package/dist/lib/plugins/resolver.js +14 -1
  181. package/dist/lib/plugins/resolver.js.map +1 -1
  182. package/dist/lib/plugins/types.d.ts +23 -2
  183. package/dist/lib/plugins/types.d.ts.map +1 -1
  184. package/dist/lib/plugins/types.js.map +1 -1
  185. package/dist/lib/preview/stega.d.ts +2 -2
  186. package/dist/lib/preview/stega.d.ts.map +1 -1
  187. package/dist/lib/preview/stega.js +52 -29
  188. package/dist/lib/preview/stega.js.map +1 -1
  189. package/dist/lib/schema-utils/validator.d.ts.map +1 -1
  190. package/dist/lib/schema-utils/validator.js +5 -2
  191. package/dist/lib/schema-utils/validator.js.map +1 -1
  192. package/dist/lib/server/api/index.d.ts.map +1 -1
  193. package/dist/lib/server/api/index.js +8 -0
  194. package/dist/lib/server/api/index.js.map +1 -1
  195. package/dist/lib/server/api/routes/agent-change-sets.d.ts +4 -0
  196. package/dist/lib/server/api/routes/agent-change-sets.d.ts.map +1 -0
  197. package/dist/lib/server/api/routes/agent-change-sets.js +132 -0
  198. package/dist/lib/server/api/routes/agent-change-sets.js.map +1 -0
  199. package/dist/lib/server/api/routes/agent-chat.d.ts +14 -0
  200. package/dist/lib/server/api/routes/agent-chat.d.ts.map +1 -0
  201. package/dist/lib/server/api/routes/agent-chat.js +224 -0
  202. package/dist/lib/server/api/routes/agent-chat.js.map +1 -0
  203. package/dist/lib/server/api/routes/document-versions.d.ts.map +1 -1
  204. package/dist/lib/server/api/routes/document-versions.js +16 -2
  205. package/dist/lib/server/api/routes/document-versions.js.map +1 -1
  206. package/dist/lib/server/api/routes/documents-by-id.d.ts.map +1 -1
  207. package/dist/lib/server/api/routes/documents-by-id.js +11 -1
  208. package/dist/lib/server/api/routes/documents-by-id.js.map +1 -1
  209. package/dist/lib/server/api/routes/documents-publish.d.ts.map +1 -1
  210. package/dist/lib/server/api/routes/documents-publish.js +36 -3
  211. package/dist/lib/server/api/routes/documents-publish.js.map +1 -1
  212. package/dist/lib/server/api/routes/jobs.d.ts.map +1 -1
  213. package/dist/lib/server/api/routes/jobs.js +4 -2
  214. package/dist/lib/server/api/routes/jobs.js.map +1 -1
  215. package/dist/lib/server/api/routes/resolve-created-by.d.ts +13 -0
  216. package/dist/lib/server/api/routes/resolve-created-by.d.ts.map +1 -0
  217. package/dist/lib/server/api/routes/resolve-created-by.js +31 -0
  218. package/dist/lib/server/api/routes/resolve-created-by.js.map +1 -0
  219. package/dist/lib/server/index.d.ts +1 -0
  220. package/dist/lib/server/index.d.ts.map +1 -1
  221. package/dist/lib/server/index.js +1 -0
  222. package/dist/lib/server/index.js.map +1 -1
  223. package/dist/lib/services/version-service.d.ts +4 -4
  224. package/dist/lib/services/version-service.d.ts.map +1 -1
  225. package/dist/lib/services/version-service.js +15 -11
  226. package/dist/lib/services/version-service.js.map +1 -1
  227. package/dist/lib/type-gen.d.ts.map +1 -1
  228. package/dist/lib/type-gen.js +11 -0
  229. package/dist/lib/type-gen.js.map +1 -1
  230. package/dist/lib/types/agent-change-sets.d.ts +70 -0
  231. package/dist/lib/types/agent-change-sets.d.ts.map +1 -0
  232. package/dist/lib/types/agent-change-sets.js +7 -0
  233. package/dist/lib/types/agent-change-sets.js.map +1 -0
  234. package/dist/lib/types/agent-stream.d.ts +60 -0
  235. package/dist/lib/types/agent-stream.d.ts.map +1 -0
  236. package/dist/lib/types/agent-stream.js +12 -0
  237. package/dist/lib/types/agent-stream.js.map +1 -0
  238. package/dist/lib/types/agent-tools.d.ts +65 -0
  239. package/dist/lib/types/agent-tools.d.ts.map +1 -0
  240. package/dist/lib/types/agent-tools.js +2 -0
  241. package/dist/lib/types/agent-tools.js.map +1 -0
  242. package/dist/lib/types/config.d.ts +19 -0
  243. package/dist/lib/types/config.d.ts.map +1 -1
  244. package/dist/lib/types/document-workspace.d.ts +53 -0
  245. package/dist/lib/types/document-workspace.d.ts.map +1 -0
  246. package/dist/lib/types/document-workspace.js +15 -0
  247. package/dist/lib/types/document-workspace.js.map +1 -0
  248. package/dist/lib/types/document.d.ts +5 -0
  249. package/dist/lib/types/document.d.ts.map +1 -1
  250. package/dist/lib/types/index.d.ts +2 -0
  251. package/dist/lib/types/index.d.ts.map +1 -1
  252. package/dist/lib/types/index.js +2 -0
  253. package/dist/lib/types/index.js.map +1 -1
  254. package/dist/lib/types/schemas.js +1 -1
  255. package/dist/lib/types/schemas.js.map +1 -1
  256. package/dist/lib/utils/fetch-remote-file.d.ts +11 -0
  257. package/dist/lib/utils/fetch-remote-file.d.ts.map +1 -0
  258. package/dist/lib/utils/fetch-remote-file.js +169 -0
  259. package/dist/lib/utils/fetch-remote-file.js.map +1 -0
  260. package/dist/local-api/collection-api.d.ts +7 -2
  261. package/dist/local-api/collection-api.d.ts.map +1 -1
  262. package/dist/local-api/collection-api.js +17 -10
  263. package/dist/mcp/tools.d.ts +39 -4
  264. package/dist/mcp/tools.d.ts.map +1 -1
  265. package/dist/mcp/tools.js +546 -362
  266. package/dist/plugins/resolver.d.ts +8 -1
  267. package/dist/plugins/resolver.d.ts.map +1 -1
  268. package/dist/plugins/resolver.js +14 -1
  269. package/dist/plugins/types.d.ts +23 -2
  270. package/dist/plugins/types.d.ts.map +1 -1
  271. package/dist/preview/stega.d.ts +2 -2
  272. package/dist/preview/stega.d.ts.map +1 -1
  273. package/dist/preview/stega.js +52 -29
  274. package/dist/schema-utils/validator.d.ts.map +1 -1
  275. package/dist/schema-utils/validator.js +5 -2
  276. package/dist/server/api/index.d.ts.map +1 -1
  277. package/dist/server/api/index.js +8 -0
  278. package/dist/server/api/routes/agent-change-sets.d.ts +4 -0
  279. package/dist/server/api/routes/agent-change-sets.d.ts.map +1 -0
  280. package/dist/server/api/routes/agent-change-sets.js +131 -0
  281. package/dist/server/api/routes/agent-chat.d.ts +14 -0
  282. package/dist/server/api/routes/agent-chat.d.ts.map +1 -0
  283. package/dist/server/api/routes/agent-chat.js +223 -0
  284. package/dist/server/api/routes/document-versions.d.ts.map +1 -1
  285. package/dist/server/api/routes/document-versions.js +16 -2
  286. package/dist/server/api/routes/documents-by-id.d.ts.map +1 -1
  287. package/dist/server/api/routes/documents-by-id.js +11 -1
  288. package/dist/server/api/routes/documents-publish.d.ts.map +1 -1
  289. package/dist/server/api/routes/documents-publish.js +36 -3
  290. package/dist/server/api/routes/jobs.d.ts.map +1 -1
  291. package/dist/server/api/routes/jobs.js +4 -2
  292. package/dist/server/api/routes/resolve-created-by.d.ts +13 -0
  293. package/dist/server/api/routes/resolve-created-by.d.ts.map +1 -0
  294. package/dist/server/api/routes/resolve-created-by.js +30 -0
  295. package/dist/server/index.d.ts +1 -0
  296. package/dist/server/index.d.ts.map +1 -1
  297. package/dist/server/index.js +1 -0
  298. package/dist/services/version-service.d.ts +4 -4
  299. package/dist/services/version-service.d.ts.map +1 -1
  300. package/dist/services/version-service.js +15 -11
  301. package/dist/type-gen.d.ts.map +1 -1
  302. package/dist/type-gen.js +11 -0
  303. package/dist/types/agent-change-sets.d.ts +70 -0
  304. package/dist/types/agent-change-sets.d.ts.map +1 -0
  305. package/dist/types/agent-change-sets.js +6 -0
  306. package/dist/types/agent-stream.d.ts +60 -0
  307. package/dist/types/agent-stream.d.ts.map +1 -0
  308. package/dist/types/agent-stream.js +11 -0
  309. package/dist/types/agent-tools.d.ts +65 -0
  310. package/dist/types/agent-tools.d.ts.map +1 -0
  311. package/dist/types/agent-tools.js +1 -0
  312. package/dist/types/config.d.ts +19 -0
  313. package/dist/types/config.d.ts.map +1 -1
  314. package/dist/types/document-workspace.d.ts +53 -0
  315. package/dist/types/document-workspace.d.ts.map +1 -0
  316. package/dist/types/document-workspace.js +14 -0
  317. package/dist/types/document.d.ts +5 -0
  318. package/dist/types/document.d.ts.map +1 -1
  319. package/dist/types/index.d.ts +2 -0
  320. package/dist/types/index.d.ts.map +1 -1
  321. package/dist/types/index.js +2 -0
  322. package/dist/types/schemas.js +1 -1
  323. package/dist/utils/fetch-remote-file.d.ts +11 -0
  324. package/dist/utils/fetch-remote-file.d.ts.map +1 -0
  325. package/dist/utils/fetch-remote-file.js +168 -0
  326. package/package.json +5 -2
@@ -0,0 +1,38 @@
1
+ export type HistoryMessage = {
2
+ role: 'system' | 'user' | 'assistant' | 'tool';
3
+ content: string;
4
+ toolCalls?: Array<{
5
+ id: string;
6
+ name: string;
7
+ arguments: Record<string, unknown>;
8
+ }>;
9
+ toolCallId?: string;
10
+ };
11
+ export type ToolCall = {
12
+ id: string;
13
+ name: string;
14
+ arguments: Record<string, unknown>;
15
+ status: 'running' | 'complete' | 'error';
16
+ result?: unknown;
17
+ error?: string;
18
+ };
19
+ export type Turn = {
20
+ id: string;
21
+ role: 'user' | 'assistant';
22
+ text: string;
23
+ status: 'complete' | 'streaming' | 'error' | 'stopped';
24
+ toolCalls: ToolCall[];
25
+ error?: string;
26
+ /** Only set on user turns — `history.length` right before this turn was sent, so
27
+ * `retry()` can roll `history` back to exactly that point rather than guessing an
28
+ * offset (a turn's server-reported `messages` can add more than 2 entries once tool
29
+ * calls are involved). */
30
+ historyIndexBeforeTurn?: number;
31
+ };
32
+ export declare const agentChatState: {
33
+ turns: Turn[];
34
+ history: HistoryMessage[];
35
+ contextSentFor: string | null;
36
+ lastPromptTokens: number;
37
+ };
38
+ //# sourceMappingURL=agent-chat-state.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-chat-state.svelte.d.ts","sourceRoot":"","sources":["../src/lib/agent-chat-state.svelte.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;IACvD,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;8BAG0B;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AA+DF,eAAO,MAAM,cAAc;WAxBR,IAAI,EAAE;aAMJ,cAAc,EAAE;oBAMT,MAAM,GAAG,IAAI;sBAMX,MAAM;CAMgB,CAAC"}
@@ -0,0 +1,86 @@
1
+ // Module-level state for AgentChat.svelte — deliberately NOT local component state.
2
+ //
3
+ // The assistant panel is mounted inside a Sheet (Sidebar.svelte); bits-ui's Dialog.Content
4
+ // (which Sheet wraps) unmounts its children when closed, so a plain `$state` declared inside
5
+ // AgentChat.svelte gets destroyed and recreated every time the panel is closed and reopened —
6
+ // the conversation would vanish even without navigating away or reloading. A module-level
7
+ // singleton survives that remount (and client-side navigation, since it's the same JS module
8
+ // instance) — same pattern as `activeTabState` (apps/studio/src/lib/stores/activeTab.svelte.ts).
9
+ //
10
+ // Also mirrored to localStorage so it survives a hard reload too — still just this one
11
+ // browser tab's convenience cache, not real conversation persistence (a DB-backed, multi-
12
+ // conversation, cross-device history is a separate, bigger feature, deliberately not built
13
+ // yet — see the conversation that led here). Wrapped in try/catch throughout: private
14
+ // browsing / a full storage quota must never break the chat, just silently skip persisting.
15
+ const STORAGE_KEY = 'aphex:agent-chat-state:v1';
16
+ function loadPersisted() {
17
+ if (typeof localStorage === 'undefined')
18
+ return null;
19
+ try {
20
+ const raw = localStorage.getItem(STORAGE_KEY);
21
+ return raw ? JSON.parse(raw) : null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ function createAgentChatState() {
28
+ const persisted = loadPersisted();
29
+ let turns = $state(persisted?.turns ?? []);
30
+ let history = $state(persisted?.history ?? []);
31
+ let contextSentFor = $state(persisted?.contextSentFor ?? null);
32
+ // The most recent `usage.promptTokens` reported by the model — since this endpoint
33
+ // resends the full conversation on every call, this is effectively "how big the
34
+ // conversation currently is," used to warn before it gets unwieldy (or expensive).
35
+ let lastPromptTokens = $state(persisted?.lastPromptTokens ?? 0);
36
+ // A live turn mid-stream shouldn't be persisted as if it finished — reload would show a
37
+ // permanently "streaming" bubble with a spinner that will never resolve. Reloading the
38
+ // page always means the in-flight request is gone, so mark it stopped instead.
39
+ for (const turn of turns) {
40
+ if (turn.status === 'streaming')
41
+ turn.status = 'stopped';
42
+ }
43
+ if (typeof localStorage !== 'undefined') {
44
+ $effect.root(() => {
45
+ $effect(() => {
46
+ // Reading `turns`/`history`/`contextSentFor` here is what makes this effect
47
+ // re-run on every mutation (including in-place `.push()`, via `$state`'s deep
48
+ // reactivity) — not just on reassignment.
49
+ const snapshot = { turns, history, contextSentFor, lastPromptTokens };
50
+ try {
51
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(snapshot));
52
+ }
53
+ catch {
54
+ // Quota exceeded / private browsing — best-effort only, drop it.
55
+ }
56
+ });
57
+ });
58
+ }
59
+ return {
60
+ get turns() {
61
+ return turns;
62
+ },
63
+ set turns(value) {
64
+ turns = value;
65
+ },
66
+ get history() {
67
+ return history;
68
+ },
69
+ set history(value) {
70
+ history = value;
71
+ },
72
+ get contextSentFor() {
73
+ return contextSentFor;
74
+ },
75
+ set contextSentFor(value) {
76
+ contextSentFor = value;
77
+ },
78
+ get lastPromptTokens() {
79
+ return lastPromptTokens;
80
+ },
81
+ set lastPromptTokens(value) {
82
+ lastPromptTokens = value;
83
+ }
84
+ };
85
+ }
86
+ export const agentChatState = createAgentChatState();
@@ -0,0 +1,3 @@
1
+ import type { ContentAgentTool } from '../mcp/tools.js';
2
+ export declare const contentWorkspaceTools: ContentAgentTool[];
3
+ //# sourceMappingURL=content-workspace-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-workspace-tools.d.ts","sourceRoot":"","sources":["../../src/lib/ai/content-workspace-tools.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQrD,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,EA8BnD,CAAC"}
@@ -0,0 +1,50 @@
1
+ // ai/content-workspace-tools.ts
2
+ //
3
+ // The two `execution: 'workspace'` tools: `content_patch_fields` (buffer a shallow-merge
4
+ // patch onto the document currently open in an editor tab) and `content_save_draft`
5
+ // (flush the buffered patch(es) as one CAS-guarded save). Live outside `mcp/tools.ts` on
6
+ // purpose — these aren't MCP-servable (an MCP client has no browser tab holding a live
7
+ // draft), so they only ever reach a caller through `resolveAgentTools`'s `documentContext`
8
+ // gate (`mcp/tools.ts`).
9
+ //
10
+ // `execute` on both is unreachable in practice: `run-agent-turn.ts`'s per-round tool loop
11
+ // partitions calls by `definition.execution` and never calls `.execute` for a `'workspace'`
12
+ // tool — it pauses the turn instead (see `types/agent-stream.ts`'s `done` event doc) and the
13
+ // *client* resolves the call against a live `DocumentWorkspace`. These bodies exist only to
14
+ // satisfy `ContentAgentTool`'s shape; don't "clean them up" into something callable without
15
+ // also removing the pause branch in `run-agent-turn.ts`, or a workspace tool would silently
16
+ // execute server-side against no live draft at all.
17
+ import { z } from 'zod';
18
+ const unreachable = (name) => Promise.resolve({
19
+ success: false,
20
+ error: `${name} must be resolved client-side against a live DocumentWorkspace; the server should never execute it directly.`
21
+ });
22
+ export const contentWorkspaceTools = [
23
+ {
24
+ definition: {
25
+ name: 'content_patch_fields',
26
+ description: 'Patch scalar/reference/asset fields on the document currently open in the editor. ' +
27
+ 'Buffered in-memory only — nothing is persisted until content_save_draft is called. ' +
28
+ 'Fields not mentioned are left unchanged.',
29
+ mutates: true,
30
+ requiredCapabilities: ['document.update'],
31
+ execution: 'workspace',
32
+ inputSchema: z.object({
33
+ fields: z.record(z.string(), z.unknown()).describe('Top-level field name -> new value.')
34
+ })
35
+ },
36
+ execute: () => unreachable('content_patch_fields')
37
+ },
38
+ {
39
+ definition: {
40
+ name: 'content_save_draft',
41
+ description: 'Persist the field patch(es) applied via content_patch_fields to the open document as ' +
42
+ 'one draft save, guarded against concurrent edits. Does not publish.',
43
+ mutates: true,
44
+ requiredCapabilities: ['document.update'],
45
+ execution: 'workspace',
46
+ inputSchema: z.object({})
47
+ },
48
+ execute: () => unreachable('content_save_draft')
49
+ }
50
+ ];
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_AGENT_SYSTEM_PROMPT = "You are the in-admin content assistant for this CMS. You can read and edit content through the tools available to you \u2014 call `describe_cms` first if you don't already know what content types, fields, and tools exist in this session; never guess at a schema's shape.\n\nGuidelines:\n- Prefer drafts: create or edit content as a draft. Only call `publish_document` when the user has explicitly asked you to publish \u2014 writing or updating something is not itself a request to publish it.\n- If `content_patch_fields`/`content_save_draft` are available, a document is currently open in the admin editor \u2014 use those two tools (not `update_document`) for any edit to that document, so the change appears live in the editor instead of only in the database.\n- Before a broad or hard-to-reverse change (bulk edits, unpublishing, overwriting existing content), briefly say what you're about to do rather than doing it silently.\n- Only reference fields, collections, and tools that `describe_cms`/`get_schema` actually showed you \u2014 never invent one.\n- If a tool call fails or is forbidden, say why rather than retrying blindly or working around it.\n- Keep responses concise \u2014 don't restate what a tool result already showed.";
2
+ //# sourceMappingURL=default-system-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-system-prompt.d.ts","sourceRoot":"","sources":["../../src/lib/ai/default-system-prompt.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,2BAA2B,8tCAQoC,CAAC"}
@@ -0,0 +1,15 @@
1
+ // The in-admin agent's default system prompt. Overridable per-instance via
2
+ // `createCMSConfig({ agentSystemPrompt: '...' })` (see types/config.ts) — an agency
3
+ // deploying this CMS for a client may want different tone/guardrails than another. Kept
4
+ // short and behavioral rather than descriptive: the tool list, schema, and capabilities are
5
+ // already self-describing via the `describe_cms` tool, so this only needs to say things a
6
+ // tool description can't — when to hold back, not what exists.
7
+ export const DEFAULT_AGENT_SYSTEM_PROMPT = `You are the in-admin content assistant for this CMS. You can read and edit content through the tools available to you — call \`describe_cms\` first if you don't already know what content types, fields, and tools exist in this session; never guess at a schema's shape.
8
+
9
+ Guidelines:
10
+ - Prefer drafts: create or edit content as a draft. Only call \`publish_document\` when the user has explicitly asked you to publish — writing or updating something is not itself a request to publish it.
11
+ - If \`content_patch_fields\`/\`content_save_draft\` are available, a document is currently open in the admin editor — use those two tools (not \`update_document\`) for any edit to that document, so the change appears live in the editor instead of only in the database.
12
+ - Before a broad or hard-to-reverse change (bulk edits, unpublishing, overwriting existing content), briefly say what you're about to do rather than doing it silently.
13
+ - Only reference fields, collections, and tools that \`describe_cms\`/\`get_schema\` actually showed you — never invent one.
14
+ - If a tool call fails or is forbidden, say why rather than retrying blindly or working around it.
15
+ - Keep responses concise — don't restate what a tool result already showed.`;
@@ -0,0 +1,2 @@
1
+ export * from './interfaces/ai-provider.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/ai/index.ts"],"names":[],"mappings":"AAIA,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,4 @@
1
+ // Aphex CMS AI Layer
2
+ // Ports and adapters for the in-admin agent's model backend
3
+ // Interfaces
4
+ export * from './interfaces/ai-provider.js';
@@ -0,0 +1,67 @@
1
+ /** One message in a conversation. `tool` messages carry the result of a prior `toolCallId`. */
2
+ export interface AIMessage {
3
+ role: 'system' | 'user' | 'assistant' | 'tool';
4
+ content: string;
5
+ /** Present on an assistant message that requested one or more tool calls. */
6
+ toolCalls?: AIToolCall[];
7
+ /** Present on a `tool` role message — which prior call this is the result of. */
8
+ toolCallId?: string;
9
+ }
10
+ /** A single tool invocation the model requested. */
11
+ export interface AIToolCall {
12
+ id: string;
13
+ name: string;
14
+ /** Parsed JSON arguments the model produced — already validated against the tool's zod schema by the caller before execution. */
15
+ arguments: Record<string, unknown>;
16
+ }
17
+ /**
18
+ * A tool definition adapted to the provider's function-calling format. The
19
+ * adapter owns converting `AgentToolDefinition.inputSchema` (zod) into this
20
+ * shape — cms-core stays schema-library-agnostic on the wire, only zod
21
+ * internally.
22
+ */
23
+ export interface AIToolSpec {
24
+ name: string;
25
+ description: string;
26
+ /** JSON Schema describing the arguments object. */
27
+ parameters: Record<string, unknown>;
28
+ }
29
+ export interface AIChatRequest {
30
+ /** Provider-specific model identifier, e.g. `anthropic/claude-sonnet-4.5` (OpenRouter) or `claude-sonnet-4-5` (Anthropic direct). */
31
+ model: string;
32
+ messages: AIMessage[];
33
+ tools?: AIToolSpec[];
34
+ /** Optional cap; adapters should pass their provider's equivalent through unchanged when omitted. */
35
+ maxTokens?: number;
36
+ /** Aborts the in-flight request — cancellation propagates from the browser tab through the runtime to here. */
37
+ signal?: AbortSignal;
38
+ }
39
+ /**
40
+ * One item in a streamed response. The runtime layer (apps/studio, not
41
+ * cms-core) maps this onto whatever wire format it sends the browser
42
+ * (SSE/NDJSON) — this is the provider-boundary shape, not the browser-facing
43
+ * one, though the two are intentionally close.
44
+ */
45
+ export type AIStreamEvent = {
46
+ type: 'text';
47
+ delta: string;
48
+ } | {
49
+ type: 'toolCall';
50
+ toolCall: AIToolCall;
51
+ } | {
52
+ type: 'usage';
53
+ promptTokens: number;
54
+ completionTokens: number;
55
+ } | {
56
+ type: 'error';
57
+ message: string;
58
+ } | {
59
+ type: 'done';
60
+ finishReason: 'stop' | 'tool_calls' | 'length' | 'error';
61
+ };
62
+ export interface AIProviderAdapter {
63
+ readonly name: string;
64
+ /** Stream a chat completion, yielding events as the model produces them. */
65
+ chatStream(request: AIChatRequest): AsyncIterable<AIStreamEvent>;
66
+ }
67
+ //# sourceMappingURL=ai-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/ai/interfaces/ai-provider.ts"],"names":[],"mappings":"AAgBA,+FAA+F;AAC/F,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,UAAU,EAAE,CAAC;IACzB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,oDAAoD;AACpD,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,iIAAiI;IACjI,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC7B,qIAAqI;IACrI,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,qGAAqG;IACrG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+GAA+G;IAC/G,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAA;CAAE,CAAC;AAE9E,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;CACjE"}
@@ -0,0 +1,16 @@
1
+ // ai/interfaces/ai-provider.ts
2
+ //
3
+ // Ports & adapters for the in-admin agent's model backend — same shape as
4
+ // EmailAdapter (see ../../email/interfaces/email.ts): cms-core owns the
5
+ // provider-neutral contract only; concrete provider clients (credentials,
6
+ // wire format, streaming parse) live in separate packages the app wires in
7
+ // via `createCMSConfig({ aiProvider: ... })`. Exactly one active instance-wide,
8
+ // same as database/storage/email — not a plugin, since a CMS install picks
9
+ // one model backend, not a composable set of them.
10
+ //
11
+ // Two adapters cover four providers: OpenAI, OpenRouter, and Ollama all speak
12
+ // the same OpenAI-compatible chat-completions + function-calling wire format
13
+ // (they differ only in base URL and auth), so one adapter handles all three;
14
+ // Anthropic's Messages API has a genuinely different shape (`tool_use` content
15
+ // blocks vs OpenAI's `tool_calls`) and gets its own.
16
+ export {};
@@ -0,0 +1,29 @@
1
+ import type { AIProviderAdapter, AIMessage } from './interfaces/ai-provider.js';
2
+ import type { AgentStreamEvent } from '../types/agent-stream.js';
3
+ import type { ContentAgentTool } from '../mcp/tools.js';
4
+ import type { AgentToolExecutionContext } from '../types/agent-tools.js';
5
+ export interface RunAgentTurnOptions {
6
+ aiProvider: AIProviderAdapter;
7
+ model: string;
8
+ messages: AIMessage[];
9
+ /** The caller's resolved tool list — see `resolveAgentTools` in `mcp/tools.ts`. */
10
+ tools: ContentAgentTool[];
11
+ toolContext: AgentToolExecutionContext;
12
+ /** Prepended ahead of `messages` on every model call within this turn, but never spliced
13
+ * into `messages` itself — it must stay out of the `done` event's `messages` (what the
14
+ * client persists and replays next turn), or a stale copy would get resent forever and an
15
+ * app-level prompt change would never reach an already-open conversation. */
16
+ systemPrompt?: string;
17
+ maxTokens?: number;
18
+ /** Safety cap on tool-calling round trips before the turn is force-stopped as an error. */
19
+ maxToolRoundtrips?: number;
20
+ signal?: AbortSignal;
21
+ }
22
+ /**
23
+ * Streams one agent turn: sends `messages` to the model, executes any tool calls it
24
+ * requests against `tools`, feeds the results back as `tool` messages, and repeats until
25
+ * the model stops calling tools (or `maxToolRoundtrips` is hit — surfaced as an error
26
+ * rather than looping forever against a model that won't stop calling tools).
27
+ */
28
+ export declare function runAgentTurn(opts: RunAgentTurnOptions): AsyncIterable<AgentStreamEvent>;
29
+ //# sourceMappingURL=run-agent-turn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-agent-turn.d.ts","sourceRoot":"","sources":["../../src/lib/ai/run-agent-turn.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACX,iBAAiB,EACjB,SAAS,EAGT,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAGtE,MAAM,WAAW,mBAAmB;IACnC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,mFAAmF;IACnF,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,WAAW,EAAE,yBAAyB,CAAC;IACvC;;;iFAG6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAYD;;;;;GAKG;AACH,wBAAuB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAuJ9F"}
@@ -0,0 +1,166 @@
1
+ // ai/run-agent-turn.ts
2
+ //
3
+ // The tool-calling loop that drives one agent turn to completion — the "runtime" half of sitting on top of the
4
+ // `AIProviderAdapter` port and the `ContentAgentTool` list `resolveAgentTools` (mcp/tools.ts)
5
+ // already resolves for MCP. Transport-agnostic: this function has no knowledge of HTTP/SSE —
6
+ // a route handler consumes the `AgentStreamEvent`s it yields and maps them onto the wire.
7
+ import { z } from 'zod';
8
+ import { hasCapability } from '../types/capabilities.js';
9
+ const DEFAULT_MAX_TOOL_ROUNDTRIPS = 8;
10
+ function toToolSpec(tool) {
11
+ return {
12
+ name: tool.definition.name,
13
+ description: tool.definition.description,
14
+ parameters: z.toJSONSchema(tool.definition.inputSchema)
15
+ };
16
+ }
17
+ /**
18
+ * Streams one agent turn: sends `messages` to the model, executes any tool calls it
19
+ * requests against `tools`, feeds the results back as `tool` messages, and repeats until
20
+ * the model stops calling tools (or `maxToolRoundtrips` is hit — surfaced as an error
21
+ * rather than looping forever against a model that won't stop calling tools).
22
+ */
23
+ export async function* runAgentTurn(opts) {
24
+ const messages = [...opts.messages];
25
+ const systemMessage = opts.systemPrompt
26
+ ? { role: 'system', content: opts.systemPrompt }
27
+ : null;
28
+ const toolsByName = new Map(opts.tools.map((t) => [t.definition.name, t]));
29
+ const toolSpecs = opts.tools.map(toToolSpec);
30
+ const maxRoundtrips = opts.maxToolRoundtrips ?? DEFAULT_MAX_TOOL_ROUNDTRIPS;
31
+ let roundtrips = 0;
32
+ for (;;) {
33
+ let assistantText = '';
34
+ const pendingToolCalls = [];
35
+ let finishReason = 'stop';
36
+ let erroredOut = false;
37
+ for await (const event of opts.aiProvider.chatStream({
38
+ model: opts.model,
39
+ messages: systemMessage ? [systemMessage, ...messages] : messages,
40
+ tools: toolSpecs,
41
+ maxTokens: opts.maxTokens,
42
+ signal: opts.signal
43
+ })) {
44
+ switch (event.type) {
45
+ case 'text':
46
+ assistantText += event.delta;
47
+ yield event;
48
+ break;
49
+ case 'toolCall':
50
+ pendingToolCalls.push(event.toolCall);
51
+ yield {
52
+ type: 'toolCall',
53
+ toolCallId: event.toolCall.id,
54
+ name: event.toolCall.name,
55
+ arguments: event.toolCall.arguments
56
+ };
57
+ break;
58
+ case 'usage':
59
+ yield event;
60
+ break;
61
+ case 'error':
62
+ yield event;
63
+ erroredOut = true;
64
+ break;
65
+ case 'done':
66
+ finishReason = event.finishReason;
67
+ break;
68
+ }
69
+ }
70
+ if (erroredOut) {
71
+ if (assistantText)
72
+ messages.push({ role: 'assistant', content: assistantText });
73
+ yield { type: 'done', finishReason: 'error', messages };
74
+ return;
75
+ }
76
+ if (finishReason !== 'tool_calls' || pendingToolCalls.length === 0) {
77
+ // Unlike the tool-calling branch below, nothing else pushes this round's assistant
78
+ // reply onto `messages` — this is the terminal round, so it must happen here or the
79
+ // model's final answer would be silently missing from the conversation `messages`
80
+ // hands back for the next turn to replay.
81
+ if (assistantText)
82
+ messages.push({ role: 'assistant', content: assistantText });
83
+ yield { type: 'done', finishReason, messages };
84
+ return;
85
+ }
86
+ if (++roundtrips > maxRoundtrips) {
87
+ yield { type: 'error', message: `Stopped after ${maxRoundtrips} tool-calling round trips.` };
88
+ yield { type: 'done', finishReason: 'error', messages };
89
+ return;
90
+ }
91
+ messages.push({ role: 'assistant', content: assistantText, toolCalls: pendingToolCalls });
92
+ // `execution: 'workspace'` tools touch a live, possibly-unsaved editor draft that only
93
+ // exists in the browser — this server-side loop can't run them. Every other call in the
94
+ // round still executes normally below; the workspace calls are set aside and, once the
95
+ // round finishes, pause the turn instead of looping — the caller resolves them locally
96
+ // and resumes with a fresh request (see `types/agent-stream.ts`'s `done` event doc).
97
+ const workspaceCalls = [];
98
+ const executableCalls = [];
99
+ for (const call of pendingToolCalls) {
100
+ const tool = toolsByName.get(call.name);
101
+ (tool?.definition.execution === 'workspace' ? workspaceCalls : executableCalls).push(call);
102
+ }
103
+ for (const call of executableCalls) {
104
+ const tool = toolsByName.get(call.name);
105
+ let success;
106
+ let data;
107
+ let error;
108
+ if (!tool) {
109
+ success = false;
110
+ error = `Unknown tool: ${call.name}`;
111
+ }
112
+ else {
113
+ // Defense in depth: `tools` is expected to already be filtered to this caller's
114
+ // capabilities (see `resolveAgentTools`), but a tool must reject direct invocation
115
+ // too — never rely on the advertisement filter alone (AgentToolDefinition's own
116
+ // doc comment on `requiredCapabilities` is explicit about this).
117
+ const requiredCaps = tool.definition.requiredCapabilities ?? [];
118
+ const auth = opts.toolContext.context.auth;
119
+ const authorized = requiredCaps.length === 0 ||
120
+ (auth != null && requiredCaps.every((c) => hasCapability(auth, c)));
121
+ if (!authorized) {
122
+ success = false;
123
+ error = `Forbidden: requires ${requiredCaps.join(', ')}`;
124
+ }
125
+ else {
126
+ const parsed = tool.definition.inputSchema.safeParse(call.arguments);
127
+ if (!parsed.success) {
128
+ success = false;
129
+ error = `Invalid arguments: ${parsed.error.message}`;
130
+ }
131
+ else {
132
+ try {
133
+ const result = await tool.execute(parsed.data, opts.toolContext);
134
+ success = result.success;
135
+ data = result.success ? result.data : undefined;
136
+ error = result.success ? undefined : result.error;
137
+ }
138
+ catch (err) {
139
+ success = false;
140
+ error = err instanceof Error ? err.message : String(err);
141
+ }
142
+ }
143
+ }
144
+ }
145
+ yield { type: 'toolResult', toolCallId: call.id, name: call.name, success, data, error };
146
+ messages.push({
147
+ role: 'tool',
148
+ toolCallId: call.id,
149
+ content: JSON.stringify(success ? (data ?? null) : { error })
150
+ });
151
+ }
152
+ if (workspaceCalls.length > 0) {
153
+ yield {
154
+ type: 'done',
155
+ finishReason: 'awaiting_workspace_tool',
156
+ messages,
157
+ pendingWorkspaceCalls: workspaceCalls.map((c) => ({
158
+ toolCallId: c.id,
159
+ name: c.name,
160
+ arguments: c.arguments
161
+ }))
162
+ };
163
+ return;
164
+ }
165
+ }
166
+ }
@@ -0,0 +1,27 @@
1
+ import type { ApiResponse } from './types.js';
2
+ import type { AgentChatRequest } from './schemas/agent-chat.js';
3
+ import type { RecordWorkspaceOperationRequest } from './schemas/agent-operations.js';
4
+ import type { AgentStreamEvent } from '../types/agent-stream.js';
5
+ /**
6
+ * Streams one leg of an agent turn. Not built on `apiClient` — that always `await`s and parses
7
+ * a JSON body, which is structurally incompatible with a chunked SSE response; this is the one
8
+ * agent-chat call that needs the raw `fetch` + `ReadableStream`. `signal` is caller-supplied
9
+ * (not `apiClient`'s own internal 10s timeout) so the chat panel's Stop button can abort
10
+ * mid-stream regardless of how long a turn runs.
11
+ *
12
+ * A turn that pauses for a workspace tool (`finishReason: 'awaiting_workspace_tool'`) ends this
13
+ * generator normally — resolving the pause and resuming is the caller's job (`AgentChat.svelte`
14
+ * re-calls this with the same `changeSetId` echoed back), not something this function loops on
15
+ * itself.
16
+ */
17
+ export declare function streamAgentChat(body: AgentChatRequest, signal?: AbortSignal): AsyncGenerator<AgentStreamEvent>;
18
+ /**
19
+ * Records an audit row for a workspace-bridge tool (`content_patch_fields`/`content_save_draft`)
20
+ * the client resolved locally against a live `DocumentWorkspace` — see
21
+ * `server/api/routes/agent-chat.ts`'s `POST /operations`. Plain JSON request/response, so unlike
22
+ * `streamAgentChat` above, this one goes through the shared `apiClient`.
23
+ */
24
+ export declare function recordWorkspaceOperation(body: RecordWorkspaceOperationRequest): Promise<ApiResponse<{
25
+ success: true;
26
+ }>>;
27
+ //# sourceMappingURL=agent-chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-chat.d.ts","sourceRoot":"","sources":["../../src/lib/api/agent-chat.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAY9D;;;;;;;;;;;GAWG;AACH,wBAAuB,eAAe,CACrC,IAAI,EAAE,gBAAgB,EACtB,MAAM,CAAC,EAAE,WAAW,GAClB,cAAc,CAAC,gBAAgB,CAAC,CA8BlC;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,+BAA+B,GACnC,OAAO,CAAC,WAAW,CAAC;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC,CAEzC"}
@@ -0,0 +1,64 @@
1
+ // Agent chat API client — the two HTTP calls AgentChat.svelte's send() loop makes, pulled out
2
+ // of the component per the same convention as api/documents.ts/api/assets.ts.
3
+ import { apiClient } from './client.js';
4
+ function parseSSEFrame(frame) {
5
+ const payload = frame
6
+ .split(/\r?\n/)
7
+ .filter((line) => line.startsWith('data:'))
8
+ .map((line) => line.slice(5).trimStart())
9
+ .join('\n');
10
+ if (!payload)
11
+ return null;
12
+ return JSON.parse(payload);
13
+ }
14
+ /**
15
+ * Streams one leg of an agent turn. Not built on `apiClient` — that always `await`s and parses
16
+ * a JSON body, which is structurally incompatible with a chunked SSE response; this is the one
17
+ * agent-chat call that needs the raw `fetch` + `ReadableStream`. `signal` is caller-supplied
18
+ * (not `apiClient`'s own internal 10s timeout) so the chat panel's Stop button can abort
19
+ * mid-stream regardless of how long a turn runs.
20
+ *
21
+ * A turn that pauses for a workspace tool (`finishReason: 'awaiting_workspace_tool'`) ends this
22
+ * generator normally — resolving the pause and resuming is the caller's job (`AgentChat.svelte`
23
+ * re-calls this with the same `changeSetId` echoed back), not something this function loops on
24
+ * itself.
25
+ */
26
+ export async function* streamAgentChat(body, signal) {
27
+ const response = await fetch('/api/agent/chat', {
28
+ method: 'POST',
29
+ headers: { 'Content-Type': 'application/json' },
30
+ body: JSON.stringify(body),
31
+ signal
32
+ });
33
+ if (!response.ok || !response.body) {
34
+ const errorBody = await response.json().catch(() => null);
35
+ throw new Error(errorBody?.error ?? `Request failed (${response.status})`);
36
+ }
37
+ const reader = response.body.getReader();
38
+ const decoder = new TextDecoder();
39
+ let buffer = '';
40
+ for (;;) {
41
+ const { done, value } = await reader.read();
42
+ buffer += decoder.decode(value, { stream: !done });
43
+ const frames = buffer.split(/\r?\n\r?\n/);
44
+ buffer = frames.pop() ?? '';
45
+ if (done && buffer.trim())
46
+ frames.push(buffer);
47
+ for (const frame of frames) {
48
+ const event = parseSSEFrame(frame);
49
+ if (event)
50
+ yield event;
51
+ }
52
+ if (done)
53
+ break;
54
+ }
55
+ }
56
+ /**
57
+ * Records an audit row for a workspace-bridge tool (`content_patch_fields`/`content_save_draft`)
58
+ * the client resolved locally against a live `DocumentWorkspace` — see
59
+ * `server/api/routes/agent-chat.ts`'s `POST /operations`. Plain JSON request/response, so unlike
60
+ * `streamAgentChat` above, this one goes through the shared `apiClient`.
61
+ */
62
+ export function recordWorkspaceOperation(body) {
63
+ return apiClient.post('/agent/operations', body);
64
+ }