Add the assistant: a chat that drives the MCP tools in-process
Docs / docs (push) Successful in 42s
Playwright Tests / test-playwright (1, 2) (push) Failing after 2m42s
Playwright Tests / test-playwright (2, 2) (push) Failing after 10s
pre-commit / pre-commit (push) Failing after 2m33s
Test Backend / test-backend (push) Failing after 2m48s
Compose Smoke Test / test-compose (push) Failing after 9s
Playwright Tests / merge-reports (push) Failing after 2m17s

A provider set under Settings (OpenAI-compatible; key encrypted in
flow-data/ai.json) turns on an Assistant panel in the sidebar. Each turn runs
the FastMCP tools in-process as the person chatting, streams the rounds over
SSE and keeps one transcript per user. The panel floats on any screen and
shares the editor's lane: a settings panel keeps the top half, the chat the
bottom. The MCP client is now built once, for the endpoint and the chat.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-16 23:28:23 +02:00
co-authored by Claude Fable 5.1
parent d9630f66f5
commit cc4091166e
25 changed files with 1957 additions and 43 deletions
+209
View File
@@ -1,5 +1,128 @@
// This file is auto-generated by @hey-api/openapi-ts
export const AIConfigPublicSchema = {
properties: {
api_base: {
type: 'string',
title: 'Api Base'
},
model: {
type: 'string',
title: 'Model'
},
max_rounds: {
type: 'integer',
title: 'Max Rounds'
},
api_key_set: {
type: 'boolean',
title: 'Api Key Set'
},
api_key_masked: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Api Key Masked'
}
},
type: 'object',
required: ['api_base', 'model', 'max_rounds', 'api_key_set', 'api_key_masked'],
title: 'AIConfigPublic'
} as const;
export const AIConfigUpdateSchema = {
properties: {
api_base: {
type: 'string',
maxLength: 512,
minLength: 1,
title: 'Api Base'
},
api_key: {
anyOf: [
{
type: 'string',
maxLength: 512
},
{
type: 'null'
}
],
title: 'Api Key'
},
model: {
type: 'string',
maxLength: 128,
title: 'Model',
default: ''
},
max_rounds: {
type: 'integer',
maximum: 50,
minimum: 1,
title: 'Max Rounds',
default: 12
}
},
type: 'object',
required: ['api_base'],
title: 'AIConfigUpdate'
} as const;
export const AIModelsBodySchema = {
properties: {
api_base: {
type: 'string',
maxLength: 512,
minLength: 1,
title: 'Api Base'
},
api_key: {
anyOf: [
{
type: 'string',
maxLength: 512
},
{
type: 'null'
}
],
title: 'Api Key'
}
},
type: 'object',
required: ['api_base'],
title: 'AIModelsBody'
} as const;
export const AIStatusSchema = {
properties: {
available: {
type: 'boolean',
title: 'Available'
},
model: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Model'
}
},
type: 'object',
required: ['available', 'model'],
title: 'AIStatus'
} as const;
export const AlertsConfigSchema = {
properties: {
enabled: {
@@ -382,6 +505,66 @@ export const ChannelSchema = {
description: 'Somewhere to send an alert.'
} as const;
export const ChatItemSchema = {
properties: {
role: {
type: 'string',
title: 'Role'
},
content: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Content'
},
tool_calls: {
anyOf: [
{
items: {
additionalProperties: true,
type: 'object'
},
type: 'array'
},
{
type: 'null'
}
],
title: 'Tool Calls'
},
ok: {
anyOf: [
{
type: 'boolean'
},
{
type: 'null'
}
],
title: 'Ok'
},
error: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Error'
}
},
type: 'object',
required: ['role'],
title: 'ChatItem'
} as const;
export const DTypeSchema = {
type: 'string',
enum: ['float', 'int', 'str', 'bool', 'json', 'series', 'record', 'list', 'artifact', 'image', 'audio', 'video'],
@@ -3608,6 +3791,32 @@ export const TriggerRequestSchema = {
title: 'TriggerRequest'
} as const;
export const TurnBodySchema = {
properties: {
message: {
type: 'string',
maxLength: 20000,
minLength: 1,
title: 'Message'
},
flow: {
anyOf: [
{
type: 'string',
pattern: '^[a-z][a-z0-9_]*$'
},
{
type: 'null'
}
],
title: 'Flow'
}
},
type: 'object',
required: ['message'],
title: 'TurnBody'
} as const;
export const UnsubscribeSchema = {
properties: {
endpoint: {
File diff suppressed because one or more lines are too long
+68
View File
@@ -1,5 +1,30 @@
// This file is auto-generated by @hey-api/openapi-ts
export type AIConfigPublic = {
api_base: string;
model: string;
max_rounds: number;
api_key_set: boolean;
api_key_masked: (string | null);
};
export type AIConfigUpdate = {
api_base: string;
api_key?: (string | null);
model?: string;
max_rounds?: number;
};
export type AIModelsBody = {
api_base: string;
api_key?: (string | null);
};
export type AIStatus = {
available: boolean;
model: (string | null);
};
/**
* The whole alerting setup, as stored and as the API sees it.
*/
@@ -107,6 +132,16 @@ export type Channel = {
export type kind = 'ntfy' | 'smtp' | 'webhook' | 'dashboard' | 'webpush';
export type ChatItem = {
role: string;
content?: (string | null);
tool_calls?: (Array<{
[key: string]: unknown;
}> | null);
ok?: (boolean | null);
error?: (string | null);
};
/**
* A dashboard as stored, and as the API hands it over.
*/
@@ -1236,6 +1271,11 @@ export type TriggerRequest = {
};
};
export type TurnBody = {
message: string;
flow?: (string | null);
};
export type Unsubscribe = {
endpoint: string;
};
@@ -1401,6 +1441,34 @@ export type WorkerInfo = {
ram_mb?: (number | null);
};
export type AiReadAiConfigResponse = (AIConfigPublic);
export type AiUpdateAiConfigData = {
requestBody: AIConfigUpdate;
};
export type AiUpdateAiConfigResponse = (AIConfigPublic);
export type AiDeleteAiConfigResponse = (unknown);
export type AiListAiModelsData = {
requestBody: AIModelsBody;
};
export type AiListAiModelsResponse = (Array<(string)>);
export type AiReadAiStatusResponse = (AIStatus);
export type AiReadChatResponse = (Array<ChatItem>);
export type AiChatData = {
requestBody: TurnBody;
};
export type AiChatResponse = (unknown);
export type AiClearChatResponse = (Array<ChatItem>);
export type AlertsReadAlertsConfigResponse = (AlertsConfig);
export type AlertsSaveAlertsConfigData = {