@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.
- package/dist/agent-chat-state.svelte.d.ts +38 -0
- package/dist/agent-chat-state.svelte.d.ts.map +1 -0
- package/dist/agent-chat-state.svelte.js +86 -0
- package/dist/ai/content-workspace-tools.d.ts +3 -0
- package/dist/ai/content-workspace-tools.d.ts.map +1 -0
- package/dist/ai/content-workspace-tools.js +50 -0
- package/dist/ai/default-system-prompt.d.ts +2 -0
- package/dist/ai/default-system-prompt.d.ts.map +1 -0
- package/dist/ai/default-system-prompt.js +15 -0
- package/dist/ai/index.d.ts +2 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +4 -0
- package/dist/ai/interfaces/ai-provider.d.ts +67 -0
- package/dist/ai/interfaces/ai-provider.d.ts.map +1 -0
- package/dist/ai/interfaces/ai-provider.js +16 -0
- package/dist/ai/run-agent-turn.d.ts +29 -0
- package/dist/ai/run-agent-turn.d.ts.map +1 -0
- package/dist/ai/run-agent-turn.js +166 -0
- package/dist/api/agent-chat.d.ts +27 -0
- package/dist/api/agent-chat.d.ts.map +1 -0
- package/dist/api/agent-chat.js +64 -0
- package/dist/api/documents.d.ts +8 -3
- package/dist/api/documents.d.ts.map +1 -1
- package/dist/api/documents.js +6 -6
- package/dist/api/schemas/agent-chat.d.ts +45 -0
- package/dist/api/schemas/agent-chat.d.ts.map +1 -0
- package/dist/api/schemas/agent-chat.js +35 -0
- package/dist/api/schemas/agent-operations.d.ts +13 -0
- package/dist/api/schemas/agent-operations.d.ts.map +1 -0
- package/dist/api/schemas/agent-operations.js +15 -0
- package/dist/api/schemas/documents.d.ts +22 -0
- package/dist/api/schemas/documents.d.ts.map +1 -1
- package/dist/api/schemas/documents.js +20 -2
- package/dist/chunk-recovery.d.ts +33 -0
- package/dist/chunk-recovery.d.ts.map +1 -0
- package/dist/chunk-recovery.js +131 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/ui.d.ts +1 -0
- package/dist/client/ui.d.ts.map +1 -1
- package/dist/client/ui.js +1 -0
- package/dist/components/AdminApp.svelte +37 -3
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/ActivityView.svelte +251 -42
- package/dist/components/admin/ActivityView.svelte.d.ts.map +1 -1
- package/dist/components/admin/AgentChat.svelte +977 -0
- package/dist/components/admin/AgentChat.svelte.d.ts +17 -0
- package/dist/components/admin/AgentChat.svelte.d.ts.map +1 -0
- package/dist/components/admin/DocumentEditor.svelte +273 -60
- package/dist/components/admin/DocumentEditor.svelte.d.ts +6 -0
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/ObjectModal.svelte +4 -2
- package/dist/components/admin/fields/ArrayField.svelte +4 -1
- package/dist/components/admin/fields/ReferenceField.svelte +12 -1
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/layout/Sidebar.svelte +26 -2
- package/dist/components/layout/Sidebar.svelte.d.ts +1 -0
- package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -1
- package/dist/db/interfaces/agent-change-sets.d.ts +17 -0
- package/dist/db/interfaces/agent-change-sets.d.ts.map +1 -0
- package/dist/db/interfaces/agent-change-sets.js +1 -0
- package/dist/db/interfaces/document.d.ts +25 -3
- package/dist/db/interfaces/document.d.ts.map +1 -1
- package/dist/db/interfaces/document.js +19 -1
- package/dist/db/interfaces/index.d.ts +4 -1
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/index.js +1 -1
- package/dist/document-refresh.svelte.d.ts +2 -0
- package/dist/document-refresh.svelte.d.ts.map +1 -1
- package/dist/document-refresh.svelte.js +15 -0
- package/dist/document-workspace-registry.svelte.d.ts +15 -0
- package/dist/document-workspace-registry.svelte.d.ts.map +1 -0
- package/dist/document-workspace-registry.svelte.js +30 -0
- package/dist/field-validation/utils.d.ts.map +1 -1
- package/dist/field-validation/utils.js +211 -29
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +2 -0
- package/dist/lib/agent-chat-state.svelte.d.ts +38 -0
- package/dist/lib/agent-chat-state.svelte.d.ts.map +1 -0
- package/dist/lib/agent-chat-state.svelte.js +87 -0
- package/dist/lib/agent-chat-state.svelte.js.map +1 -0
- package/dist/lib/ai/content-workspace-tools.d.ts +3 -0
- package/dist/lib/ai/content-workspace-tools.d.ts.map +1 -0
- package/dist/lib/ai/content-workspace-tools.js +51 -0
- package/dist/lib/ai/content-workspace-tools.js.map +1 -0
- package/dist/lib/ai/default-system-prompt.d.ts +2 -0
- package/dist/lib/ai/default-system-prompt.d.ts.map +1 -0
- package/dist/lib/ai/default-system-prompt.js +16 -0
- package/dist/lib/ai/default-system-prompt.js.map +1 -0
- package/dist/lib/ai/index.d.ts +2 -0
- package/dist/lib/ai/index.d.ts.map +1 -0
- package/dist/lib/ai/index.js +5 -0
- package/dist/lib/ai/index.js.map +1 -0
- package/dist/lib/ai/interfaces/ai-provider.d.ts +67 -0
- package/dist/lib/ai/interfaces/ai-provider.d.ts.map +1 -0
- package/dist/lib/ai/interfaces/ai-provider.js +17 -0
- package/dist/lib/ai/interfaces/ai-provider.js.map +1 -0
- package/dist/lib/ai/run-agent-turn.d.ts +29 -0
- package/dist/lib/ai/run-agent-turn.d.ts.map +1 -0
- package/dist/lib/ai/run-agent-turn.js +167 -0
- package/dist/lib/ai/run-agent-turn.js.map +1 -0
- package/dist/lib/api/agent-chat.d.ts +27 -0
- package/dist/lib/api/agent-chat.d.ts.map +1 -0
- package/dist/lib/api/agent-chat.js +65 -0
- package/dist/lib/api/agent-chat.js.map +1 -0
- package/dist/lib/api/documents.d.ts +8 -3
- package/dist/lib/api/documents.d.ts.map +1 -1
- package/dist/lib/api/documents.js +6 -6
- package/dist/lib/api/documents.js.map +1 -1
- package/dist/lib/api/schemas/agent-chat.d.ts +45 -0
- package/dist/lib/api/schemas/agent-chat.d.ts.map +1 -0
- package/dist/lib/api/schemas/agent-chat.js +36 -0
- package/dist/lib/api/schemas/agent-chat.js.map +1 -0
- package/dist/lib/api/schemas/agent-operations.d.ts +13 -0
- package/dist/lib/api/schemas/agent-operations.d.ts.map +1 -0
- package/dist/lib/api/schemas/agent-operations.js +16 -0
- package/dist/lib/api/schemas/agent-operations.js.map +1 -0
- package/dist/lib/api/schemas/documents.d.ts +22 -0
- package/dist/lib/api/schemas/documents.d.ts.map +1 -1
- package/dist/lib/api/schemas/documents.js +20 -2
- package/dist/lib/api/schemas/documents.js.map +1 -1
- package/dist/lib/chunk-recovery.d.ts +33 -0
- package/dist/lib/chunk-recovery.d.ts.map +1 -0
- package/dist/lib/chunk-recovery.js +132 -0
- package/dist/lib/chunk-recovery.js.map +1 -0
- package/dist/lib/client/index.d.ts +1 -0
- package/dist/lib/client/index.d.ts.map +1 -1
- package/dist/lib/client/index.js +1 -0
- package/dist/lib/client/index.js.map +1 -1
- package/dist/lib/client/ui.d.ts +1 -0
- package/dist/lib/client/ui.d.ts.map +1 -1
- package/dist/lib/client/ui.js +1 -0
- package/dist/lib/client/ui.js.map +1 -1
- package/dist/lib/components/index.d.ts +1 -0
- package/dist/lib/components/index.d.ts.map +1 -1
- package/dist/lib/components/index.js +1 -0
- package/dist/lib/components/index.js.map +1 -1
- package/dist/lib/db/interfaces/agent-change-sets.d.ts +17 -0
- package/dist/lib/db/interfaces/agent-change-sets.d.ts.map +1 -0
- package/dist/lib/db/interfaces/agent-change-sets.js +2 -0
- package/dist/lib/db/interfaces/agent-change-sets.js.map +1 -0
- package/dist/lib/db/interfaces/document.d.ts +25 -3
- package/dist/lib/db/interfaces/document.d.ts.map +1 -1
- package/dist/lib/db/interfaces/document.js +19 -1
- package/dist/lib/db/interfaces/document.js.map +1 -1
- package/dist/lib/db/interfaces/index.d.ts +4 -1
- package/dist/lib/db/interfaces/index.d.ts.map +1 -1
- package/dist/lib/db/interfaces/index.js +1 -1
- package/dist/lib/db/interfaces/index.js.map +1 -1
- package/dist/lib/document-refresh.svelte.d.ts +2 -0
- package/dist/lib/document-refresh.svelte.d.ts.map +1 -1
- package/dist/lib/document-refresh.svelte.js +15 -0
- package/dist/lib/document-refresh.svelte.js.map +1 -1
- package/dist/lib/document-workspace-registry.svelte.d.ts +15 -0
- package/dist/lib/document-workspace-registry.svelte.d.ts.map +1 -0
- package/dist/lib/document-workspace-registry.svelte.js +31 -0
- package/dist/lib/document-workspace-registry.svelte.js.map +1 -0
- package/dist/lib/field-validation/utils.d.ts.map +1 -1
- package/dist/lib/field-validation/utils.js +211 -29
- package/dist/lib/field-validation/utils.js.map +1 -1
- package/dist/lib/hooks.d.ts +2 -0
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/hooks.js +2 -0
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/local-api/collection-api.d.ts +7 -2
- package/dist/lib/local-api/collection-api.d.ts.map +1 -1
- package/dist/lib/local-api/collection-api.js +17 -10
- package/dist/lib/local-api/collection-api.js.map +1 -1
- package/dist/lib/mcp/tools.d.ts +39 -4
- package/dist/lib/mcp/tools.d.ts.map +1 -1
- package/dist/lib/mcp/tools.js +546 -362
- package/dist/lib/mcp/tools.js.map +1 -1
- package/dist/lib/plugins/resolver.d.ts +8 -1
- package/dist/lib/plugins/resolver.d.ts.map +1 -1
- package/dist/lib/plugins/resolver.js +14 -1
- package/dist/lib/plugins/resolver.js.map +1 -1
- package/dist/lib/plugins/types.d.ts +23 -2
- package/dist/lib/plugins/types.d.ts.map +1 -1
- package/dist/lib/plugins/types.js.map +1 -1
- package/dist/lib/preview/stega.d.ts +2 -2
- package/dist/lib/preview/stega.d.ts.map +1 -1
- package/dist/lib/preview/stega.js +52 -29
- package/dist/lib/preview/stega.js.map +1 -1
- package/dist/lib/schema-utils/validator.d.ts.map +1 -1
- package/dist/lib/schema-utils/validator.js +5 -2
- package/dist/lib/schema-utils/validator.js.map +1 -1
- package/dist/lib/server/api/index.d.ts.map +1 -1
- package/dist/lib/server/api/index.js +8 -0
- package/dist/lib/server/api/index.js.map +1 -1
- package/dist/lib/server/api/routes/agent-change-sets.d.ts +4 -0
- package/dist/lib/server/api/routes/agent-change-sets.d.ts.map +1 -0
- package/dist/lib/server/api/routes/agent-change-sets.js +132 -0
- package/dist/lib/server/api/routes/agent-change-sets.js.map +1 -0
- package/dist/lib/server/api/routes/agent-chat.d.ts +14 -0
- package/dist/lib/server/api/routes/agent-chat.d.ts.map +1 -0
- package/dist/lib/server/api/routes/agent-chat.js +224 -0
- package/dist/lib/server/api/routes/agent-chat.js.map +1 -0
- package/dist/lib/server/api/routes/document-versions.d.ts.map +1 -1
- package/dist/lib/server/api/routes/document-versions.js +16 -2
- package/dist/lib/server/api/routes/document-versions.js.map +1 -1
- package/dist/lib/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents-by-id.js +11 -1
- package/dist/lib/server/api/routes/documents-by-id.js.map +1 -1
- package/dist/lib/server/api/routes/documents-publish.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents-publish.js +36 -3
- package/dist/lib/server/api/routes/documents-publish.js.map +1 -1
- package/dist/lib/server/api/routes/jobs.d.ts.map +1 -1
- package/dist/lib/server/api/routes/jobs.js +4 -2
- package/dist/lib/server/api/routes/jobs.js.map +1 -1
- package/dist/lib/server/api/routes/resolve-created-by.d.ts +13 -0
- package/dist/lib/server/api/routes/resolve-created-by.d.ts.map +1 -0
- package/dist/lib/server/api/routes/resolve-created-by.js +31 -0
- package/dist/lib/server/api/routes/resolve-created-by.js.map +1 -0
- package/dist/lib/server/index.d.ts +1 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +1 -0
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/services/version-service.d.ts +4 -4
- package/dist/lib/services/version-service.d.ts.map +1 -1
- package/dist/lib/services/version-service.js +15 -11
- package/dist/lib/services/version-service.js.map +1 -1
- package/dist/lib/type-gen.d.ts.map +1 -1
- package/dist/lib/type-gen.js +11 -0
- package/dist/lib/type-gen.js.map +1 -1
- package/dist/lib/types/agent-change-sets.d.ts +70 -0
- package/dist/lib/types/agent-change-sets.d.ts.map +1 -0
- package/dist/lib/types/agent-change-sets.js +7 -0
- package/dist/lib/types/agent-change-sets.js.map +1 -0
- package/dist/lib/types/agent-stream.d.ts +60 -0
- package/dist/lib/types/agent-stream.d.ts.map +1 -0
- package/dist/lib/types/agent-stream.js +12 -0
- package/dist/lib/types/agent-stream.js.map +1 -0
- package/dist/lib/types/agent-tools.d.ts +65 -0
- package/dist/lib/types/agent-tools.d.ts.map +1 -0
- package/dist/lib/types/agent-tools.js +2 -0
- package/dist/lib/types/agent-tools.js.map +1 -0
- package/dist/lib/types/config.d.ts +19 -0
- package/dist/lib/types/config.d.ts.map +1 -1
- package/dist/lib/types/document-workspace.d.ts +53 -0
- package/dist/lib/types/document-workspace.d.ts.map +1 -0
- package/dist/lib/types/document-workspace.js +15 -0
- package/dist/lib/types/document-workspace.js.map +1 -0
- package/dist/lib/types/document.d.ts +5 -0
- package/dist/lib/types/document.d.ts.map +1 -1
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js +2 -0
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/schemas.js +1 -1
- package/dist/lib/types/schemas.js.map +1 -1
- package/dist/lib/utils/fetch-remote-file.d.ts +11 -0
- package/dist/lib/utils/fetch-remote-file.d.ts.map +1 -0
- package/dist/lib/utils/fetch-remote-file.js +169 -0
- package/dist/lib/utils/fetch-remote-file.js.map +1 -0
- package/dist/local-api/collection-api.d.ts +7 -2
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +17 -10
- package/dist/mcp/tools.d.ts +39 -4
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +546 -362
- package/dist/plugins/resolver.d.ts +8 -1
- package/dist/plugins/resolver.d.ts.map +1 -1
- package/dist/plugins/resolver.js +14 -1
- package/dist/plugins/types.d.ts +23 -2
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/preview/stega.d.ts +2 -2
- package/dist/preview/stega.d.ts.map +1 -1
- package/dist/preview/stega.js +52 -29
- package/dist/schema-utils/validator.d.ts.map +1 -1
- package/dist/schema-utils/validator.js +5 -2
- package/dist/server/api/index.d.ts.map +1 -1
- package/dist/server/api/index.js +8 -0
- package/dist/server/api/routes/agent-change-sets.d.ts +4 -0
- package/dist/server/api/routes/agent-change-sets.d.ts.map +1 -0
- package/dist/server/api/routes/agent-change-sets.js +131 -0
- package/dist/server/api/routes/agent-chat.d.ts +14 -0
- package/dist/server/api/routes/agent-chat.d.ts.map +1 -0
- package/dist/server/api/routes/agent-chat.js +223 -0
- package/dist/server/api/routes/document-versions.d.ts.map +1 -1
- package/dist/server/api/routes/document-versions.js +16 -2
- package/dist/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/server/api/routes/documents-by-id.js +11 -1
- package/dist/server/api/routes/documents-publish.d.ts.map +1 -1
- package/dist/server/api/routes/documents-publish.js +36 -3
- package/dist/server/api/routes/jobs.d.ts.map +1 -1
- package/dist/server/api/routes/jobs.js +4 -2
- package/dist/server/api/routes/resolve-created-by.d.ts +13 -0
- package/dist/server/api/routes/resolve-created-by.d.ts.map +1 -0
- package/dist/server/api/routes/resolve-created-by.js +30 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/services/version-service.d.ts +4 -4
- package/dist/services/version-service.d.ts.map +1 -1
- package/dist/services/version-service.js +15 -11
- package/dist/type-gen.d.ts.map +1 -1
- package/dist/type-gen.js +11 -0
- package/dist/types/agent-change-sets.d.ts +70 -0
- package/dist/types/agent-change-sets.d.ts.map +1 -0
- package/dist/types/agent-change-sets.js +6 -0
- package/dist/types/agent-stream.d.ts +60 -0
- package/dist/types/agent-stream.d.ts.map +1 -0
- package/dist/types/agent-stream.js +11 -0
- package/dist/types/agent-tools.d.ts +65 -0
- package/dist/types/agent-tools.d.ts.map +1 -0
- package/dist/types/agent-tools.js +1 -0
- package/dist/types/config.d.ts +19 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/document-workspace.d.ts +53 -0
- package/dist/types/document-workspace.d.ts.map +1 -0
- package/dist/types/document-workspace.js +14 -0
- package/dist/types/document.d.ts +5 -0
- package/dist/types/document.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/schemas.js +1 -1
- package/dist/utils/fetch-remote-file.d.ts +11 -0
- package/dist/utils/fetch-remote-file.d.ts.map +1 -0
- package/dist/utils/fetch-remote-file.js +168 -0
- 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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/ai/index.ts"],"names":[],"mappings":"AAIA,cAAc,0BAA0B,CAAC"}
|
package/dist/ai/index.js
ADDED
|
@@ -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
|
+
}
|