@objectstack/service-ai 4.0.0 → 4.0.2

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 (40) hide show
  1. package/.turbo/turbo-build.log +11 -11
  2. package/CHANGELOG.md +20 -0
  3. package/dist/index.cjs +1245 -54
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +344 -77
  6. package/dist/index.d.ts +344 -77
  7. package/dist/index.js +1230 -51
  8. package/dist/index.js.map +1 -1
  9. package/package.json +26 -4
  10. package/src/__tests__/ai-service.test.ts +248 -27
  11. package/src/__tests__/auth-and-toolcalling.test.ts +627 -0
  12. package/src/__tests__/chatbot-features.test.ts +229 -82
  13. package/src/__tests__/metadata-tools.test.ts +964 -0
  14. package/src/__tests__/objectql-conversation-service.test.ts +34 -16
  15. package/src/__tests__/vercel-stream-encoder.test.ts +263 -0
  16. package/src/adapters/index.ts +2 -0
  17. package/src/adapters/memory-adapter.ts +17 -9
  18. package/src/adapters/vercel-adapter.ts +148 -0
  19. package/src/agent-runtime.ts +27 -3
  20. package/src/agents/index.ts +1 -0
  21. package/src/agents/metadata-assistant-agent.ts +87 -0
  22. package/src/ai-service.ts +174 -22
  23. package/src/conversation/in-memory-conversation-service.ts +2 -2
  24. package/src/conversation/objectql-conversation-service.ts +67 -18
  25. package/src/index.ts +22 -3
  26. package/src/plugin.ts +166 -9
  27. package/src/routes/agent-routes.ts +28 -3
  28. package/src/routes/ai-routes.ts +231 -14
  29. package/src/routes/index.ts +1 -1
  30. package/src/stream/index.ts +3 -0
  31. package/src/stream/vercel-stream-encoder.ts +129 -0
  32. package/src/tools/add-field.tool.ts +70 -0
  33. package/src/tools/create-object.tool.ts +66 -0
  34. package/src/tools/delete-field.tool.ts +38 -0
  35. package/src/tools/describe-metadata-object.tool.ts +32 -0
  36. package/src/tools/index.ts +12 -1
  37. package/src/tools/list-metadata-objects.tool.ts +34 -0
  38. package/src/tools/metadata-tools.ts +430 -0
  39. package/src/tools/modify-field.tool.ts +44 -0
  40. package/src/tools/tool-registry.ts +32 -9
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
- import { AIToolDefinition, AIToolCall, AIToolResult, IAIService, IAIConversationService, LLMAdapter, Logger, AIMessage, AIRequestOptions, AIResult, AIStreamEvent, ChatWithToolsOptions, AIConversation, IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
1
+ import { AIToolDefinition, ToolCallPart, ToolResultPart, IAIService, IAIConversationService, LLMAdapter, Logger, ModelMessage, AIRequestOptions, AIResult, TextStreamPart, ToolSet, ChatWithToolsOptions, AIConversation, IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
2
2
  export { LLMAdapter } from '@objectstack/spec/contracts';
3
3
  import { Plugin, PluginContext } from '@objectstack/core';
4
+ import { LanguageModelV2 } from '@ai-sdk/provider';
5
+ import { TextStreamPart as TextStreamPart$1, ToolSet as ToolSet$1 } from 'ai';
6
+ import { Tool } from '@objectstack/spec/ai';
4
7
  import { Agent } from '@objectstack/spec';
5
8
  import { z } from 'zod';
6
9
  import * as _objectstack_spec_data from '@objectstack/spec/data';
@@ -11,6 +14,13 @@ import * as _objectstack_spec_data from '@objectstack/spec/data';
11
14
  * Receives parsed arguments and returns the tool output as a string.
12
15
  */
13
16
  type ToolHandler = (args: Record<string, unknown>) => Promise<string> | string;
17
+ /**
18
+ * Extended ToolResultPart that carries an `isError` flag for internal
19
+ * error-tracking in the tool-call loop.
20
+ */
21
+ interface ToolExecutionResult extends ToolResultPart {
22
+ isError?: boolean;
23
+ }
14
24
  /**
15
25
  * ToolRegistry — Central registry for AI-callable tools.
16
26
  *
@@ -50,11 +60,11 @@ declare class ToolRegistry {
50
60
  /**
51
61
  * Execute a tool call and return the result.
52
62
  */
53
- execute(toolCall: AIToolCall): Promise<AIToolResult>;
63
+ execute(toolCall: ToolCallPart): Promise<ToolExecutionResult>;
54
64
  /**
55
65
  * Execute multiple tool calls in parallel.
56
66
  */
57
- executeAll(toolCalls: AIToolCall[]): Promise<AIToolResult[]>;
67
+ executeAll(toolCalls: ToolCallPart[]): Promise<ToolExecutionResult[]>;
58
68
  /**
59
69
  * Clear all registered tools.
60
70
  */
@@ -97,13 +107,15 @@ declare class AIService implements IAIService {
97
107
  constructor(config?: AIServiceConfig);
98
108
  /** The name of the active LLM adapter. */
99
109
  get adapterName(): string;
100
- chat(messages: AIMessage[], options?: AIRequestOptions): Promise<AIResult>;
110
+ chat(messages: ModelMessage[], options?: AIRequestOptions): Promise<AIResult>;
101
111
  complete(prompt: string, options?: AIRequestOptions): Promise<AIResult>;
102
- streamChat(messages: AIMessage[], options?: AIRequestOptions): AsyncIterable<AIStreamEvent>;
112
+ streamChat(messages: ModelMessage[], options?: AIRequestOptions): AsyncIterable<TextStreamPart<ToolSet>>;
103
113
  embed(input: string | string[], model?: string): Promise<number[][]>;
104
114
  listModels(): Promise<string[]>;
105
115
  /** Default maximum iterations for the tool call loop. */
106
116
  static readonly DEFAULT_MAX_ITERATIONS = 10;
117
+ /** Extract the text value from a ToolExecutionResult's output. */
118
+ private static extractOutputText;
107
119
  /**
108
120
  * Chat with automatic tool call resolution.
109
121
  *
@@ -115,7 +127,15 @@ declare class AIService implements IAIService {
115
127
  * 4. Repeats until the model produces a final text response or the
116
128
  * maximum number of iterations (`maxIterations`) is reached.
117
129
  */
118
- chatWithTools(messages: AIMessage[], options?: ChatWithToolsOptions): Promise<AIResult>;
130
+ chatWithTools(messages: ModelMessage[], options?: ChatWithToolsOptions): Promise<AIResult>;
131
+ /**
132
+ * Stream chat with automatic tool call resolution.
133
+ *
134
+ * Works like {@link chatWithTools} but yields SSE events. When the model
135
+ * requests tool calls during streaming, they are executed and the results
136
+ * fed back until a final text stream is produced.
137
+ */
138
+ streamChatWithTools(messages: ModelMessage[], options?: ChatWithToolsOptions): AsyncIterable<TextStreamPart<ToolSet>>;
119
139
  }
120
140
 
121
141
  /**
@@ -160,6 +180,19 @@ declare class AIServicePlugin implements Plugin {
160
180
  private service?;
161
181
  private readonly options;
162
182
  constructor(options?: AIServicePluginOptions);
183
+ /**
184
+ * Auto-detect LLM provider from environment variables.
185
+ *
186
+ * Priority order:
187
+ * 1. AI_GATEWAY_MODEL → Vercel AI Gateway
188
+ * 2. OPENAI_API_KEY → OpenAI
189
+ * 3. ANTHROPIC_API_KEY → Anthropic
190
+ * 4. GOOGLE_GENERATIVE_AI_API_KEY → Google
191
+ * 5. Fallback → MemoryLLMAdapter
192
+ *
193
+ * Returns the adapter and a description for logging.
194
+ */
195
+ private detectAdapter;
163
196
  init(ctx: PluginContext): Promise<void>;
164
197
  start(ctx: PluginContext): Promise<void>;
165
198
  destroy(): Promise<void>;
@@ -173,13 +206,81 @@ declare class AIServicePlugin implements Plugin {
173
206
  */
174
207
  declare class MemoryLLMAdapter implements LLMAdapter {
175
208
  readonly name = "memory";
176
- chat(messages: AIMessage[], options?: AIRequestOptions): Promise<AIResult>;
209
+ chat(messages: ModelMessage[], options?: AIRequestOptions): Promise<AIResult>;
177
210
  complete(prompt: string, options?: AIRequestOptions): Promise<AIResult>;
178
- streamChat(messages: AIMessage[], _options?: AIRequestOptions): AsyncIterable<AIStreamEvent>;
211
+ streamChat(messages: ModelMessage[], _options?: AIRequestOptions): AsyncIterable<TextStreamPart<ToolSet>>;
179
212
  embed(input: string | string[]): Promise<number[][]>;
180
213
  listModels(): Promise<string[]>;
181
214
  }
182
215
 
216
+ /**
217
+ * VercelLLMAdapter — Production LLM adapter powered by the Vercel AI SDK.
218
+ *
219
+ * Wraps `generateText` / `streamText` from the `ai` package, delegating to
220
+ * any Vercel AI SDK–compatible model provider (OpenAI, Anthropic, Google,
221
+ * Ollama, etc.).
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * import { openai } from '@ai-sdk/openai';
226
+ * import { VercelLLMAdapter } from '@objectstack/service-ai';
227
+ *
228
+ * const adapter = new VercelLLMAdapter({ model: openai('gpt-4o') });
229
+ * ```
230
+ */
231
+ declare class VercelLLMAdapter implements LLMAdapter {
232
+ readonly name = "vercel";
233
+ private readonly model;
234
+ constructor(config: VercelLLMAdapterConfig);
235
+ chat(messages: ModelMessage[], options?: AIRequestOptions): Promise<AIResult>;
236
+ complete(prompt: string, options?: AIRequestOptions): Promise<AIResult>;
237
+ streamChat(messages: ModelMessage[], options?: AIRequestOptions): AsyncIterable<TextStreamPart<ToolSet>>;
238
+ embed(_input: string | string[]): Promise<number[][]>;
239
+ listModels(): Promise<string[]>;
240
+ }
241
+ /**
242
+ * Configuration for the Vercel LLM adapter.
243
+ */
244
+ interface VercelLLMAdapterConfig {
245
+ /**
246
+ * A Vercel AI SDK–compatible language model instance.
247
+ *
248
+ * @example `openai('gpt-4o')` or `anthropic('claude-sonnet-4-20250514')`
249
+ */
250
+ model: LanguageModelV2;
251
+ }
252
+
253
+ /**
254
+ * Vercel AI SDK v6 — UI Message Stream Encoder
255
+ *
256
+ * Converts `AsyncIterable<TextStreamPart<ToolSet>>` (the internal ObjectStack
257
+ * streaming format) into the Vercel AI SDK v6 **UI Message Stream Protocol**.
258
+ *
259
+ * Wire format: Server-Sent Events (SSE) with JSON payloads.
260
+ * `data: {"type":"text-delta","id":"0","delta":"Hello"}\n\n`
261
+ *
262
+ * The client-side `DefaultChatTransport` from `ai` v6 uses
263
+ * `parseJsonEventStream` to parse these SSE events.
264
+ *
265
+ * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol
266
+ */
267
+
268
+ /**
269
+ * Encode a single `TextStreamPart` event into SSE-formatted UI Message
270
+ * Stream chunk(s).
271
+ *
272
+ * Returns an empty string for event types that have no wire-format mapping.
273
+ */
274
+ declare function encodeStreamPart(part: TextStreamPart$1<ToolSet$1>): string;
275
+ /**
276
+ * Transform an `AsyncIterable<TextStreamPart>` into an `AsyncIterable<string>`
277
+ * where each yielded string is an SSE-formatted UI Message Stream chunk.
278
+ *
279
+ * Lifecycle order required by the client:
280
+ * start → start-step → text-start → text-delta* → text-end → finish-step → finish → [DONE]
281
+ */
282
+ declare function encodeVercelDataStream(events: AsyncIterable<TextStreamPart$1<ToolSet$1>>): AsyncIterable<string>;
283
+
183
284
  /**
184
285
  * InMemoryConversationService — Reference implementation of IAIConversationService.
185
286
  *
@@ -203,7 +304,7 @@ declare class InMemoryConversationService implements IAIConversationService {
203
304
  limit?: number;
204
305
  cursor?: string;
205
306
  }): Promise<AIConversation[]>;
206
- addMessage(conversationId: string, message: AIMessage): Promise<AIConversation>;
307
+ addMessage(conversationId: string, message: ModelMessage): Promise<AIConversation>;
207
308
  delete(conversationId: string): Promise<void>;
208
309
  /** Total number of stored conversations. */
209
310
  get size(): number;
@@ -237,7 +338,7 @@ declare class ObjectQLConversationService implements IAIConversationService {
237
338
  limit?: number;
238
339
  cursor?: string;
239
340
  }): Promise<AIConversation[]>;
240
- addMessage(conversationId: string, message: AIMessage): Promise<AIConversation>;
341
+ addMessage(conversationId: string, message: ModelMessage): Promise<AIConversation>;
241
342
  delete(conversationId: string): Promise<void>;
242
343
  /**
243
344
  * Safely parse a JSON string, returning `undefined` on failure.
@@ -248,7 +349,7 @@ declare class ObjectQLConversationService implements IAIConversationService {
248
349
  */
249
350
  private toConversation;
250
351
  /**
251
- * Map a database row to an AIMessage.
352
+ * Map a database row to a ModelMessage.
252
353
  */
253
354
  private toMessage;
254
355
  }
@@ -284,6 +385,158 @@ declare const DATA_TOOL_DEFINITIONS: AIToolDefinition[];
284
385
  */
285
386
  declare function registerDataTools(registry: ToolRegistry, context: DataToolContext): void;
286
387
 
388
+ /**
389
+ * create_object — AI Tool Metadata
390
+ *
391
+ * Creates a new data object (table) with schema validation.
392
+ * Validates snake_case naming for object and initial fields,
393
+ * checks for duplicates, and registers the object definition.
394
+ */
395
+ declare const createObjectTool: {
396
+ name: string;
397
+ label: string;
398
+ description: string;
399
+ parameters: Record<string, unknown>;
400
+ requiresConfirmation: boolean;
401
+ active: boolean;
402
+ builtIn: boolean;
403
+ category?: "flow" | "action" | "vector_search" | "data" | "utility" | "integration" | "analytics" | undefined;
404
+ outputSchema?: Record<string, unknown> | undefined;
405
+ objectName?: string | undefined;
406
+ permissions?: string[] | undefined;
407
+ };
408
+
409
+ /**
410
+ * add_field — AI Tool Metadata
411
+ *
412
+ * Adds a new field (column) to an existing data object.
413
+ * Validates snake_case for objectName, field name, reference,
414
+ * and select option values before merging into the definition.
415
+ */
416
+ declare const addFieldTool: {
417
+ name: string;
418
+ label: string;
419
+ description: string;
420
+ parameters: Record<string, unknown>;
421
+ requiresConfirmation: boolean;
422
+ active: boolean;
423
+ builtIn: boolean;
424
+ category?: "flow" | "action" | "vector_search" | "data" | "utility" | "integration" | "analytics" | undefined;
425
+ outputSchema?: Record<string, unknown> | undefined;
426
+ objectName?: string | undefined;
427
+ permissions?: string[] | undefined;
428
+ };
429
+
430
+ /**
431
+ * modify_field — AI Tool Metadata
432
+ *
433
+ * Modifies an existing field definition (label, type, required, default value, etc.)
434
+ * on a data object. Does not support renaming the field.
435
+ */
436
+ declare const modifyFieldTool: {
437
+ name: string;
438
+ label: string;
439
+ description: string;
440
+ parameters: Record<string, unknown>;
441
+ requiresConfirmation: boolean;
442
+ active: boolean;
443
+ builtIn: boolean;
444
+ category?: "flow" | "action" | "vector_search" | "data" | "utility" | "integration" | "analytics" | undefined;
445
+ outputSchema?: Record<string, unknown> | undefined;
446
+ objectName?: string | undefined;
447
+ permissions?: string[] | undefined;
448
+ };
449
+
450
+ /**
451
+ * delete_field — AI Tool Metadata
452
+ *
453
+ * Removes a field (column) from an existing data object.
454
+ * This is a destructive operation.
455
+ */
456
+ declare const deleteFieldTool: {
457
+ name: string;
458
+ label: string;
459
+ description: string;
460
+ parameters: Record<string, unknown>;
461
+ requiresConfirmation: boolean;
462
+ active: boolean;
463
+ builtIn: boolean;
464
+ category?: "flow" | "action" | "vector_search" | "data" | "utility" | "integration" | "analytics" | undefined;
465
+ outputSchema?: Record<string, unknown> | undefined;
466
+ objectName?: string | undefined;
467
+ permissions?: string[] | undefined;
468
+ };
469
+
470
+ /**
471
+ * list_metadata_objects — AI Tool Metadata
472
+ *
473
+ * Lists all registered metadata objects (tables) with optional filtering.
474
+ * Uses a unique name (`list_metadata_objects`) to avoid collision with
475
+ * the data-tools `list_objects` tool.
476
+ */
477
+ declare const listMetadataObjectsTool: {
478
+ name: string;
479
+ label: string;
480
+ description: string;
481
+ parameters: Record<string, unknown>;
482
+ requiresConfirmation: boolean;
483
+ active: boolean;
484
+ builtIn: boolean;
485
+ category?: "flow" | "action" | "vector_search" | "data" | "utility" | "integration" | "analytics" | undefined;
486
+ outputSchema?: Record<string, unknown> | undefined;
487
+ objectName?: string | undefined;
488
+ permissions?: string[] | undefined;
489
+ };
490
+
491
+ /**
492
+ * describe_metadata_object — AI Tool Metadata
493
+ *
494
+ * Returns the full metadata schema of a data object including all
495
+ * fields, types, relationships, and configuration. Uses a unique name
496
+ * (`describe_metadata_object`) to avoid collision with the data-tools
497
+ * `describe_object` tool.
498
+ */
499
+ declare const describeMetadataObjectTool: {
500
+ name: string;
501
+ label: string;
502
+ description: string;
503
+ parameters: Record<string, unknown>;
504
+ requiresConfirmation: boolean;
505
+ active: boolean;
506
+ builtIn: boolean;
507
+ category?: "flow" | "action" | "vector_search" | "data" | "utility" | "integration" | "analytics" | undefined;
508
+ outputSchema?: Record<string, unknown> | undefined;
509
+ objectName?: string | undefined;
510
+ permissions?: string[] | undefined;
511
+ };
512
+
513
+ /** All built-in metadata management tool definitions (Tool metadata). */
514
+ declare const METADATA_TOOL_DEFINITIONS: Tool[];
515
+ /**
516
+ * Services required by the metadata management tools.
517
+ *
518
+ * Provided by the kernel at `ai:ready` time and closed over
519
+ * by the handler functions so they stay framework-agnostic.
520
+ */
521
+ interface MetadataToolContext {
522
+ /** Metadata service for schema CRUD operations. */
523
+ metadataService: IMetadataService;
524
+ }
525
+ /**
526
+ * Register all built-in metadata management tools on the given {@link ToolRegistry}.
527
+ *
528
+ * Typically called from the `ai:ready` hook after the metadata service is available.
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * ctx.hook('ai:ready', async (aiService) => {
533
+ * const metadataService = ctx.getService<IMetadataService>('metadata');
534
+ * registerMetadataTools(aiService.toolRegistry, { metadataService });
535
+ * });
536
+ * ```
537
+ */
538
+ declare function registerMetadataTools(registry: ToolRegistry, context: MetadataToolContext): void;
539
+
287
540
  /**
288
541
  * Context passed alongside a user message when chatting with an agent.
289
542
  *
@@ -312,6 +565,17 @@ interface AgentChatContext {
312
565
  declare class AgentRuntime {
313
566
  private readonly metadataService;
314
567
  constructor(metadataService: IMetadataService);
568
+ /**
569
+ * List all active agents registered in the metadata service.
570
+ *
571
+ * Returns a summary for each agent (name, label, role) suitable
572
+ * for populating an agent selector dropdown in the UI.
573
+ */
574
+ listAgents(): Promise<Array<{
575
+ name: string;
576
+ label: string;
577
+ role: string;
578
+ }>>;
315
579
  /**
316
580
  * Load and validate an agent definition by name.
317
581
  *
@@ -325,7 +589,7 @@ declare class AgentRuntime {
325
589
  * Build the system message(s) that should be prepended to the
326
590
  * conversation when chatting with the given agent.
327
591
  */
328
- buildSystemMessages(agent: Agent, context?: AgentChatContext): AIMessage[];
592
+ buildSystemMessages(agent: Agent, context?: AgentChatContext): ModelMessage[];
329
593
  /**
330
594
  * Derive {@link AIRequestOptions} from an agent definition.
331
595
  *
@@ -360,6 +624,27 @@ declare class AgentRuntime {
360
624
  */
361
625
  declare const DATA_CHAT_AGENT: Agent;
362
626
 
627
+ /**
628
+ * Built-in `metadata_assistant` agent definition.
629
+ *
630
+ * This agent powers AI-driven metadata management — users can create objects,
631
+ * add/modify/delete fields, and inspect schema definitions through natural
632
+ * language conversation.
633
+ *
634
+ * It is registered automatically by the AI service plugin alongside the
635
+ * `data_chat` agent when the metadata service is available.
636
+ *
637
+ * @example
638
+ * ```
639
+ * POST /api/v1/ai/agents/metadata_assistant/chat
640
+ * {
641
+ * "messages": [{ "role": "user", "content": "Create a contracts table with name, value, and status fields" }],
642
+ * "context": {}
643
+ * }
644
+ * ```
645
+ */
646
+ declare const METADATA_ASSISTANT_AGENT: Agent;
647
+
363
648
  /**
364
649
  * XState-inspired State Machine Protocol
365
650
  * Used to define strict business logic constraints and lifecycle management.
@@ -423,7 +708,7 @@ declare const AiConversationObject: Omit<{
423
708
  abstract: boolean;
424
709
  datasource: string;
425
710
  fields: Record<string, {
426
- type: "number" | "boolean" | "file" | "json" | "text" | "avatar" | "vector" | "date" | "tags" | "lookup" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "datetime" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "code" | "color" | "rating" | "slider" | "signature" | "qrcode" | "progress";
711
+ type: "number" | "boolean" | "file" | "text" | "json" | "code" | "avatar" | "vector" | "date" | "tags" | "lookup" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "datetime" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "signature" | "qrcode" | "progress";
427
712
  required: boolean;
428
713
  searchable: boolean;
429
714
  multiple: boolean;
@@ -607,7 +892,7 @@ declare const AiConversationObject: Omit<{
607
892
  } | undefined;
608
893
  versioning?: {
609
894
  enabled: boolean;
610
- strategy: "snapshot" | "delta" | "event-sourcing";
895
+ strategy: "delta" | "snapshot" | "event-sourcing";
611
896
  versionField: string;
612
897
  retentionDays?: number | undefined;
613
898
  } | undefined;
@@ -683,11 +968,7 @@ declare const AiConversationObject: Omit<{
683
968
  keyPrefix?: string | undefined;
684
969
  actions?: {
685
970
  name: string;
686
- label: string | {
687
- key: string;
688
- defaultValue?: string | undefined;
689
- params?: Record<string, string | number | boolean> | undefined;
690
- };
971
+ label: string;
691
972
  type: "url" | "script" | "modal" | "flow" | "api";
692
973
  refreshAfter: boolean;
693
974
  objectName?: string | undefined;
@@ -698,44 +979,24 @@ declare const AiConversationObject: Omit<{
698
979
  execute?: string | undefined;
699
980
  params?: {
700
981
  name: string;
701
- label: string | {
702
- key: string;
703
- defaultValue?: string | undefined;
704
- params?: Record<string, string | number | boolean> | undefined;
705
- };
982
+ label: string;
706
983
  type: "number" | "boolean" | "date" | "lookup" | "file" | "url" | "json" | "text" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "datetime" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "master_detail" | "tree" | "image" | "avatar" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "code" | "color" | "rating" | "slider" | "signature" | "qrcode" | "progress" | "tags" | "vector";
707
984
  required: boolean;
708
985
  options?: {
709
- label: string | {
710
- key: string;
711
- defaultValue?: string | undefined;
712
- params?: Record<string, string | number | boolean> | undefined;
713
- };
986
+ label: string;
714
987
  value: string;
715
988
  }[] | undefined;
716
989
  }[] | undefined;
717
990
  variant?: "link" | "primary" | "secondary" | "danger" | "ghost" | undefined;
718
- confirmText?: string | {
719
- key: string;
720
- defaultValue?: string | undefined;
721
- params?: Record<string, string | number | boolean> | undefined;
722
- } | undefined;
723
- successMessage?: string | {
724
- key: string;
725
- defaultValue?: string | undefined;
726
- params?: Record<string, string | number | boolean> | undefined;
727
- } | undefined;
991
+ confirmText?: string | undefined;
992
+ successMessage?: string | undefined;
728
993
  visible?: string | undefined;
729
994
  disabled?: string | boolean | undefined;
730
995
  shortcut?: string | undefined;
731
996
  bulkEnabled?: boolean | undefined;
732
997
  timeout?: number | undefined;
733
998
  aria?: {
734
- ariaLabel?: string | {
735
- key: string;
736
- defaultValue?: string | undefined;
737
- params?: Record<string, string | number | boolean> | undefined;
738
- } | undefined;
999
+ ariaLabel?: string | undefined;
739
1000
  ariaDescribedBy?: string | undefined;
740
1001
  role?: string | undefined;
741
1002
  } | undefined;
@@ -1888,7 +2149,7 @@ declare const AiMessageObject: Omit<{
1888
2149
  abstract: boolean;
1889
2150
  datasource: string;
1890
2151
  fields: Record<string, {
1891
- type: "number" | "boolean" | "file" | "json" | "text" | "avatar" | "vector" | "date" | "tags" | "lookup" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "datetime" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "code" | "color" | "rating" | "slider" | "signature" | "qrcode" | "progress";
2152
+ type: "number" | "boolean" | "file" | "text" | "json" | "code" | "avatar" | "vector" | "date" | "tags" | "lookup" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "datetime" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "signature" | "qrcode" | "progress";
1892
2153
  required: boolean;
1893
2154
  searchable: boolean;
1894
2155
  multiple: boolean;
@@ -2072,7 +2333,7 @@ declare const AiMessageObject: Omit<{
2072
2333
  } | undefined;
2073
2334
  versioning?: {
2074
2335
  enabled: boolean;
2075
- strategy: "snapshot" | "delta" | "event-sourcing";
2336
+ strategy: "delta" | "snapshot" | "event-sourcing";
2076
2337
  versionField: string;
2077
2338
  retentionDays?: number | undefined;
2078
2339
  } | undefined;
@@ -2148,11 +2409,7 @@ declare const AiMessageObject: Omit<{
2148
2409
  keyPrefix?: string | undefined;
2149
2410
  actions?: {
2150
2411
  name: string;
2151
- label: string | {
2152
- key: string;
2153
- defaultValue?: string | undefined;
2154
- params?: Record<string, string | number | boolean> | undefined;
2155
- };
2412
+ label: string;
2156
2413
  type: "url" | "script" | "modal" | "flow" | "api";
2157
2414
  refreshAfter: boolean;
2158
2415
  objectName?: string | undefined;
@@ -2163,44 +2420,24 @@ declare const AiMessageObject: Omit<{
2163
2420
  execute?: string | undefined;
2164
2421
  params?: {
2165
2422
  name: string;
2166
- label: string | {
2167
- key: string;
2168
- defaultValue?: string | undefined;
2169
- params?: Record<string, string | number | boolean> | undefined;
2170
- };
2423
+ label: string;
2171
2424
  type: "number" | "boolean" | "date" | "lookup" | "file" | "url" | "json" | "text" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "datetime" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "master_detail" | "tree" | "image" | "avatar" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "code" | "color" | "rating" | "slider" | "signature" | "qrcode" | "progress" | "tags" | "vector";
2172
2425
  required: boolean;
2173
2426
  options?: {
2174
- label: string | {
2175
- key: string;
2176
- defaultValue?: string | undefined;
2177
- params?: Record<string, string | number | boolean> | undefined;
2178
- };
2427
+ label: string;
2179
2428
  value: string;
2180
2429
  }[] | undefined;
2181
2430
  }[] | undefined;
2182
2431
  variant?: "link" | "primary" | "secondary" | "danger" | "ghost" | undefined;
2183
- confirmText?: string | {
2184
- key: string;
2185
- defaultValue?: string | undefined;
2186
- params?: Record<string, string | number | boolean> | undefined;
2187
- } | undefined;
2188
- successMessage?: string | {
2189
- key: string;
2190
- defaultValue?: string | undefined;
2191
- params?: Record<string, string | number | boolean> | undefined;
2192
- } | undefined;
2432
+ confirmText?: string | undefined;
2433
+ successMessage?: string | undefined;
2193
2434
  visible?: string | undefined;
2194
2435
  disabled?: string | boolean | undefined;
2195
2436
  shortcut?: string | undefined;
2196
2437
  bulkEnabled?: boolean | undefined;
2197
2438
  timeout?: number | undefined;
2198
2439
  aria?: {
2199
- ariaLabel?: string | {
2200
- key: string;
2201
- defaultValue?: string | undefined;
2202
- params?: Record<string, string | number | boolean> | undefined;
2203
- } | undefined;
2440
+ ariaLabel?: string | undefined;
2204
2441
  ariaDescribedBy?: string | undefined;
2205
2442
  role?: string | undefined;
2206
2443
  } | undefined;
@@ -3349,12 +3586,31 @@ interface RouteDefinition {
3349
3586
  path: string;
3350
3587
  /** Human-readable description */
3351
3588
  description: string;
3589
+ /** Whether this route requires authentication (default: true). */
3590
+ auth?: boolean;
3591
+ /** Required permissions for accessing this route. */
3592
+ permissions?: string[];
3352
3593
  /**
3353
3594
  * Handler receives a plain request-like object and returns a response-like
3354
3595
  * object. SSE responses set `stream: true` and provide an async iterable.
3355
3596
  */
3356
3597
  handler: (req: RouteRequest) => Promise<RouteResponse>;
3357
3598
  }
3599
+ /**
3600
+ * Authenticated user context attached to a route request.
3601
+ *
3602
+ * Populated by the auth middleware when `RouteDefinition.auth` is `true`.
3603
+ */
3604
+ interface RouteUserContext {
3605
+ /** Unique user identifier. */
3606
+ userId: string;
3607
+ /** User display name (optional). */
3608
+ displayName?: string;
3609
+ /** Roles assigned to the user (e.g. `['admin', 'user']`). */
3610
+ roles?: string[];
3611
+ /** Fine-grained permissions (e.g. `['ai:chat', 'ai:admin']`). */
3612
+ permissions?: string[];
3613
+ }
3358
3614
  interface RouteRequest {
3359
3615
  /** Parsed JSON body (for POST requests) */
3360
3616
  body?: unknown;
@@ -3362,6 +3618,8 @@ interface RouteRequest {
3362
3618
  params?: Record<string, string>;
3363
3619
  /** Query string parameters */
3364
3620
  query?: Record<string, string>;
3621
+ /** Authenticated user context (populated by auth middleware). */
3622
+ user?: RouteUserContext;
3365
3623
  }
3366
3624
  interface RouteResponse {
3367
3625
  /** HTTP status code */
@@ -3372,6 +3630,14 @@ interface RouteResponse {
3372
3630
  stream?: boolean;
3373
3631
  /** Async iterable of SSE events (when stream=true) */
3374
3632
  events?: AsyncIterable<unknown>;
3633
+ /**
3634
+ * When `true`, the HTTP server layer should encode the `events` iterable
3635
+ * using the Vercel AI Data Stream Protocol frame format (`0:`, `9:`, `d:`, …)
3636
+ * instead of generic SSE `data:` lines.
3637
+ *
3638
+ * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol
3639
+ */
3640
+ vercelDataStream?: boolean;
3375
3641
  }
3376
3642
  /**
3377
3643
  * Build the standard AI REST/SSE routes.
@@ -3399,8 +3665,9 @@ declare function buildAIRoutes(aiService: IAIService, conversationService: IAICo
3399
3665
  *
3400
3666
  * | Method | Path | Description |
3401
3667
  * |:---|:---|:---|
3668
+ * | GET | /api/v1/ai/agents | List all active agents |
3402
3669
  * | POST | /api/v1/ai/agents/:agentName/chat | Chat with a specific agent |
3403
3670
  */
3404
3671
  declare function buildAgentRoutes(aiService: AIService, agentRuntime: AgentRuntime, logger: Logger): RouteDefinition[];
3405
3672
 
3406
- export { AIService, type AIServiceConfig, AIServicePlugin, type AIServicePluginOptions, type AgentChatContext, AgentRuntime, AiConversationObject, AiMessageObject, DATA_CHAT_AGENT, DATA_TOOL_DEFINITIONS, type DataToolContext, InMemoryConversationService, MemoryLLMAdapter, ObjectQLConversationService, type RouteDefinition, type RouteRequest, type RouteResponse, type ToolHandler, ToolRegistry, buildAIRoutes, buildAgentRoutes, registerDataTools };
3673
+ export { AIService, type AIServiceConfig, AIServicePlugin, type AIServicePluginOptions, type AgentChatContext, AgentRuntime, AiConversationObject, AiMessageObject, DATA_CHAT_AGENT, DATA_TOOL_DEFINITIONS, type DataToolContext, InMemoryConversationService, METADATA_ASSISTANT_AGENT, METADATA_TOOL_DEFINITIONS, MemoryLLMAdapter, type MetadataToolContext, ObjectQLConversationService, type RouteDefinition, type RouteRequest, type RouteResponse, type RouteUserContext, type ToolExecutionResult, type ToolHandler, ToolRegistry, VercelLLMAdapter, type VercelLLMAdapterConfig, addFieldTool, buildAIRoutes, buildAgentRoutes, createObjectTool, deleteFieldTool, describeMetadataObjectTool, encodeStreamPart, encodeVercelDataStream, listMetadataObjectsTool, modifyFieldTool, registerDataTools, registerMetadataTools };