feat(ai-chat): agent write tools, provenance wiring, chat panel + provider settings UI" -m "Backend:
- Add reversible write tools to the per-user agent toolset (page create/update/ move/soft-delete; comment reply + resolve), exposed under the user's JWT and enforced by Docmost CASL; no permanent/force delete (D3). - Non-spoofable agent provenance: sign actor/aiChatId into the access and collab tokens (TokenService), propagate via jwt.strategy onto the request, and set pages.last_updated_source/last_updated_ai_chat_id on REST create/update/move and comments.created_source/resolved_source/ai_chat_id. - packages/mcp: add an optional getCollabToken provider (content-edit provenance) and guard against empty tokens; service-account /mcp path unchanged. Frontend: - Admin 'AI / Models' settings section: provider/model/embedding/base URL, a write-only API key field, system prompt, and Test connection. - AI chat panel (useChat + DefaultChatTransport): conversation list, streamed messages, tool-call action log and page citations; header entry point gated on settings.ai.chat. Compile-verified (server nest build + client tsc/vite); not yet live-tested. Known gaps: history 'AI agent' badge (C3), vector RAG (D), external MCP (E); chat tool-card citation links pending a fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import api from "@/lib/api-client";
|
||||
|
||||
// Supported LLM providers/drivers.
|
||||
export type AiDriver = "openai" | "gemini" | "ollama";
|
||||
|
||||
// Masked AI provider settings returned by the server.
|
||||
// The API key is NEVER returned; only `hasApiKey` indicates whether one is stored.
|
||||
export interface IAiSettings {
|
||||
driver?: AiDriver;
|
||||
chatModel?: string;
|
||||
embeddingModel?: string;
|
||||
baseUrl?: string;
|
||||
systemPrompt?: string;
|
||||
hasApiKey: boolean;
|
||||
}
|
||||
|
||||
// Update payload. Key semantics:
|
||||
// - omit `apiKey` -> key unchanged
|
||||
// - `apiKey: ''` -> clear the stored key
|
||||
// - `apiKey: 'non-empty'`-> set the key
|
||||
// Non-secret fields are saved as given.
|
||||
export interface IAiSettingsUpdate {
|
||||
driver?: AiDriver;
|
||||
chatModel?: string;
|
||||
embeddingModel?: string;
|
||||
baseUrl?: string;
|
||||
systemPrompt?: string;
|
||||
apiKey?: string;
|
||||
}
|
||||
|
||||
// Result of a connection test against the configured provider.
|
||||
// The error string is already sanitized server-side.
|
||||
export interface IAiTestResult {
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export async function getAiSettings(): Promise<IAiSettings> {
|
||||
const req = await api.post<IAiSettings>("/workspace/ai-settings");
|
||||
return req.data;
|
||||
}
|
||||
|
||||
export async function updateAiSettings(
|
||||
data: IAiSettingsUpdate,
|
||||
): Promise<IAiSettings> {
|
||||
const req = await api.post<IAiSettings>("/workspace/ai-settings/update", data);
|
||||
return req.data;
|
||||
}
|
||||
|
||||
export async function testAiConnection(): Promise<IAiTestResult> {
|
||||
const req = await api.post<IAiTestResult>("/workspace/ai-settings/test");
|
||||
return req.data;
|
||||
}
|
||||
Reference in New Issue
Block a user