@objectstack/service-ai 4.0.1 → 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.
- package/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +9 -0
- package/dist/index.cjs +1120 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +316 -78
- package/dist/index.d.ts +316 -78
- package/dist/index.js +1105 -63
- package/dist/index.js.map +1 -1
- package/package.json +26 -4
- package/src/__tests__/ai-service.test.ts +248 -27
- package/src/__tests__/auth-and-toolcalling.test.ts +30 -28
- package/src/__tests__/chatbot-features.test.ts +229 -82
- package/src/__tests__/metadata-tools.test.ts +964 -0
- package/src/__tests__/objectql-conversation-service.test.ts +34 -16
- package/src/__tests__/vercel-stream-encoder.test.ts +263 -0
- package/src/adapters/index.ts +2 -0
- package/src/adapters/memory-adapter.ts +17 -9
- package/src/adapters/vercel-adapter.ts +148 -0
- package/src/agent-runtime.ts +27 -3
- package/src/agents/index.ts +1 -0
- package/src/agents/metadata-assistant-agent.ts +87 -0
- package/src/ai-service.ts +68 -36
- package/src/conversation/in-memory-conversation-service.ts +2 -2
- package/src/conversation/objectql-conversation-service.ts +67 -18
- package/src/index.ts +21 -2
- package/src/plugin.ts +166 -9
- package/src/routes/agent-routes.ts +26 -3
- package/src/routes/ai-routes.ts +156 -13
- package/src/stream/index.ts +3 -0
- package/src/stream/vercel-stream-encoder.ts +129 -0
- package/src/tools/add-field.tool.ts +70 -0
- package/src/tools/create-object.tool.ts +66 -0
- package/src/tools/delete-field.tool.ts +38 -0
- package/src/tools/describe-metadata-object.tool.ts +32 -0
- package/src/tools/index.ts +12 -1
- package/src/tools/list-metadata-objects.tool.ts +34 -0
- package/src/tools/metadata-tools.ts +430 -0
- package/src/tools/modify-field.tool.ts +44 -0
- package/src/tools/tool-registry.ts +32 -9
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/ai-service.ts","../src/adapters/memory-adapter.ts","../src/tools/tool-registry.ts","../src/conversation/in-memory-conversation-service.ts","../src/routes/ai-routes.ts","../src/routes/agent-routes.ts","../src/conversation/objectql-conversation-service.ts","../src/objects/ai-conversation.object.ts","../src/objects/ai-message.object.ts","../src/tools/data-tools.ts","../src/agent-runtime.ts","../src/agents/data-chat-agent.ts","../src/plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n// Core service\nexport { AIService } from './ai-service.js';\nexport type { AIServiceConfig } from './ai-service.js';\n\n// Kernel plugin\nexport { AIServicePlugin } from './plugin.js';\nexport type { AIServicePluginOptions } from './plugin.js';\n\n// Adapters\nexport { MemoryLLMAdapter } from './adapters/memory-adapter.js';\nexport type { LLMAdapter } from '@objectstack/spec/contracts';\n\n// Conversation\nexport { InMemoryConversationService } from './conversation/in-memory-conversation-service.js';\nexport { ObjectQLConversationService } from './conversation/objectql-conversation-service.js';\n\n// Tool registry\nexport { ToolRegistry } from './tools/tool-registry.js';\nexport type { ToolHandler } from './tools/tool-registry.js';\n\n// Data tools\nexport { registerDataTools, DATA_TOOL_DEFINITIONS } from './tools/data-tools.js';\nexport type { DataToolContext } from './tools/data-tools.js';\n\n// Agent runtime\nexport { AgentRuntime } from './agent-runtime.js';\nexport type { AgentChatContext } from './agent-runtime.js';\n\n// Built-in agents\nexport { DATA_CHAT_AGENT } from './agents/index.js';\n\n// Object definitions\nexport { AiConversationObject, AiMessageObject } from './objects/index.js';\n\n// Routes\nexport { buildAIRoutes } from './routes/ai-routes.js';\nexport { buildAgentRoutes } from './routes/agent-routes.js';\nexport type { RouteDefinition, RouteRequest, RouteResponse, RouteUserContext } from './routes/ai-routes.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIMessage,\n AIRequestOptions,\n AIResult,\n AIStreamEvent,\n IAIService,\n IAIConversationService,\n ChatWithToolsOptions,\n LLMAdapter,\n} from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport { createLogger } from '@objectstack/core';\nimport { MemoryLLMAdapter } from './adapters/memory-adapter.js';\nimport { ToolRegistry } from './tools/tool-registry.js';\nimport { InMemoryConversationService } from './conversation/in-memory-conversation-service.js';\n\n/**\n * Configuration for AIService.\n */\nexport interface AIServiceConfig {\n /** LLM adapter to delegate calls to (defaults to MemoryLLMAdapter). */\n adapter?: LLMAdapter;\n /** Logger instance. */\n logger?: Logger;\n /** Pre-registered tools. */\n toolRegistry?: ToolRegistry;\n /** Conversation service (defaults to InMemoryConversationService). */\n conversationService?: IAIConversationService;\n}\n\n/**\n * AIService — Unified AI capability service.\n *\n * Implements {@link IAIService} by delegating to a pluggable {@link LLMAdapter}\n * and managing tools and conversations through dedicated sub-components:\n *\n * | Component | Responsibility |\n * |:---|:---|\n * | {@link LLMAdapter} | LLM provider abstraction (chat, complete, stream, embed) |\n * | {@link ToolRegistry} | Tool definition storage & execution |\n * | {@link IAIConversationService} | Conversation CRUD & message persistence |\n *\n * The service is registered as `'ai'` in the kernel service registry by\n * the {@link AIServicePlugin}.\n */\nexport class AIService implements IAIService {\n private readonly adapter: LLMAdapter;\n private readonly logger: Logger;\n readonly toolRegistry: ToolRegistry;\n readonly conversationService: IAIConversationService;\n\n constructor(config: AIServiceConfig = {}) {\n this.adapter = config.adapter ?? new MemoryLLMAdapter();\n this.logger = config.logger ?? createLogger({ level: 'info', format: 'pretty' });\n this.toolRegistry = config.toolRegistry ?? new ToolRegistry();\n this.conversationService = config.conversationService ?? new InMemoryConversationService();\n\n this.logger.info(\n `[AI] Service initialized with adapter=\"${this.adapter.name}\", ` +\n `tools=${this.toolRegistry.size}`,\n );\n }\n\n /** The name of the active LLM adapter. */\n get adapterName(): string {\n return this.adapter.name;\n }\n\n // ── IAIService implementation ──────────────────────────────────\n\n async chat(messages: AIMessage[], options?: AIRequestOptions): Promise<AIResult> {\n this.logger.debug('[AI] chat', { messageCount: messages.length, model: options?.model });\n return this.adapter.chat(messages, options);\n }\n\n async complete(prompt: string, options?: AIRequestOptions): Promise<AIResult> {\n this.logger.debug('[AI] complete', { promptLength: prompt.length, model: options?.model });\n return this.adapter.complete(prompt, options);\n }\n\n async *streamChat(\n messages: AIMessage[],\n options?: AIRequestOptions,\n ): AsyncIterable<AIStreamEvent> {\n this.logger.debug('[AI] streamChat', { messageCount: messages.length, model: options?.model });\n\n if (!this.adapter.streamChat) {\n // Fallback: emit the entire response as a single text-delta + finish\n const result = await this.adapter.chat(messages, options);\n yield { type: 'text-delta', textDelta: result.content };\n yield { type: 'finish', result };\n return;\n }\n\n yield* this.adapter.streamChat(messages, options);\n }\n\n async embed(input: string | string[], model?: string): Promise<number[][]> {\n if (!this.adapter.embed) {\n throw new Error(`[AI] Adapter \"${this.adapter.name}\" does not support embeddings`);\n }\n return this.adapter.embed(input, model);\n }\n\n async listModels(): Promise<string[]> {\n if (!this.adapter.listModels) {\n return [];\n }\n return this.adapter.listModels();\n }\n\n // ── Tool Call Loop ────────────────────────────────────────────\n\n /** Default maximum iterations for the tool call loop. */\n static readonly DEFAULT_MAX_ITERATIONS = 10;\n\n /**\n * Chat with automatic tool call resolution.\n *\n * 1. Merges registered tool definitions into `options.tools`.\n * 2. Calls the LLM adapter.\n * 3. If the response contains `toolCalls`, executes them via the\n * {@link ToolRegistry}, appends tool results as `role: 'tool'`\n * messages, and loops back to step 2.\n * 4. Repeats until the model produces a final text response or the\n * maximum number of iterations (`maxIterations`) is reached.\n */\n async chatWithTools(\n messages: AIMessage[],\n options?: ChatWithToolsOptions,\n ): Promise<AIResult> {\n // Destructure loop-specific options so they are never forwarded to the adapter\n const { maxIterations: maxIter, onToolError, ...restOptions } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n\n // Merge registered tools with any explicitly provided tools\n const mergedTools = [\n ...registeredTools,\n ...(restOptions.tools ?? []),\n ];\n\n // Build the options that will be sent to every LLM call in the loop\n const chatOptions: AIRequestOptions = {\n ...restOptions,\n tools: mergedTools.length > 0 ? mergedTools : undefined,\n toolChoice: mergedTools.length > 0 ? (restOptions.toolChoice ?? 'auto') : undefined,\n };\n\n // Working copy of the conversation\n const conversation = [...messages];\n\n // Track errors across iterations for diagnostics\n const toolErrors: Array<{ iteration: number; toolName: string; error: string }> = [];\n\n this.logger.debug('[AI] chatWithTools start', {\n messageCount: conversation.length,\n toolCount: mergedTools.length,\n maxIterations,\n });\n\n let abortedByCallback = false;\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n const result = await this.adapter.chat(conversation, chatOptions);\n\n // If the model did not request any tool calls we're done\n if (!result.toolCalls || result.toolCalls.length === 0) {\n this.logger.debug('[AI] chatWithTools finished', { iteration, content: result.content.slice(0, 80) });\n return result;\n }\n\n this.logger.debug('[AI] chatWithTools tool calls', {\n iteration,\n calls: result.toolCalls.map(tc => tc.name),\n });\n\n // Append the assistant's response (with tool call metadata) to the conversation\n conversation.push({\n role: 'assistant',\n content: result.content ?? '',\n toolCalls: result.toolCalls,\n });\n\n // Execute all tool calls in parallel\n const toolResults = await this.toolRegistry.executeAll(result.toolCalls);\n\n // Process results: track errors and honour onToolError callback\n for (const tr of toolResults) {\n if (tr.isError) {\n // Match tool call by toolCallId for robust attribution\n const matchedCall = result.toolCalls!.find(tc => tc.id === tr.toolCallId);\n const toolName = matchedCall?.name ?? 'unknown';\n const errorEntry = { iteration, toolName, error: tr.content };\n toolErrors.push(errorEntry);\n this.logger.warn('[AI] chatWithTools tool error', errorEntry);\n\n if (onToolError && matchedCall) {\n const action = onToolError(matchedCall, tr.content);\n if (action === 'abort') {\n abortedByCallback = true;\n }\n }\n }\n\n // Append each tool result as a `role: 'tool'` message\n conversation.push({\n role: 'tool',\n content: tr.content,\n toolCallId: tr.toolCallId,\n });\n }\n\n if (abortedByCallback) {\n break;\n }\n }\n\n // Distinguish user-driven abort from max-iterations exhaustion in logs\n if (abortedByCallback) {\n this.logger.warn('[AI] chatWithTools aborted by onToolError callback', { toolErrors });\n } else {\n this.logger.warn('[AI] chatWithTools max iterations reached, forcing final response', {\n toolErrors: toolErrors.length > 0 ? toolErrors : undefined,\n });\n }\n\n // Make one last call *without* tools so the model is forced to produce text.\n const finalResult = await this.adapter.chat(conversation, {\n ...chatOptions,\n tools: undefined,\n toolChoice: undefined,\n });\n return finalResult;\n }\n\n /**\n * Stream chat with automatic tool call resolution.\n *\n * Works like {@link chatWithTools} but yields SSE events. When the model\n * requests tool calls during streaming, they are executed and the results\n * fed back until a final text stream is produced.\n */\n async *streamChatWithTools(\n messages: AIMessage[],\n options?: ChatWithToolsOptions,\n ): AsyncIterable<AIStreamEvent> {\n const { maxIterations: maxIter, onToolError, ...restOptions } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n\n const mergedTools = [\n ...registeredTools,\n ...(restOptions.tools ?? []),\n ];\n\n const chatOptions: AIRequestOptions = {\n ...restOptions,\n tools: mergedTools.length > 0 ? mergedTools : undefined,\n toolChoice: mergedTools.length > 0 ? (restOptions.toolChoice ?? 'auto') : undefined,\n };\n\n const conversation = [...messages];\n let abortedByCallback = false;\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Use non-streaming chat for intermediate tool-call rounds\n const result = await this.adapter.chat(conversation, chatOptions);\n\n if (!result.toolCalls || result.toolCalls.length === 0) {\n // Final round — return the probed result without an extra model call\n yield { type: 'text-delta', textDelta: result.content };\n yield { type: 'finish', result };\n return;\n }\n\n // Emit tool-call events so the client can see tool execution progress\n for (const tc of result.toolCalls) {\n yield { type: 'tool-call', toolCall: tc };\n }\n\n conversation.push({\n role: 'assistant',\n content: result.content ?? '',\n toolCalls: result.toolCalls,\n });\n\n const toolResults = await this.toolRegistry.executeAll(result.toolCalls);\n\n for (const tr of toolResults) {\n if (tr.isError && onToolError) {\n const matchedCall = result.toolCalls!.find(tc => tc.id === tr.toolCallId);\n if (matchedCall) {\n const action = onToolError(matchedCall, tr.content);\n if (action === 'abort') {\n abortedByCallback = true;\n }\n }\n }\n conversation.push({\n role: 'tool',\n content: tr.content,\n toolCallId: tr.toolCallId,\n });\n }\n\n if (abortedByCallback) {\n break;\n }\n }\n\n // Forced final response (no tools) — either aborted or max iterations\n if (abortedByCallback) {\n this.logger.warn('[AI] streamChatWithTools aborted by onToolError callback');\n } else {\n this.logger.warn('[AI] streamChatWithTools max iterations reached');\n }\n const finalOptions = { ...chatOptions, tools: undefined, toolChoice: undefined };\n const result = await this.adapter.chat(conversation, finalOptions);\n yield { type: 'text-delta', textDelta: result.content };\n yield { type: 'finish', result };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIMessage,\n AIRequestOptions,\n AIResult,\n AIStreamEvent,\n} from '@objectstack/spec/contracts';\nimport type { LLMAdapter } from '@objectstack/spec/contracts';\n\n/**\n * MemoryLLMAdapter — deterministic in-memory adapter for testing & development.\n *\n * Always echoes back the last user message prefixed with \"[memory] \".\n * Useful for unit tests, CI pipelines, and local dev without an LLM key.\n */\nexport class MemoryLLMAdapter implements LLMAdapter {\n readonly name = 'memory';\n\n async chat(messages: AIMessage[], options?: AIRequestOptions): Promise<AIResult> {\n const lastUserMessage = [...messages].reverse().find(m => m.role === 'user');\n const content = lastUserMessage\n ? `[memory] ${lastUserMessage.content}`\n : '[memory] (no user message)';\n\n return {\n content,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n async complete(prompt: string, options?: AIRequestOptions): Promise<AIResult> {\n return {\n content: `[memory] ${prompt}`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n async *streamChat(\n messages: AIMessage[],\n _options?: AIRequestOptions,\n ): AsyncIterable<AIStreamEvent> {\n const result = await this.chat(messages);\n // Emit word-by-word deltas for realistic streaming simulation\n const words = result.content.split(' ');\n for (let i = 0; i < words.length; i++) {\n const textDelta = i === 0 ? words[i] : ` ${words[i]}`;\n yield { type: 'text-delta', textDelta };\n }\n yield { type: 'finish', result };\n }\n\n async embed(input: string | string[]): Promise<number[][]> {\n const texts = Array.isArray(input) ? input : [input];\n // Return deterministic zero vectors of dimension 3\n return texts.map(() => [0, 0, 0]);\n }\n\n async listModels(): Promise<string[]> {\n return ['memory'];\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { AIToolDefinition, AIToolCall, AIToolResult } from '@objectstack/spec/contracts';\n\n/**\n * Handler function for a registered tool.\n *\n * Receives parsed arguments and returns the tool output as a string.\n */\nexport type ToolHandler = (args: Record<string, unknown>) => Promise<string> | string;\n\n/**\n * ToolRegistry — Central registry for AI-callable tools.\n *\n * Plugins register tools (metadata helpers, data queries, business actions)\n * during the `ai:ready` hook. The AI service resolves tool calls against\n * this registry and feeds the results back to the LLM.\n */\nexport class ToolRegistry {\n private readonly definitions = new Map<string, AIToolDefinition>();\n private readonly handlers = new Map<string, ToolHandler>();\n\n /**\n * Register a tool with its definition and handler.\n * @param definition - Tool definition (name, description, parameters schema)\n * @param handler - Async function that executes the tool\n */\n register(definition: AIToolDefinition, handler: ToolHandler): void {\n this.definitions.set(definition.name, definition);\n this.handlers.set(definition.name, handler);\n }\n\n /**\n * Unregister a tool by name.\n */\n unregister(name: string): void {\n this.definitions.delete(name);\n this.handlers.delete(name);\n }\n\n /**\n * Check whether a tool is registered.\n */\n has(name: string): boolean {\n return this.definitions.has(name);\n }\n\n /**\n * Get the definition for a registered tool.\n */\n getDefinition(name: string): AIToolDefinition | undefined {\n return this.definitions.get(name);\n }\n\n /**\n * Return all registered tool definitions.\n */\n getAll(): AIToolDefinition[] {\n return Array.from(this.definitions.values());\n }\n\n /** Number of registered tools. */\n get size(): number {\n return this.definitions.size;\n }\n\n /** All registered tool names. */\n names(): string[] {\n return Array.from(this.definitions.keys());\n }\n\n /**\n * Execute a tool call and return the result.\n */\n async execute(toolCall: AIToolCall): Promise<AIToolResult> {\n const handler = this.handlers.get(toolCall.name);\n if (!handler) {\n return {\n toolCallId: toolCall.id,\n content: `Tool \"${toolCall.name}\" is not registered`,\n isError: true,\n };\n }\n\n try {\n const args: Record<string, unknown> = JSON.parse(toolCall.arguments);\n const content = await handler(args);\n return { toolCallId: toolCall.id, content };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { toolCallId: toolCall.id, content: message, isError: true };\n }\n }\n\n /**\n * Execute multiple tool calls in parallel.\n */\n async executeAll(toolCalls: AIToolCall[]): Promise<AIToolResult[]> {\n return Promise.all(toolCalls.map(tc => this.execute(tc)));\n }\n\n /**\n * Clear all registered tools.\n */\n clear(): void {\n this.definitions.clear();\n this.handlers.clear();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIConversation,\n AIMessage,\n IAIConversationService,\n} from '@objectstack/spec/contracts';\n\n/**\n * InMemoryConversationService — Reference implementation of IAIConversationService.\n *\n * Stores conversations in a simple Map. Suitable for development, testing,\n * and single-process deployments. Production environments should replace\n * this with a persistent implementation (e.g., backed by ObjectQL/SQL).\n */\nexport class InMemoryConversationService implements IAIConversationService {\n private readonly store = new Map<string, AIConversation>();\n private counter = 0;\n\n async create(options: {\n title?: string;\n agentId?: string;\n userId?: string;\n metadata?: Record<string, unknown>;\n } = {}): Promise<AIConversation> {\n const now = new Date().toISOString();\n const id = `conv_${++this.counter}`;\n\n const conversation: AIConversation = {\n id,\n title: options.title,\n agentId: options.agentId,\n userId: options.userId,\n messages: [],\n createdAt: now,\n updatedAt: now,\n metadata: options.metadata,\n };\n\n this.store.set(id, conversation);\n return conversation;\n }\n\n async get(conversationId: string): Promise<AIConversation | null> {\n return this.store.get(conversationId) ?? null;\n }\n\n async list(options: {\n userId?: string;\n agentId?: string;\n limit?: number;\n cursor?: string;\n } = {}): Promise<AIConversation[]> {\n let results = Array.from(this.store.values());\n\n if (options.userId) {\n results = results.filter(c => c.userId === options.userId);\n }\n if (options.agentId) {\n results = results.filter(c => c.agentId === options.agentId);\n }\n\n // Simple cursor-based pagination: cursor = conversation ID\n if (options.cursor) {\n const idx = results.findIndex(c => c.id === options.cursor);\n if (idx >= 0) {\n results = results.slice(idx + 1);\n }\n }\n\n if (options.limit && options.limit > 0) {\n results = results.slice(0, options.limit);\n }\n\n return results;\n }\n\n async addMessage(conversationId: string, message: AIMessage): Promise<AIConversation> {\n const conversation = this.store.get(conversationId);\n if (!conversation) {\n throw new Error(`Conversation \"${conversationId}\" not found`);\n }\n\n conversation.messages.push(message);\n conversation.updatedAt = new Date().toISOString();\n return conversation;\n }\n\n async delete(conversationId: string): Promise<void> {\n this.store.delete(conversationId);\n }\n\n /** Total number of stored conversations. */\n get size(): number {\n return this.store.size;\n }\n\n /** Clear all conversations. */\n clear(): void {\n this.store.clear();\n this.counter = 0;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IAIService, IAIConversationService, AIMessage } from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\n\n/**\n * Minimal HTTP handler abstraction so routes stay framework-agnostic.\n *\n * Consumers wire these handlers to their HTTP server of choice\n * (Hono, Express, Fastify, etc.) via the kernel's HTTP server service.\n */\nexport interface RouteDefinition {\n /** HTTP method */\n method: 'GET' | 'POST' | 'DELETE';\n /** Path pattern (e.g. '/api/v1/ai/chat') */\n path: string;\n /** Human-readable description */\n description: string;\n /** Whether this route requires authentication (default: true). */\n auth?: boolean;\n /** Required permissions for accessing this route. */\n permissions?: string[];\n /**\n * Handler receives a plain request-like object and returns a response-like\n * object. SSE responses set `stream: true` and provide an async iterable.\n */\n handler: (req: RouteRequest) => Promise<RouteResponse>;\n}\n\n/**\n * Authenticated user context attached to a route request.\n *\n * Populated by the auth middleware when `RouteDefinition.auth` is `true`.\n */\nexport interface RouteUserContext {\n /** Unique user identifier. */\n userId: string;\n /** User display name (optional). */\n displayName?: string;\n /** Roles assigned to the user (e.g. `['admin', 'user']`). */\n roles?: string[];\n /** Fine-grained permissions (e.g. `['ai:chat', 'ai:admin']`). */\n permissions?: string[];\n}\n\nexport interface RouteRequest {\n /** Parsed JSON body (for POST requests) */\n body?: unknown;\n /** Route/query parameters */\n params?: Record<string, string>;\n /** Query string parameters */\n query?: Record<string, string>;\n /** Authenticated user context (populated by auth middleware). */\n user?: RouteUserContext;\n}\n\nexport interface RouteResponse {\n /** HTTP status code */\n status: number;\n /** JSON-serializable body (for non-streaming responses) */\n body?: unknown;\n /** If true, `stream` provides SSE events */\n stream?: boolean;\n /** Async iterable of SSE events (when stream=true) */\n events?: AsyncIterable<unknown>;\n}\n\n/** Valid message roles accepted by the AI routes. */\nconst VALID_ROLES = new Set<string>(['system', 'user', 'assistant', 'tool']);\n\n/**\n * Validate that `raw` is a well-formed AIMessage.\n * Returns null on success, or an error string on failure.\n */\nfunction validateMessage(raw: unknown): string | null {\n if (typeof raw !== 'object' || raw === null) {\n return 'each message must be an object';\n }\n const msg = raw as Record<string, unknown>;\n if (typeof msg.role !== 'string' || !VALID_ROLES.has(msg.role)) {\n return `message.role must be one of ${[...VALID_ROLES].map(r => `\"${r}\"`).join(', ')}`;\n }\n if (typeof msg.content !== 'string') {\n return 'message.content must be a string';\n }\n return null;\n}\n\n/**\n * Build the standard AI REST/SSE routes.\n *\n * Depends on contracts ({@link IAIService} + {@link IAIConversationService})\n * rather than concrete implementations, so any compliant service pair can\n * be wired in.\n *\n * Routes:\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | POST | /api/v1/ai/chat | Synchronous chat completion |\n * | POST | /api/v1/ai/chat/stream | SSE streaming chat completion |\n * | POST | /api/v1/ai/complete | Text completion |\n * | GET | /api/v1/ai/models | List available models |\n * | POST | /api/v1/ai/conversations | Create a conversation |\n * | GET | /api/v1/ai/conversations | List conversations |\n * | POST | /api/v1/ai/conversations/:id/messages | Add message to conversation |\n * | DELETE | /api/v1/ai/conversations/:id | Delete conversation |\n */\nexport function buildAIRoutes(\n aiService: IAIService,\n conversationService: IAIConversationService,\n logger: Logger,\n): RouteDefinition[] {\n return [\n // ── Chat ────────────────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/chat',\n description: 'Synchronous chat completion',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n const { messages, options } = (req.body ?? {}) as {\n messages?: unknown[];\n options?: Record<string, unknown>;\n };\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n\n for (const msg of messages) {\n const err = validateMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n try {\n const result = await aiService.chat(messages as AIMessage[], options as any);\n return { status: 200, body: result };\n } catch (err) {\n logger.error('[AI Route] /chat error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Stream Chat (SSE) ──────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/chat/stream',\n description: 'SSE streaming chat completion',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n const { messages, options } = (req.body ?? {}) as {\n messages?: unknown[];\n options?: Record<string, unknown>;\n };\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n\n for (const msg of messages) {\n const err = validateMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n try {\n if (!aiService.streamChat) {\n return { status: 501, body: { error: 'Streaming is not supported by the configured AI service' } };\n }\n const events = aiService.streamChat(messages as AIMessage[], options as any);\n return { status: 200, stream: true, events };\n } catch (err) {\n logger.error('[AI Route] /chat/stream error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Complete ────────────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/complete',\n description: 'Text completion',\n auth: true,\n permissions: ['ai:complete'],\n handler: async (req) => {\n const { prompt, options } = (req.body ?? {}) as {\n prompt?: string;\n options?: Record<string, unknown>;\n };\n\n if (!prompt || typeof prompt !== 'string') {\n return { status: 400, body: { error: 'prompt string is required' } };\n }\n\n try {\n const result = await aiService.complete(prompt, options as any);\n return { status: 200, body: result };\n } catch (err) {\n logger.error('[AI Route] /complete error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Models ──────────────────────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/models',\n description: 'List available models',\n auth: true,\n permissions: ['ai:read'],\n handler: async () => {\n try {\n const models = aiService.listModels ? await aiService.listModels() : [];\n return { status: 200, body: { models } };\n } catch (err) {\n logger.error('[AI Route] /models error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Conversations ──────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/conversations',\n description: 'Create a conversation',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n try {\n // Ensure the request body is a non-null object before mutating it\n if (req.body !== undefined && req.body !== null && (typeof req.body !== 'object' || Array.isArray(req.body))) {\n return { status: 400, body: { error: 'Invalid request payload' } };\n }\n\n const options: Record<string, unknown> = { ...((req.body ?? {}) as Record<string, unknown>) };\n // Bind the conversation to the authenticated user\n if (req.user?.userId) {\n options.userId = req.user.userId;\n }\n const conversation = await conversationService.create(options as any);\n return { status: 201, body: conversation };\n } catch (err) {\n logger.error('[AI Route] POST /conversations error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n {\n method: 'GET',\n path: '/api/v1/ai/conversations',\n description: 'List conversations',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n try {\n const rawQuery = req.query ?? {};\n const options: Record<string, unknown> = { ...rawQuery };\n\n if (typeof rawQuery.limit === 'string') {\n const parsedLimit = Number(rawQuery.limit);\n if (!Number.isFinite(parsedLimit) || parsedLimit <= 0 || !Number.isInteger(parsedLimit)) {\n return { status: 400, body: { error: 'Invalid limit parameter' } };\n }\n options.limit = parsedLimit;\n }\n\n // Scope to the authenticated user's conversations\n if (req.user?.userId) {\n options.userId = req.user.userId;\n }\n\n const conversations = await conversationService.list(options as any);\n return { status: 200, body: { conversations } };\n } catch (err) {\n logger.error('[AI Route] GET /conversations error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n {\n method: 'POST',\n path: '/api/v1/ai/conversations/:id/messages',\n description: 'Add message to a conversation',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n const id = req.params?.id;\n if (!id) {\n return { status: 400, body: { error: 'conversation id is required' } };\n }\n\n const message = req.body;\n const validationError = validateMessage(message);\n if (validationError) {\n return { status: 400, body: { error: validationError } };\n }\n\n try {\n // Ownership check: verify the conversation belongs to the current user\n if (req.user?.userId) {\n const existing = await conversationService.get(id);\n if (!existing) {\n return { status: 404, body: { error: `Conversation \"${id}\" not found` } };\n }\n if (existing.userId && existing.userId !== req.user.userId) {\n return { status: 403, body: { error: 'You do not have access to this conversation' } };\n }\n }\n\n const conversation = await conversationService.addMessage(id, message as AIMessage);\n return { status: 200, body: conversation };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found')) {\n return { status: 404, body: { error: msg } };\n }\n logger.error('[AI Route] POST /conversations/:id/messages error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n {\n method: 'DELETE',\n path: '/api/v1/ai/conversations/:id',\n description: 'Delete a conversation',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n const id = req.params?.id;\n if (!id) {\n return { status: 400, body: { error: 'conversation id is required' } };\n }\n\n try {\n // Ownership check: verify the conversation belongs to the current user\n if (req.user?.userId) {\n const existing = await conversationService.get(id);\n if (!existing) {\n return { status: 404, body: { error: `Conversation \"${id}\" not found` } };\n }\n if (existing.userId && existing.userId !== req.user.userId) {\n return { status: 403, body: { error: 'You do not have access to this conversation' } };\n }\n }\n\n await conversationService.delete(id);\n return { status: 204 };\n } catch (err) {\n logger.error('[AI Route] DELETE /conversations/:id error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n ];\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { AIMessage } from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport type { AIService } from '../ai-service.js';\nimport type { AgentRuntime, AgentChatContext } from '../agent-runtime.js';\nimport type { RouteDefinition } from './ai-routes.js';\n\n/**\n * Allowed message roles for the agent chat endpoint.\n *\n * Only `user` and `assistant` are accepted from clients.\n * `system` messages are injected server-side from agent instructions,\n * and `tool` messages are produced by the tool-call loop — accepting\n * either from the client would allow callers to override agent\n * guardrails or inject fabricated tool results.\n */\nconst ALLOWED_AGENT_ROLES = new Set<string>(['user', 'assistant']);\n\nfunction validateAgentMessage(raw: unknown): string | null {\n if (typeof raw !== 'object' || raw === null) {\n return 'each message must be an object';\n }\n const msg = raw as Record<string, unknown>;\n if (typeof msg.role !== 'string' || !ALLOWED_AGENT_ROLES.has(msg.role)) {\n return `message.role must be one of ${[...ALLOWED_AGENT_ROLES].map(r => `\"${r}\"`).join(', ')} for agent chat`;\n }\n if (typeof msg.content !== 'string') {\n return 'message.content must be a string';\n }\n return null;\n}\n\n/**\n * Build agent-specific REST routes.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | POST | /api/v1/ai/agents/:agentName/chat | Chat with a specific agent |\n */\nexport function buildAgentRoutes(\n aiService: AIService,\n agentRuntime: AgentRuntime,\n logger: Logger,\n): RouteDefinition[] {\n return [\n {\n method: 'POST',\n path: '/api/v1/ai/agents/:agentName/chat',\n description: 'Chat with a specific AI agent',\n auth: true,\n permissions: ['ai:chat', 'ai:agents'],\n handler: async (req) => {\n const agentName = req.params?.agentName;\n if (!agentName) {\n return { status: 400, body: { error: 'agentName parameter is required' } };\n }\n\n // Parse request body\n const {\n messages: rawMessages,\n context: chatContext,\n options: extraOptions,\n } = (req.body ?? {}) as {\n messages?: unknown[];\n context?: AgentChatContext;\n options?: Record<string, unknown>;\n };\n\n if (!Array.isArray(rawMessages) || rawMessages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n\n for (const msg of rawMessages) {\n const err = validateAgentMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n // Load agent definition\n const agent = await agentRuntime.loadAgent(agentName);\n if (!agent) {\n return { status: 404, body: { error: `Agent \"${agentName}\" not found` } };\n }\n if (!agent.active) {\n return { status: 403, body: { error: `Agent \"${agentName}\" is not active` } };\n }\n\n try {\n // Build system messages from agent instructions + UI context\n const systemMessages = agentRuntime.buildSystemMessages(agent, chatContext);\n\n // Resolve agent model/tools → request options\n const agentOptions = agentRuntime.buildRequestOptions(\n agent,\n aiService.toolRegistry.getAll(),\n );\n\n // Whitelist only safe caller overrides — block tools/toolChoice/model\n // to prevent tool-definition injection or DoS via unregistered tools.\n const safeOverrides: Record<string, unknown> = {};\n if (extraOptions) {\n const ALLOWED_KEYS = new Set(['temperature', 'maxTokens', 'stop']);\n for (const key of Object.keys(extraOptions)) {\n if (ALLOWED_KEYS.has(key)) {\n safeOverrides[key] = extraOptions[key];\n }\n }\n }\n const mergedOptions = { ...agentOptions, ...safeOverrides };\n\n // Prepend system messages then user conversation\n const fullMessages: AIMessage[] = [\n ...systemMessages,\n ...(rawMessages as AIMessage[]),\n ];\n\n // Use chatWithTools for automatic tool resolution\n const result = await aiService.chatWithTools(fullMessages, {\n ...mergedOptions,\n maxIterations: agent.planning?.maxIterations,\n });\n\n return { status: 200, body: result };\n } catch (err) {\n logger.error(\n '[AI Route] /agents/:agentName/chat error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n ];\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n AIConversation,\n AIMessage,\n IAIConversationService,\n IDataEngine,\n} from '@objectstack/spec/contracts';\n\n/** Object names used for persistence. */\nconst CONVERSATIONS_OBJECT = 'ai_conversations';\nconst MESSAGES_OBJECT = 'ai_messages';\n\n/** Database row shape for ai_conversations. */\ninterface DbConversationRow {\n id: string;\n title: string | null;\n agent_id: string | null;\n user_id: string | null;\n metadata: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/** Database row shape for ai_messages. */\ninterface DbMessageRow {\n id: string;\n conversation_id: string;\n role: 'system' | 'user' | 'assistant' | 'tool';\n content: string;\n tool_calls: string | null;\n tool_call_id: string | null;\n created_at: string;\n}\n\n/** Deterministic ordering for conversations (total order). */\nconst CONVERSATION_ORDER = [\n { field: 'created_at', order: 'asc' as const },\n { field: 'id', order: 'asc' as const },\n];\n\n/** Deterministic ordering for messages within a conversation. */\nconst MESSAGE_ORDER = [\n { field: 'created_at', order: 'asc' as const },\n { field: 'id', order: 'asc' as const },\n];\n\n/**\n * ObjectQLConversationService — Persistent implementation of IAIConversationService.\n *\n * Delegates all storage to an {@link IDataEngine} instance, using the\n * `ai_conversations` and `ai_messages` objects. This decouples the service\n * from any specific database driver (Turso, Postgres, SQLite, etc.).\n *\n * Production environments should use this implementation to ensure\n * conversation history survives service restarts.\n */\nexport class ObjectQLConversationService implements IAIConversationService {\n private readonly engine: IDataEngine;\n\n constructor(engine: IDataEngine) {\n this.engine = engine;\n }\n\n async create(options: {\n title?: string;\n agentId?: string;\n userId?: string;\n metadata?: Record<string, unknown>;\n } = {}): Promise<AIConversation> {\n const now = new Date().toISOString();\n const id = `conv_${randomUUID()}`;\n\n const record = {\n id,\n title: options.title ?? null,\n agent_id: options.agentId ?? null,\n user_id: options.userId ?? null,\n metadata: options.metadata ? JSON.stringify(options.metadata) : null,\n created_at: now,\n updated_at: now,\n };\n\n await this.engine.insert(CONVERSATIONS_OBJECT, record);\n\n return {\n id,\n title: options.title,\n agentId: options.agentId,\n userId: options.userId,\n messages: [],\n createdAt: now,\n updatedAt: now,\n metadata: options.metadata,\n };\n }\n\n async get(conversationId: string): Promise<AIConversation | null> {\n const row: DbConversationRow | null = await this.engine.findOne(CONVERSATIONS_OBJECT, {\n where: { id: conversationId },\n });\n\n if (!row) return null;\n\n const messages: DbMessageRow[] = await this.engine.find(MESSAGES_OBJECT, {\n where: { conversation_id: conversationId },\n orderBy: MESSAGE_ORDER,\n });\n\n return this.toConversation(row, messages);\n }\n\n async list(options: {\n userId?: string;\n agentId?: string;\n limit?: number;\n cursor?: string;\n } = {}): Promise<AIConversation[]> {\n const where: Record<string, unknown> = {};\n if (options.userId) where.user_id = options.userId;\n if (options.agentId) where.agent_id = options.agentId;\n\n // Stable cursor-based pagination using composite (created_at, id) order.\n // This avoids skips/duplicates when multiple conversations share a timestamp.\n if (options.cursor) {\n const cursorRow = await this.engine.findOne(CONVERSATIONS_OBJECT, {\n where: { id: options.cursor },\n fields: ['created_at', 'id'],\n });\n if (cursorRow) {\n where.$or = [\n { created_at: { $gt: cursorRow.created_at } },\n { created_at: cursorRow.created_at, id: { $gt: cursorRow.id } },\n ];\n }\n }\n\n const rows: DbConversationRow[] = await this.engine.find(CONVERSATIONS_OBJECT, {\n where: Object.keys(where).length > 0 ? where : undefined,\n orderBy: CONVERSATION_ORDER,\n limit: options.limit && options.limit > 0 ? options.limit : undefined,\n });\n\n // Load messages per conversation in parallel.\n // N+1 is bounded by the pagination limit; driver-agnostic $in is not guaranteed.\n const conversations: AIConversation[] = await Promise.all(\n rows.map(async (row) => {\n const messages: DbMessageRow[] = await this.engine.find(MESSAGES_OBJECT, {\n where: { conversation_id: row.id },\n orderBy: MESSAGE_ORDER,\n });\n return this.toConversation(row, messages);\n }),\n );\n\n return conversations;\n }\n\n async addMessage(conversationId: string, message: AIMessage): Promise<AIConversation> {\n // Verify conversation exists\n const row: DbConversationRow | null = await this.engine.findOne(CONVERSATIONS_OBJECT, {\n where: { id: conversationId },\n });\n if (!row) {\n throw new Error(`Conversation \"${conversationId}\" not found`);\n }\n\n const now = new Date().toISOString();\n const msgId = `msg_${randomUUID()}`;\n\n // Insert the message\n await this.engine.insert(MESSAGES_OBJECT, {\n id: msgId,\n conversation_id: conversationId,\n role: message.role,\n content: message.content,\n tool_calls: message.toolCalls ? JSON.stringify(message.toolCalls) : null,\n tool_call_id: message.toolCallId ?? null,\n created_at: now,\n });\n\n // Update conversation timestamp\n await this.engine.update(CONVERSATIONS_OBJECT, { id: conversationId, updated_at: now }, {\n where: { id: conversationId },\n });\n\n // Return the full updated conversation\n return (await this.get(conversationId))!;\n }\n\n async delete(conversationId: string): Promise<void> {\n // Delete messages first (child records)\n await this.engine.delete(MESSAGES_OBJECT, {\n where: { conversation_id: conversationId },\n multi: true,\n });\n\n // Delete the conversation\n await this.engine.delete(CONVERSATIONS_OBJECT, {\n where: { id: conversationId },\n });\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n /**\n * Safely parse a JSON string, returning `undefined` on failure.\n */\n private safeParse<T>(value: string | null, fallback?: T): T | undefined {\n if (!value) return undefined;\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n }\n\n /**\n * Map a database row + message rows to an AIConversation.\n */\n private toConversation(row: DbConversationRow, messageRows: DbMessageRow[]): AIConversation {\n return {\n id: row.id,\n title: row.title ?? undefined,\n agentId: row.agent_id ?? undefined,\n userId: row.user_id ?? undefined,\n messages: messageRows.map(m => this.toMessage(m)),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n metadata: this.safeParse<Record<string, unknown>>(row.metadata),\n };\n }\n\n /**\n * Map a database row to an AIMessage.\n */\n private toMessage(row: DbMessageRow): AIMessage {\n const msg: AIMessage = {\n role: row.role,\n content: row.content,\n };\n const toolCalls = this.safeParse<any[]>(row.tool_calls);\n if (toolCalls) {\n msg.toolCalls = toolCalls;\n }\n if (row.tool_call_id) {\n msg.toolCallId = row.tool_call_id;\n }\n return msg;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * ai_conversations — AI Conversation Object\n *\n * Stores conversation metadata for persistent AI conversation management.\n * Messages are stored separately in `ai_messages` to support efficient\n * querying and pagination.\n *\n * @namespace ai\n */\nexport const AiConversationObject = ObjectSchema.create({\n namespace: 'ai',\n name: 'conversations',\n label: 'AI Conversation',\n pluralLabel: 'AI Conversations',\n icon: 'message-square',\n isSystem: true,\n description: 'Persistent AI conversation metadata',\n\n fields: {\n id: Field.text({\n label: 'Conversation ID',\n required: true,\n readonly: true,\n }),\n\n title: Field.text({\n label: 'Title',\n required: false,\n maxLength: 500,\n description: 'Conversation title or summary',\n }),\n\n agent_id: Field.text({\n label: 'Agent ID',\n required: false,\n maxLength: 255,\n description: 'Associated AI agent identifier',\n }),\n\n user_id: Field.text({\n label: 'User ID',\n required: false,\n maxLength: 255,\n description: 'User who owns the conversation',\n }),\n\n metadata: Field.textarea({\n label: 'Metadata',\n required: false,\n description: 'JSON-serialized conversation metadata',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['user_id'] },\n { fields: ['agent_id'] },\n { fields: ['created_at'] },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * ai_messages — AI Message Object\n *\n * Stores individual messages within an AI conversation.\n * Each message belongs to a conversation via `conversation_id` foreign key.\n *\n * @namespace ai\n */\nexport const AiMessageObject = ObjectSchema.create({\n namespace: 'ai',\n name: 'messages',\n label: 'AI Message',\n pluralLabel: 'AI Messages',\n icon: 'message-circle',\n isSystem: true,\n description: 'Individual messages within AI conversations',\n\n fields: {\n id: Field.text({\n label: 'Message ID',\n required: true,\n readonly: true,\n }),\n\n conversation_id: Field.text({\n label: 'Conversation ID',\n required: true,\n description: 'Foreign key to ai_conversations',\n }),\n\n role: Field.select({\n label: 'Role',\n required: true,\n options: [\n { label: 'System', value: 'system' },\n { label: 'User', value: 'user' },\n { label: 'Assistant', value: 'assistant' },\n { label: 'Tool', value: 'tool' },\n ],\n }),\n\n content: Field.textarea({\n label: 'Content',\n required: true,\n description: 'Message content',\n }),\n\n tool_calls: Field.textarea({\n label: 'Tool Calls',\n required: false,\n description: 'JSON-serialized tool calls (when role=assistant)',\n }),\n\n tool_call_id: Field.text({\n label: 'Tool Call ID',\n required: false,\n maxLength: 255,\n description: 'ID of the tool call this message responds to (when role=tool)',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['conversation_id'] },\n { fields: ['conversation_id', 'created_at'] },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { AIToolDefinition, IDataEngine, IMetadataService } from '@objectstack/spec/contracts';\nimport type { ToolHandler } from './tool-registry.js';\nimport type { ToolRegistry } from './tool-registry.js';\n\n// ---------------------------------------------------------------------------\n// Internal type aliases for metadata payloads (returned as `unknown` from\n// IMetadataService — we cast to these lightweight shapes for field access).\n// ---------------------------------------------------------------------------\n\n/** Minimal shape of an object definition as returned by IMetadataService. */\ninterface ObjectDef {\n name: string;\n label?: string;\n fields?: Record<string, FieldDef>;\n}\n\n/** Minimal shape of a field definition inside an object. */\ninterface FieldDef {\n type?: string;\n label?: string;\n required?: boolean;\n reference?: string;\n options?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Data context — injected once at registration time\n// ---------------------------------------------------------------------------\n\n/**\n * Services required by the built-in data tools.\n *\n * These are provided by the kernel at `ai:ready` time and closed over\n * by the handler functions so they stay framework-agnostic.\n */\nexport interface DataToolContext {\n /** ObjectQL data engine for record-level operations. */\n dataEngine: IDataEngine;\n /** Metadata service for schema/object introspection. */\n metadataService: IMetadataService;\n}\n\n// ---------------------------------------------------------------------------\n// Tool Definitions\n// ---------------------------------------------------------------------------\n\n/** Maximum number of records a single query may return. */\nconst MAX_QUERY_LIMIT = 200;\n\n/** Default record limit when not specified. */\nconst DEFAULT_QUERY_LIMIT = 20;\n\nexport const LIST_OBJECTS_TOOL: AIToolDefinition = {\n name: 'list_objects',\n description: 'List all available data objects (tables) in the system. Returns object names and labels.',\n parameters: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n};\n\nexport const DESCRIBE_OBJECT_TOOL: AIToolDefinition = {\n name: 'describe_object',\n description:\n 'Get the schema (fields, types, labels) of a specific data object. ' +\n 'Use this to understand the structure of a table before querying it.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object to describe',\n },\n },\n required: ['objectName'],\n additionalProperties: false,\n },\n};\n\nexport const QUERY_RECORDS_TOOL: AIToolDefinition = {\n name: 'query_records',\n description:\n 'Query records from a data object with optional filters, field selection, ' +\n 'sorting, and pagination. Returns an array of matching records.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object to query',\n },\n where: {\n type: 'object',\n description:\n 'Filter conditions as key-value pairs (e.g. { \"status\": \"active\" }) ' +\n 'or MongoDB-style operators (e.g. { \"amount\": { \"$gt\": 100 } })',\n },\n fields: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of field names to return (omit for all fields)',\n },\n orderBy: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n field: { type: 'string' },\n order: { type: 'string', enum: ['asc', 'desc'] },\n },\n },\n description: 'Sort order (e.g. [{ \"field\": \"created_at\", \"order\": \"desc\" }])',\n },\n limit: {\n type: 'number',\n description: `Maximum number of records to return (default ${DEFAULT_QUERY_LIMIT}, max ${MAX_QUERY_LIMIT})`,\n },\n offset: {\n type: 'number',\n description: 'Number of records to skip for pagination',\n },\n },\n required: ['objectName'],\n additionalProperties: false,\n },\n};\n\nexport const GET_RECORD_TOOL: AIToolDefinition = {\n name: 'get_record',\n description: 'Get a single record by its ID from a data object.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object',\n },\n recordId: {\n type: 'string',\n description: 'The unique ID of the record',\n },\n fields: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of field names to return (omit for all fields)',\n },\n },\n required: ['objectName', 'recordId'],\n additionalProperties: false,\n },\n};\n\nexport const AGGREGATE_DATA_TOOL: AIToolDefinition = {\n name: 'aggregate_data',\n description:\n 'Perform aggregation/statistical operations on a data object. ' +\n 'Supports count, sum, avg, min, max with optional groupBy and where filters.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object to aggregate',\n },\n aggregations: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n function: {\n type: 'string',\n enum: ['count', 'sum', 'avg', 'min', 'max', 'count_distinct'],\n description: 'Aggregation function',\n },\n field: {\n type: 'string',\n description: 'Field to aggregate (optional for count)',\n },\n alias: {\n type: 'string',\n description: 'Result column alias',\n },\n },\n required: ['function', 'alias'],\n },\n description: 'Aggregation definitions',\n },\n groupBy: {\n type: 'array',\n items: { type: 'string' },\n description: 'Fields to group by',\n },\n where: {\n type: 'object',\n description: 'Filter conditions applied before aggregation',\n },\n },\n required: ['objectName', 'aggregations'],\n additionalProperties: false,\n },\n};\n\n/** All built-in data tool definitions. */\nexport const DATA_TOOL_DEFINITIONS: AIToolDefinition[] = [\n LIST_OBJECTS_TOOL,\n DESCRIBE_OBJECT_TOOL,\n QUERY_RECORDS_TOOL,\n GET_RECORD_TOOL,\n AGGREGATE_DATA_TOOL,\n];\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createListObjectsHandler(ctx: DataToolContext): ToolHandler {\n return async () => {\n const objects = await ctx.metadataService.listObjects();\n const summary = (objects as ObjectDef[]).map(o => ({\n name: o.name,\n label: o.label ?? o.name,\n }));\n return JSON.stringify(summary);\n };\n}\n\nfunction createDescribeObjectHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const { objectName } = args as { objectName: string };\n const objectDef = await ctx.metadataService.getObject(objectName);\n if (!objectDef) {\n return JSON.stringify({ error: `Object \"${objectName}\" not found` });\n }\n\n const def = objectDef as ObjectDef;\n const fields = def.fields ?? {};\n const fieldSummary: Record<string, Record<string, unknown>> = {};\n for (const [key, f] of Object.entries(fields)) {\n fieldSummary[key] = {\n type: f.type,\n label: f.label ?? key,\n required: f.required ?? false,\n ...(f.reference ? { reference: f.reference } : {}),\n ...(f.options ? { options: f.options } : {}),\n };\n }\n\n return JSON.stringify({\n name: def.name,\n label: def.label ?? def.name,\n fields: fieldSummary,\n });\n };\n}\n\nfunction createQueryRecordsHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const {\n objectName,\n where,\n fields,\n orderBy,\n limit,\n offset,\n } = args as {\n objectName: string;\n where?: Record<string, unknown>;\n fields?: string[];\n orderBy?: Array<{ field: string; order: 'asc' | 'desc' }>;\n limit?: number;\n offset?: number;\n };\n\n // Validate and clamp limit to [1, MAX_QUERY_LIMIT]\n const rawLimit = limit ?? DEFAULT_QUERY_LIMIT;\n const safeLimit = Number.isFinite(rawLimit) && rawLimit > 0\n ? Math.min(Math.floor(rawLimit), MAX_QUERY_LIMIT)\n : DEFAULT_QUERY_LIMIT;\n\n // Validate offset: must be a non-negative finite integer\n const safeOffset = (Number.isFinite(offset) && (offset as number) >= 0)\n ? Math.floor(offset as number)\n : undefined;\n\n const records = await ctx.dataEngine.find(objectName, {\n where,\n fields,\n orderBy,\n limit: safeLimit,\n offset: safeOffset,\n });\n\n return JSON.stringify({ count: records.length, records });\n };\n}\n\nfunction createGetRecordHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, recordId, fields } = args as {\n objectName: string;\n recordId: string;\n fields?: string[];\n };\n\n const record = await ctx.dataEngine.findOne(objectName, {\n where: { id: recordId },\n fields,\n });\n\n if (!record) {\n return JSON.stringify({ error: `Record \"${recordId}\" not found in \"${objectName}\"` });\n }\n\n return JSON.stringify(record);\n };\n}\n\n/** Aggregation function names supported by the data engine. */\ntype AggFn = 'count' | 'sum' | 'avg' | 'min' | 'max' | 'count_distinct';\n\n/** Set of valid aggregation function names for runtime validation. */\nconst VALID_AGG_FUNCTIONS = new Set<string>([\n 'count', 'sum', 'avg', 'min', 'max', 'count_distinct',\n]);\n\nfunction createAggregateDataHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, aggregations, groupBy, where } = args as {\n objectName: string;\n aggregations: Array<{ function: string; field?: string; alias: string }>;\n groupBy?: string[];\n where?: Record<string, unknown>;\n };\n\n // Validate aggregation functions at runtime\n for (const a of aggregations) {\n if (!VALID_AGG_FUNCTIONS.has(a.function)) {\n return JSON.stringify({\n error: `Invalid aggregation function \"${a.function}\". ` +\n `Allowed: ${[...VALID_AGG_FUNCTIONS].join(', ')}`,\n });\n }\n }\n\n const result = await ctx.dataEngine.aggregate(objectName, {\n where,\n groupBy,\n aggregations: aggregations.map(a => ({\n function: a.function as AggFn,\n field: a.field,\n alias: a.alias,\n })),\n });\n\n return JSON.stringify(result);\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public Registration Helper\n// ---------------------------------------------------------------------------\n\n/**\n * Register all built-in data tools on the given {@link ToolRegistry}.\n *\n * Typically called from the `ai:ready` hook after both the data engine\n * and metadata service are available.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const dataEngine = ctx.getService<IDataEngine>('data');\n * const metadataService = ctx.getService<IMetadataService>('metadata');\n * registerDataTools(aiService.toolRegistry, { dataEngine, metadataService });\n * });\n * ```\n */\nexport function registerDataTools(\n registry: ToolRegistry,\n context: DataToolContext,\n): void {\n registry.register(LIST_OBJECTS_TOOL, createListObjectsHandler(context));\n registry.register(DESCRIBE_OBJECT_TOOL, createDescribeObjectHandler(context));\n registry.register(QUERY_RECORDS_TOOL, createQueryRecordsHandler(context));\n registry.register(GET_RECORD_TOOL, createGetRecordHandler(context));\n registry.register(AGGREGATE_DATA_TOOL, createAggregateDataHandler(context));\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIMessage,\n AIRequestOptions,\n AIToolDefinition,\n IMetadataService,\n} from '@objectstack/spec/contracts';\nimport type { Agent } from '@objectstack/spec';\nimport { AgentSchema } from '@objectstack/spec/ai';\n\n/**\n * Context passed alongside a user message when chatting with an agent.\n *\n * UI clients set these fields to tell the agent which object, record,\n * or view the user is currently looking at so it can provide contextual\n * answers without additional tool calls.\n */\nexport interface AgentChatContext {\n /** Current object the user is viewing (e.g. \"account\") */\n objectName?: string;\n /** Currently selected record ID */\n recordId?: string;\n /** Current view name */\n viewName?: string;\n}\n\n/**\n * AgentRuntime — Resolves an agent definition into runnable chat parameters.\n *\n * Responsibilities:\n * 1. Load & validate agent metadata from the metadata service.\n * 2. Build the system prompt from agent `instructions` + UI context.\n * 3. Derive {@link AIRequestOptions} from agent `model` and `tools`.\n * 4. Map agent tool references to concrete {@link AIToolDefinition}s\n * registered in the {@link ToolRegistry}.\n */\nexport class AgentRuntime {\n constructor(private readonly metadataService: IMetadataService) {}\n\n // ── Public API ────────────────────────────────────────────────\n\n /**\n * Load and validate an agent definition by name.\n *\n * The raw metadata is validated through {@link AgentSchema} to ensure\n * required fields (`instructions`, `name`, `role`, etc.) are present\n * and well-typed. Returns `undefined` when the agent does not exist\n * or validation fails.\n */\n async loadAgent(agentName: string): Promise<Agent | undefined> {\n const raw = await this.metadataService.get('agent', agentName);\n if (!raw) return undefined;\n\n const result = AgentSchema.safeParse(raw);\n if (!result.success) {\n return undefined;\n }\n return result.data;\n }\n\n /**\n * Build the system message(s) that should be prepended to the\n * conversation when chatting with the given agent.\n */\n buildSystemMessages(agent: Agent, context?: AgentChatContext): AIMessage[] {\n const parts: string[] = [];\n\n // Base instructions\n parts.push(agent.instructions);\n\n // Contextual hints from the user's current UI state\n if (context) {\n const ctx: string[] = [];\n if (context.objectName) ctx.push(`Current object: ${context.objectName}`);\n if (context.recordId) ctx.push(`Selected record ID: ${context.recordId}`);\n if (context.viewName) ctx.push(`Current view: ${context.viewName}`);\n if (ctx.length > 0) {\n parts.push('\\n--- Current Context ---\\n' + ctx.join('\\n'));\n }\n }\n\n return [{ role: 'system', content: parts.join('\\n') }];\n }\n\n /**\n * Derive {@link AIRequestOptions} from an agent definition.\n *\n * Tool references declared in `agent.tools` are resolved by name against\n * `availableTools` (i.e. the full set of ToolRegistry definitions).\n * Any unresolved references (tools the agent declares but that are not\n * registered) are silently skipped — this is intentional so that agents\n * can be defined before all tools are available.\n *\n * @param agent - The agent definition to derive options from\n * @param availableTools - All tool definitions currently registered in the ToolRegistry\n * @returns Request options with model config and resolved tool definitions\n */\n buildRequestOptions(\n agent: Agent,\n availableTools: AIToolDefinition[],\n ): AIRequestOptions {\n const options: AIRequestOptions = {};\n\n // Model config\n if (agent.model) {\n options.model = agent.model.model;\n options.temperature = agent.model.temperature;\n options.maxTokens = agent.model.maxTokens;\n }\n\n // Resolve agent tool references → concrete tool definitions\n if (agent.tools && agent.tools.length > 0) {\n const toolMap = new Map(availableTools.map(t => [t.name, t]));\n const resolved: AIToolDefinition[] = [];\n for (const ref of agent.tools) {\n const def = toolMap.get(ref.name);\n if (def) {\n resolved.push(def);\n }\n }\n if (resolved.length > 0) {\n options.tools = resolved;\n options.toolChoice = 'auto';\n }\n }\n\n return options;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Agent } from '@objectstack/spec';\n\n/**\n * Built-in `data_chat` agent definition.\n *\n * This agent powers the Airtable-style data conversation Chatbot.\n * It is registered automatically by the AI service plugin when a\n * data engine is available.\n *\n * @example\n * ```\n * POST /api/v1/ai/agents/data_chat/chat\n * {\n * \"messages\": [{ \"role\": \"user\", \"content\": \"Show me all active accounts\" }],\n * \"context\": { \"objectName\": \"account\" }\n * }\n * ```\n */\nexport const DATA_CHAT_AGENT: Agent = {\n name: 'data_chat',\n label: 'Data Assistant',\n role: 'Business Data Analyst',\n instructions: `You are a helpful data assistant that helps users explore and understand their business data through natural language.\n\nCapabilities:\n- List available data objects (tables) and their schemas\n- Query records with filters, sorting, and pagination\n- Look up individual records by ID\n- Perform aggregations and statistical analysis (count, sum, avg, min, max)\n\nGuidelines:\n1. Always use the describe_object tool first to understand a table's structure before querying it.\n2. Respect the user's current context — if they are viewing a specific object or record, use that as the default scope.\n3. When presenting data, format it in a clear and readable way using markdown tables or bullet lists.\n4. For large result sets, summarize the data and mention the total count.\n5. When performing aggregations, explain the results in plain language.\n6. If a query returns no results, suggest possible reasons and alternative queries.\n7. Never expose internal IDs unless the user explicitly asks for them.\n8. Always answer in the same language the user is using.`,\n\n model: {\n provider: 'openai',\n model: 'gpt-4',\n temperature: 0.3,\n maxTokens: 4096,\n },\n\n tools: [\n { type: 'query', name: 'list_objects', description: 'List all available data objects' },\n { type: 'query', name: 'describe_object', description: 'Get schema/fields of a data object' },\n { type: 'query', name: 'query_records', description: 'Query records with filters and pagination' },\n { type: 'query', name: 'get_record', description: 'Get a single record by ID' },\n { type: 'query', name: 'aggregate_data', description: 'Aggregate/statistics on data' },\n ],\n\n active: true,\n visibility: 'global',\n\n guardrails: {\n maxTokensPerInvocation: 8192,\n maxExecutionTimeSec: 30,\n blockedTopics: ['delete_records', 'drop_table', 'alter_schema'],\n },\n\n planning: {\n strategy: 'react',\n maxIterations: 5,\n allowReplan: false,\n },\n\n memory: {\n shortTerm: {\n maxMessages: 20,\n maxTokens: 4096,\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { IAIService, IAIConversationService, IDataEngine, IMetadataService, LLMAdapter } from '@objectstack/spec/contracts';\nimport { AIService } from './ai-service.js';\nimport type { AIServiceConfig } from './ai-service.js';\nimport { buildAIRoutes } from './routes/ai-routes.js';\nimport { buildAgentRoutes } from './routes/agent-routes.js';\nimport { ObjectQLConversationService } from './conversation/objectql-conversation-service.js';\nimport { AiConversationObject, AiMessageObject } from './objects/index.js';\nimport { registerDataTools } from './tools/data-tools.js';\nimport { AgentRuntime } from './agent-runtime.js';\nimport { DATA_CHAT_AGENT } from './agents/index.js';\n\n/**\n * Configuration options for the AIServicePlugin.\n */\nexport interface AIServicePluginOptions {\n /** LLM adapter to use (defaults to MemoryLLMAdapter). */\n adapter?: LLMAdapter;\n /** Enable debug logging. */\n debug?: boolean;\n /** Explicit conversation service override. When set, auto-detection is skipped. */\n conversationService?: IAIConversationService;\n}\n\n/**\n * AIServicePlugin — Kernel plugin for the unified AI capability service.\n *\n * Lifecycle:\n * 1. **init** — Creates {@link AIService}, registers as `'ai'` service.\n * If an existing AI service is already registered, it is replaced.\n * 2. **start** — Triggers `'ai:ready'` hook so other plugins can register\n * tools or extend the service. Registers REST/SSE routes.\n * 3. **destroy** — Cleans up references.\n *\n * @example\n * ```ts\n * import { LiteKernel } from '@objectstack/core';\n * import { AIServicePlugin } from '@objectstack/service-ai';\n *\n * const kernel = new LiteKernel();\n * kernel.use(new AIServicePlugin());\n * await kernel.bootstrap();\n *\n * const ai = kernel.getService<IAIService>('ai');\n * const result = await ai.chat([{ role: 'user', content: 'Hello' }]);\n * ```\n */\nexport class AIServicePlugin implements Plugin {\n name = 'com.objectstack.service-ai';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies: string[] = [];\n\n private service?: AIService;\n private readonly options: AIServicePluginOptions;\n\n constructor(options: AIServicePluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n // Check if there is an existing AI service (e.g. from dev-plugin)\n let hasExisting = false;\n try {\n const existing = ctx.getService<IAIService>('ai');\n if (existing && typeof existing.chat === 'function') {\n hasExisting = true;\n ctx.logger.debug('[AI] Found existing AI service, replacing');\n }\n } catch {\n // No existing service — that's fine\n }\n\n // Determine conversation service: explicit > auto-detect IDataEngine > InMemory fallback\n let conversationService: IAIConversationService | undefined = this.options.conversationService;\n if (!conversationService) {\n try {\n const engine = ctx.getService<IDataEngine>('data');\n if (engine && typeof engine.find === 'function') {\n conversationService = new ObjectQLConversationService(engine);\n ctx.logger.info('[AI] Using ObjectQLConversationService (IDataEngine detected)');\n }\n } catch {\n // No data engine — fall back to InMemory\n }\n }\n\n const config: AIServiceConfig = {\n adapter: this.options.adapter,\n logger: ctx.logger,\n conversationService,\n };\n\n this.service = new AIService(config);\n\n // Register or replace the AI service\n if (hasExisting) {\n ctx.replaceService('ai', this.service);\n } else {\n ctx.registerService('ai', this.service);\n }\n\n // Register AI system objects so ObjectQLPlugin auto-discovers them\n ctx.registerService('app.com.objectstack.service-ai', {\n id: 'com.objectstack.service-ai',\n name: 'AI Service',\n version: '1.0.0',\n type: 'plugin',\n namespace: 'ai',\n objects: [AiConversationObject, AiMessageObject],\n });\n\n if (this.options.debug) {\n ctx.hook('ai:beforeChat', async (messages: unknown) => {\n ctx.logger.debug('[AI] Before chat', { messages });\n });\n }\n\n ctx.logger.info('[AI] Service initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (!this.service) return;\n\n // ── Auto-register built-in data tools if data engine + metadata are available ──\n try {\n const dataEngine = ctx.getService<IDataEngine>('data');\n const metadataService = ctx.getService<IMetadataService>('metadata');\n if (dataEngine && metadataService) {\n registerDataTools(this.service.toolRegistry, { dataEngine, metadataService });\n ctx.logger.info('[AI] Built-in data tools registered');\n\n // Register the built-in data_chat agent only if it does not already exist\n const agentExists =\n typeof metadataService.exists === 'function'\n ? await metadataService.exists('agent', DATA_CHAT_AGENT.name)\n : false;\n\n if (!agentExists) {\n await metadataService.register('agent', DATA_CHAT_AGENT.name, DATA_CHAT_AGENT);\n ctx.logger.info('[AI] data_chat agent registered');\n } else {\n ctx.logger.debug('[AI] data_chat agent already exists, skipping auto-registration');\n }\n }\n } catch {\n // Data engine or metadata service not available — skip data tools\n ctx.logger.debug('[AI] Data engine or metadata service not available, skipping data tools');\n }\n\n // Trigger hook to notify AI service is ready — other plugins can register tools\n await ctx.trigger('ai:ready', this.service);\n\n // Build and expose route definitions\n const routes = buildAIRoutes(this.service, this.service.conversationService, ctx.logger);\n\n // Build agent routes if metadata service is available\n try {\n const metadataService = ctx.getService<IMetadataService>('metadata');\n if (metadataService) {\n const agentRuntime = new AgentRuntime(metadataService);\n const agentRoutes = buildAgentRoutes(this.service, agentRuntime, ctx.logger);\n routes.push(...agentRoutes);\n }\n } catch {\n ctx.logger.debug('[AI] Metadata service not available, skipping agent routes');\n }\n\n // Trigger hook so HTTP server plugins can mount these routes\n await ctx.trigger('ai:routes', routes);\n\n ctx.logger.info(\n `[AI] Service started — adapter=\"${this.service.adapterName}\", ` +\n `tools=${this.service.toolRegistry.size}, ` +\n `routes=${routes.length}`,\n );\n }\n\n async destroy(): Promise<void> {\n this.service = undefined;\n }\n}\n"],"mappings":"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","names":["result","import_data"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/ai-service.ts","../src/adapters/memory-adapter.ts","../src/tools/tool-registry.ts","../src/conversation/in-memory-conversation-service.ts","../src/stream/vercel-stream-encoder.ts","../src/routes/ai-routes.ts","../src/routes/agent-routes.ts","../src/conversation/objectql-conversation-service.ts","../src/objects/ai-conversation.object.ts","../src/objects/ai-message.object.ts","../src/tools/data-tools.ts","../src/tools/create-object.tool.ts","../src/tools/add-field.tool.ts","../src/tools/modify-field.tool.ts","../src/tools/delete-field.tool.ts","../src/tools/list-metadata-objects.tool.ts","../src/tools/describe-metadata-object.tool.ts","../src/tools/metadata-tools.ts","../src/agent-runtime.ts","../src/agents/data-chat-agent.ts","../src/agents/metadata-assistant-agent.ts","../src/adapters/vercel-adapter.ts","../src/plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n// Core service\nexport { AIService } from './ai-service.js';\nexport type { AIServiceConfig } from './ai-service.js';\n\n// Kernel plugin\nexport { AIServicePlugin } from './plugin.js';\nexport type { AIServicePluginOptions } from './plugin.js';\n\n// Adapters\nexport { MemoryLLMAdapter } from './adapters/memory-adapter.js';\nexport { VercelLLMAdapter } from './adapters/vercel-adapter.js';\nexport type { VercelLLMAdapterConfig } from './adapters/vercel-adapter.js';\nexport type { LLMAdapter } from '@objectstack/spec/contracts';\n\n// Vercel Data Stream encoder\nexport { encodeStreamPart, encodeVercelDataStream } from './stream/vercel-stream-encoder.js';\n\n// Conversation\nexport { InMemoryConversationService } from './conversation/in-memory-conversation-service.js';\nexport { ObjectQLConversationService } from './conversation/objectql-conversation-service.js';\n\n// Tool registry\nexport { ToolRegistry } from './tools/tool-registry.js';\nexport type { ToolHandler, ToolExecutionResult } from './tools/tool-registry.js';\n\n// Data tools\nexport { registerDataTools, DATA_TOOL_DEFINITIONS } from './tools/data-tools.js';\nexport type { DataToolContext } from './tools/data-tools.js';\n\n// Metadata tools\nexport { registerMetadataTools, METADATA_TOOL_DEFINITIONS } from './tools/metadata-tools.js';\nexport type { MetadataToolContext } from './tools/metadata-tools.js';\n\n// Individual tool metadata (first-class Tool definitions via defineTool)\nexport {\n createObjectTool,\n addFieldTool,\n modifyFieldTool,\n deleteFieldTool,\n listMetadataObjectsTool,\n describeMetadataObjectTool,\n} from './tools/metadata-tools.js';\n\n// Agent runtime\nexport { AgentRuntime } from './agent-runtime.js';\nexport type { AgentChatContext } from './agent-runtime.js';\n\n// Built-in agents\nexport { DATA_CHAT_AGENT, METADATA_ASSISTANT_AGENT } from './agents/index.js';\n\n// Object definitions\nexport { AiConversationObject, AiMessageObject } from './objects/index.js';\n\n// Routes\nexport { buildAIRoutes } from './routes/ai-routes.js';\nexport { buildAgentRoutes } from './routes/agent-routes.js';\nexport type { RouteDefinition, RouteRequest, RouteResponse, RouteUserContext } from './routes/ai-routes.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ModelMessage,\n ToolCallPart,\n TextStreamPart,\n ToolSet,\n AIRequestOptions,\n AIResult,\n IAIService,\n IAIConversationService,\n ChatWithToolsOptions,\n LLMAdapter,\n} from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport { createLogger } from '@objectstack/core';\nimport { MemoryLLMAdapter } from './adapters/memory-adapter.js';\nimport { ToolRegistry } from './tools/tool-registry.js';\nimport type { ToolExecutionResult } from './tools/tool-registry.js';\nimport { InMemoryConversationService } from './conversation/in-memory-conversation-service.js';\n\n// ── Stream event helpers ──────────────────────────────────────────\n// These helpers construct properly-typed Vercel AI SDK stream parts\n// to avoid repeated `as unknown as TextStreamPart<ToolSet>` casts.\n\n/** Create a text-delta stream part. */\nfunction textDeltaPart(id: string, text: string): TextStreamPart<ToolSet> {\n return { type: 'text-delta', id, text } as TextStreamPart<ToolSet>;\n}\n\n/** Create a finish stream part from an AIResult. */\nfunction finishPart(result?: AIResult): TextStreamPart<ToolSet> {\n return {\n type: 'finish',\n finishReason: 'stop',\n totalUsage: result?.usage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n rawFinishReason: 'stop',\n } as unknown as TextStreamPart<ToolSet>;\n}\n\n/**\n * Configuration for AIService.\n */\nexport interface AIServiceConfig {\n /** LLM adapter to delegate calls to (defaults to MemoryLLMAdapter). */\n adapter?: LLMAdapter;\n /** Logger instance. */\n logger?: Logger;\n /** Pre-registered tools. */\n toolRegistry?: ToolRegistry;\n /** Conversation service (defaults to InMemoryConversationService). */\n conversationService?: IAIConversationService;\n}\n\n/**\n * AIService — Unified AI capability service.\n *\n * Implements {@link IAIService} by delegating to a pluggable {@link LLMAdapter}\n * and managing tools and conversations through dedicated sub-components:\n *\n * | Component | Responsibility |\n * |:---|:---|\n * | {@link LLMAdapter} | LLM provider abstraction (chat, complete, stream, embed) |\n * | {@link ToolRegistry} | Tool definition storage & execution |\n * | {@link IAIConversationService} | Conversation CRUD & message persistence |\n *\n * The service is registered as `'ai'` in the kernel service registry by\n * the {@link AIServicePlugin}.\n */\nexport class AIService implements IAIService {\n private readonly adapter: LLMAdapter;\n private readonly logger: Logger;\n readonly toolRegistry: ToolRegistry;\n readonly conversationService: IAIConversationService;\n\n constructor(config: AIServiceConfig = {}) {\n this.adapter = config.adapter ?? new MemoryLLMAdapter();\n this.logger = config.logger ?? createLogger({ level: 'info', format: 'pretty' });\n this.toolRegistry = config.toolRegistry ?? new ToolRegistry();\n this.conversationService = config.conversationService ?? new InMemoryConversationService();\n\n this.logger.info(\n `[AI] Service initialized with adapter=\"${this.adapter.name}\", ` +\n `tools=${this.toolRegistry.size}`,\n );\n }\n\n /** The name of the active LLM adapter. */\n get adapterName(): string {\n return this.adapter.name;\n }\n\n // ── IAIService implementation ──────────────────────────────────\n\n async chat(messages: ModelMessage[], options?: AIRequestOptions): Promise<AIResult> {\n this.logger.debug('[AI] chat', { messageCount: messages.length, model: options?.model });\n return this.adapter.chat(messages, options);\n }\n\n async complete(prompt: string, options?: AIRequestOptions): Promise<AIResult> {\n this.logger.debug('[AI] complete', { promptLength: prompt.length, model: options?.model });\n return this.adapter.complete(prompt, options);\n }\n\n async *streamChat(\n messages: ModelMessage[],\n options?: AIRequestOptions,\n ): AsyncIterable<TextStreamPart<ToolSet>> {\n this.logger.debug('[AI] streamChat', { messageCount: messages.length, model: options?.model });\n\n if (!this.adapter.streamChat) {\n // Fallback: emit the entire response as a single text-delta + finish\n const result = await this.adapter.chat(messages, options);\n yield textDeltaPart('fallback', result.content);\n yield finishPart(result);\n return;\n }\n\n yield* this.adapter.streamChat(messages, options);\n }\n\n async embed(input: string | string[], model?: string): Promise<number[][]> {\n if (!this.adapter.embed) {\n throw new Error(`[AI] Adapter \"${this.adapter.name}\" does not support embeddings`);\n }\n return this.adapter.embed(input, model);\n }\n\n async listModels(): Promise<string[]> {\n if (!this.adapter.listModels) {\n return [];\n }\n return this.adapter.listModels();\n }\n\n // ── Tool Call Loop ────────────────────────────────────────────\n\n /** Default maximum iterations for the tool call loop. */\n static readonly DEFAULT_MAX_ITERATIONS = 10;\n\n /** Extract the text value from a ToolExecutionResult's output. */\n private static extractOutputText(tr: ToolExecutionResult): string {\n return tr.output && typeof tr.output === 'object' && 'value' in tr.output\n ? String(tr.output.value) : 'unknown error';\n }\n\n /**\n * Chat with automatic tool call resolution.\n *\n * 1. Merges registered tool definitions into `options.tools`.\n * 2. Calls the LLM adapter.\n * 3. If the response contains `toolCalls`, executes them via the\n * {@link ToolRegistry}, appends tool results as `role: 'tool'`\n * messages, and loops back to step 2.\n * 4. Repeats until the model produces a final text response or the\n * maximum number of iterations (`maxIterations`) is reached.\n */\n async chatWithTools(\n messages: ModelMessage[],\n options?: ChatWithToolsOptions,\n ): Promise<AIResult> {\n // Destructure loop-specific options so they are never forwarded to the adapter\n const { maxIterations: maxIter, onToolError, ...restOptions } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n\n // Merge registered tools with any explicitly provided tools\n const mergedTools = [\n ...registeredTools,\n ...(restOptions.tools ?? []),\n ];\n\n // Build the options that will be sent to every LLM call in the loop\n const chatOptions: AIRequestOptions = {\n ...restOptions,\n tools: mergedTools.length > 0 ? mergedTools : undefined,\n toolChoice: mergedTools.length > 0 ? (restOptions.toolChoice ?? 'auto') : undefined,\n };\n\n // Working copy of the conversation\n const conversation = [...messages];\n\n // Track errors across iterations for diagnostics\n const toolErrors: Array<{ iteration: number; toolName: string; error: string }> = [];\n\n this.logger.debug('[AI] chatWithTools start', {\n messageCount: conversation.length,\n toolCount: mergedTools.length,\n maxIterations,\n });\n\n let abortedByCallback = false;\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n const result = await this.adapter.chat(conversation, chatOptions);\n\n // If the model did not request any tool calls we're done\n if (!result.toolCalls || result.toolCalls.length === 0) {\n this.logger.debug('[AI] chatWithTools finished', { iteration, content: result.content.slice(0, 80) });\n return result;\n }\n\n this.logger.debug('[AI] chatWithTools tool calls', {\n iteration,\n calls: result.toolCalls.map(tc => tc.toolName),\n });\n\n // Append the assistant's response (with tool call metadata) to the conversation\n const assistantContent: Array<{ type: 'text'; text: string } | ToolCallPart> = [];\n if (result.content) assistantContent.push({ type: 'text', text: result.content });\n assistantContent.push(...result.toolCalls);\n conversation.push({\n role: 'assistant',\n content: assistantContent,\n } as ModelMessage);\n\n // Execute all tool calls in parallel\n const toolResults: ToolExecutionResult[] = await this.toolRegistry.executeAll(result.toolCalls);\n\n // Process results: track errors and honour onToolError callback\n for (const tr of toolResults) {\n if (tr.isError) {\n // Match tool call by toolCallId for robust attribution\n const matchedCall = result.toolCalls!.find(tc => tc.toolCallId === tr.toolCallId);\n const toolName = matchedCall?.toolName ?? 'unknown';\n const errorText = AIService.extractOutputText(tr);\n const errorEntry = { iteration, toolName, error: errorText };\n toolErrors.push(errorEntry);\n this.logger.warn('[AI] chatWithTools tool error', errorEntry);\n\n if (onToolError && matchedCall) {\n const action = onToolError(matchedCall, errorText);\n if (action === 'abort') {\n abortedByCallback = true;\n }\n }\n }\n\n // Append each tool result as a `role: 'tool'` message\n conversation.push({\n role: 'tool',\n content: [tr],\n } as ModelMessage);\n }\n\n if (abortedByCallback) {\n break;\n }\n }\n\n // Distinguish user-driven abort from max-iterations exhaustion in logs\n if (abortedByCallback) {\n this.logger.warn('[AI] chatWithTools aborted by onToolError callback', { toolErrors });\n } else {\n this.logger.warn('[AI] chatWithTools max iterations reached, forcing final response', {\n toolErrors: toolErrors.length > 0 ? toolErrors : undefined,\n });\n }\n\n // Make one last call *without* tools so the model is forced to produce text.\n const finalResult = await this.adapter.chat(conversation, {\n ...chatOptions,\n tools: undefined,\n toolChoice: undefined,\n });\n return finalResult;\n }\n\n /**\n * Stream chat with automatic tool call resolution.\n *\n * Works like {@link chatWithTools} but yields SSE events. When the model\n * requests tool calls during streaming, they are executed and the results\n * fed back until a final text stream is produced.\n */\n async *streamChatWithTools(\n messages: ModelMessage[],\n options?: ChatWithToolsOptions,\n ): AsyncIterable<TextStreamPart<ToolSet>> {\n const { maxIterations: maxIter, onToolError, ...restOptions } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n\n const mergedTools = [\n ...registeredTools,\n ...(restOptions.tools ?? []),\n ];\n\n const chatOptions: AIRequestOptions = {\n ...restOptions,\n tools: mergedTools.length > 0 ? mergedTools : undefined,\n toolChoice: mergedTools.length > 0 ? (restOptions.toolChoice ?? 'auto') : undefined,\n };\n\n const conversation = [...messages];\n let abortedByCallback = false;\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Use non-streaming chat for intermediate tool-call rounds\n const result = await this.adapter.chat(conversation, chatOptions);\n\n if (!result.toolCalls || result.toolCalls.length === 0) {\n // Final round — return the probed result without an extra model call\n yield textDeltaPart('stream', result.content);\n yield finishPart(result);\n return;\n }\n\n // Emit tool-call events so the client can see tool execution progress\n for (const tc of result.toolCalls) {\n yield { type: 'tool-call', toolCallId: tc.toolCallId, toolName: tc.toolName, input: tc.input } as TextStreamPart<ToolSet>;\n }\n\n const assistantContent: Array<{ type: 'text'; text: string } | ToolCallPart> = [];\n if (result.content) assistantContent.push({ type: 'text', text: result.content });\n assistantContent.push(...result.toolCalls);\n conversation.push({\n role: 'assistant',\n content: assistantContent,\n } as ModelMessage);\n\n const toolResults: ToolExecutionResult[] = await this.toolRegistry.executeAll(result.toolCalls);\n\n for (const tr of toolResults) {\n if (tr.isError && onToolError) {\n const matchedCall = result.toolCalls!.find(tc => tc.toolCallId === tr.toolCallId);\n if (matchedCall) {\n const errorText = AIService.extractOutputText(tr);\n const action = onToolError(matchedCall, errorText);\n if (action === 'abort') {\n abortedByCallback = true;\n }\n }\n }\n conversation.push({\n role: 'tool',\n content: [tr],\n } as ModelMessage);\n }\n\n if (abortedByCallback) {\n break;\n }\n }\n\n // Forced final response (no tools) — either aborted or max iterations\n if (abortedByCallback) {\n this.logger.warn('[AI] streamChatWithTools aborted by onToolError callback');\n } else {\n this.logger.warn('[AI] streamChatWithTools max iterations reached');\n }\n const finalOptions = { ...chatOptions, tools: undefined, toolChoice: undefined };\n const result = await this.adapter.chat(conversation, finalOptions);\n yield textDeltaPart('stream', result.content);\n yield finishPart(result);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ModelMessage,\n AIRequestOptions,\n AIResult,\n TextStreamPart,\n ToolSet,\n} from '@objectstack/spec/contracts';\nimport type { LLMAdapter } from '@objectstack/spec/contracts';\n\n/**\n * MemoryLLMAdapter — deterministic in-memory adapter for testing & development.\n *\n * Always echoes back the last user message prefixed with \"[memory] \".\n * Useful for unit tests, CI pipelines, and local dev without an LLM key.\n */\nexport class MemoryLLMAdapter implements LLMAdapter {\n readonly name = 'memory';\n\n async chat(messages: ModelMessage[], options?: AIRequestOptions): Promise<AIResult> {\n const lastUserMessage = [...messages].reverse().find(m => m.role === 'user');\n const userContent = lastUserMessage?.content;\n const text = typeof userContent === 'string' ? userContent : '(complex content)';\n const content = lastUserMessage\n ? `[memory] ${text}`\n : '[memory] (no user message)';\n\n return {\n content,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n async complete(prompt: string, options?: AIRequestOptions): Promise<AIResult> {\n return {\n content: `[memory] ${prompt}`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n async *streamChat(\n messages: ModelMessage[],\n _options?: AIRequestOptions,\n ): AsyncIterable<TextStreamPart<ToolSet>> {\n const result = await this.chat(messages);\n // Emit word-by-word deltas for realistic streaming simulation\n const words = result.content.split(' ');\n for (let i = 0; i < words.length; i++) {\n const wordText = i === 0 ? words[i] : ` ${words[i]}`;\n yield { type: 'text-delta', id: `delta_${i}`, text: wordText } as TextStreamPart<ToolSet>;\n }\n yield {\n type: 'finish',\n finishReason: 'stop' as const,\n totalUsage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n rawFinishReason: 'stop',\n } as unknown as TextStreamPart<ToolSet>;\n }\n\n async embed(input: string | string[]): Promise<number[][]> {\n const texts = Array.isArray(input) ? input : [input];\n // Return deterministic zero vectors of dimension 3\n return texts.map(() => [0, 0, 0]);\n }\n\n async listModels(): Promise<string[]> {\n return ['memory'];\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { AIToolDefinition, ToolCallPart, ToolResultPart } from '@objectstack/spec/contracts';\n\n/**\n * Handler function for a registered tool.\n *\n * Receives parsed arguments and returns the tool output as a string.\n */\nexport type ToolHandler = (args: Record<string, unknown>) => Promise<string> | string;\n\n/**\n * Extended ToolResultPart that carries an `isError` flag for internal\n * error-tracking in the tool-call loop.\n */\nexport interface ToolExecutionResult extends ToolResultPart {\n isError?: boolean;\n}\n\n/**\n * ToolRegistry — Central registry for AI-callable tools.\n *\n * Plugins register tools (metadata helpers, data queries, business actions)\n * during the `ai:ready` hook. The AI service resolves tool calls against\n * this registry and feeds the results back to the LLM.\n */\nexport class ToolRegistry {\n private readonly definitions = new Map<string, AIToolDefinition>();\n private readonly handlers = new Map<string, ToolHandler>();\n\n /**\n * Register a tool with its definition and handler.\n * @param definition - Tool definition (name, description, parameters schema)\n * @param handler - Async function that executes the tool\n */\n register(definition: AIToolDefinition, handler: ToolHandler): void {\n this.definitions.set(definition.name, definition);\n this.handlers.set(definition.name, handler);\n }\n\n /**\n * Unregister a tool by name.\n */\n unregister(name: string): void {\n this.definitions.delete(name);\n this.handlers.delete(name);\n }\n\n /**\n * Check whether a tool is registered.\n */\n has(name: string): boolean {\n return this.definitions.has(name);\n }\n\n /**\n * Get the definition for a registered tool.\n */\n getDefinition(name: string): AIToolDefinition | undefined {\n return this.definitions.get(name);\n }\n\n /**\n * Return all registered tool definitions.\n */\n getAll(): AIToolDefinition[] {\n return Array.from(this.definitions.values());\n }\n\n /** Number of registered tools. */\n get size(): number {\n return this.definitions.size;\n }\n\n /** All registered tool names. */\n names(): string[] {\n return Array.from(this.definitions.keys());\n }\n\n /**\n * Execute a tool call and return the result.\n */\n async execute(toolCall: ToolCallPart): Promise<ToolExecutionResult> {\n const handler = this.handlers.get(toolCall.toolName);\n if (!handler) {\n return {\n type: 'tool-result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: { type: 'text', value: `Tool \"${toolCall.toolName}\" is not registered` },\n isError: true,\n };\n }\n\n try {\n const args = typeof toolCall.input === 'string'\n ? JSON.parse(toolCall.input)\n : (toolCall.input as Record<string, unknown>) ?? {};\n const content = await handler(args);\n return {\n type: 'tool-result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: { type: 'text', value: content },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n type: 'tool-result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: { type: 'text', value: message },\n isError: true,\n };\n }\n }\n\n /**\n * Execute multiple tool calls in parallel.\n */\n async executeAll(toolCalls: ToolCallPart[]): Promise<ToolExecutionResult[]> {\n return Promise.all(toolCalls.map(tc => this.execute(tc)));\n }\n\n /**\n * Clear all registered tools.\n */\n clear(): void {\n this.definitions.clear();\n this.handlers.clear();\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIConversation,\n ModelMessage,\n IAIConversationService,\n} from '@objectstack/spec/contracts';\n\n/**\n * InMemoryConversationService — Reference implementation of IAIConversationService.\n *\n * Stores conversations in a simple Map. Suitable for development, testing,\n * and single-process deployments. Production environments should replace\n * this with a persistent implementation (e.g., backed by ObjectQL/SQL).\n */\nexport class InMemoryConversationService implements IAIConversationService {\n private readonly store = new Map<string, AIConversation>();\n private counter = 0;\n\n async create(options: {\n title?: string;\n agentId?: string;\n userId?: string;\n metadata?: Record<string, unknown>;\n } = {}): Promise<AIConversation> {\n const now = new Date().toISOString();\n const id = `conv_${++this.counter}`;\n\n const conversation: AIConversation = {\n id,\n title: options.title,\n agentId: options.agentId,\n userId: options.userId,\n messages: [],\n createdAt: now,\n updatedAt: now,\n metadata: options.metadata,\n };\n\n this.store.set(id, conversation);\n return conversation;\n }\n\n async get(conversationId: string): Promise<AIConversation | null> {\n return this.store.get(conversationId) ?? null;\n }\n\n async list(options: {\n userId?: string;\n agentId?: string;\n limit?: number;\n cursor?: string;\n } = {}): Promise<AIConversation[]> {\n let results = Array.from(this.store.values());\n\n if (options.userId) {\n results = results.filter(c => c.userId === options.userId);\n }\n if (options.agentId) {\n results = results.filter(c => c.agentId === options.agentId);\n }\n\n // Simple cursor-based pagination: cursor = conversation ID\n if (options.cursor) {\n const idx = results.findIndex(c => c.id === options.cursor);\n if (idx >= 0) {\n results = results.slice(idx + 1);\n }\n }\n\n if (options.limit && options.limit > 0) {\n results = results.slice(0, options.limit);\n }\n\n return results;\n }\n\n async addMessage(conversationId: string, message: ModelMessage): Promise<AIConversation> {\n const conversation = this.store.get(conversationId);\n if (!conversation) {\n throw new Error(`Conversation \"${conversationId}\" not found`);\n }\n\n conversation.messages.push(message);\n conversation.updatedAt = new Date().toISOString();\n return conversation;\n }\n\n async delete(conversationId: string): Promise<void> {\n this.store.delete(conversationId);\n }\n\n /** Total number of stored conversations. */\n get size(): number {\n return this.store.size;\n }\n\n /** Clear all conversations. */\n clear(): void {\n this.store.clear();\n this.counter = 0;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Vercel AI SDK v6 — UI Message Stream Encoder\n *\n * Converts `AsyncIterable<TextStreamPart<ToolSet>>` (the internal ObjectStack\n * streaming format) into the Vercel AI SDK v6 **UI Message Stream Protocol**.\n *\n * Wire format: Server-Sent Events (SSE) with JSON payloads.\n * `data: {\"type\":\"text-delta\",\"id\":\"0\",\"delta\":\"Hello\"}\\n\\n`\n *\n * The client-side `DefaultChatTransport` from `ai` v6 uses\n * `parseJsonEventStream` to parse these SSE events.\n *\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n */\n\nimport type { TextStreamPart, ToolSet } from 'ai';\n\n// ── SSE helpers ──────────────────────────────────────────────────────\n\nfunction sse(data: object): string {\n return `data: ${JSON.stringify(data)}\\n\\n`;\n}\n\n// ── Public API ──────────────────────────────────────────────────────\n\n/**\n * Encode a single `TextStreamPart` event into SSE-formatted UI Message\n * Stream chunk(s).\n *\n * Returns an empty string for event types that have no wire-format mapping.\n */\nexport function encodeStreamPart(part: TextStreamPart<ToolSet>): string {\n switch (part.type) {\n case 'text-delta':\n return sse({ type: 'text-delta', id: '0', delta: part.text });\n\n case 'tool-input-start':\n return sse({\n type: 'tool-input-start',\n toolCallId: part.id,\n toolName: part.toolName,\n });\n\n case 'tool-input-delta':\n return sse({\n type: 'tool-input-delta',\n toolCallId: part.id,\n inputTextDelta: part.delta,\n });\n\n case 'tool-call':\n return sse({\n type: 'tool-input-available',\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n input: part.input,\n });\n\n case 'tool-result':\n return sse({\n type: 'tool-output-available',\n toolCallId: part.toolCallId,\n output: part.output,\n });\n\n case 'error':\n return sse({\n type: 'error',\n errorText: String(part.error),\n });\n\n // finish-step and finish are handled by the generator, not here\n default:\n return '';\n }\n}\n\n/**\n * Transform an `AsyncIterable<TextStreamPart>` into an `AsyncIterable<string>`\n * where each yielded string is an SSE-formatted UI Message Stream chunk.\n *\n * Lifecycle order required by the client:\n * start → start-step → text-start → text-delta* → text-end → finish-step → finish → [DONE]\n */\nexport async function* encodeVercelDataStream(\n events: AsyncIterable<TextStreamPart<ToolSet>>,\n): AsyncIterable<string> {\n // Preamble\n yield sse({ type: 'start' });\n yield sse({ type: 'start-step' });\n yield sse({ type: 'text-start', id: '0' });\n\n let textOpen = true;\n let finishReason = 'stop';\n\n for await (const part of events) {\n // Capture finish reason\n if (part.type === 'finish') {\n finishReason = part.finishReason ?? 'stop';\n }\n\n // Before finish-step/finish, close the text part first\n if (part.type === 'finish-step' || part.type === 'finish') {\n if (textOpen) {\n yield sse({ type: 'text-end', id: '0' });\n textOpen = false;\n }\n // Don't emit these via encodeStreamPart — we handle them in postamble\n continue;\n }\n\n const frame = encodeStreamPart(part);\n if (frame) {\n yield frame;\n }\n }\n\n // Close text if still open (safety)\n if (textOpen) {\n yield sse({ type: 'text-end', id: '0' });\n }\n\n // Postamble\n yield sse({ type: 'finish-step' });\n yield sse({ type: 'finish', finishReason });\n yield 'data: [DONE]\\n\\n';\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IAIService, IAIConversationService, ModelMessage } from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport { encodeVercelDataStream } from '../stream/vercel-stream-encoder.js';\n\n/**\n * Minimal HTTP handler abstraction so routes stay framework-agnostic.\n *\n * Consumers wire these handlers to their HTTP server of choice\n * (Hono, Express, Fastify, etc.) via the kernel's HTTP server service.\n */\nexport interface RouteDefinition {\n /** HTTP method */\n method: 'GET' | 'POST' | 'DELETE';\n /** Path pattern (e.g. '/api/v1/ai/chat') */\n path: string;\n /** Human-readable description */\n description: string;\n /** Whether this route requires authentication (default: true). */\n auth?: boolean;\n /** Required permissions for accessing this route. */\n permissions?: string[];\n /**\n * Handler receives a plain request-like object and returns a response-like\n * object. SSE responses set `stream: true` and provide an async iterable.\n */\n handler: (req: RouteRequest) => Promise<RouteResponse>;\n}\n\n/**\n * Authenticated user context attached to a route request.\n *\n * Populated by the auth middleware when `RouteDefinition.auth` is `true`.\n */\nexport interface RouteUserContext {\n /** Unique user identifier. */\n userId: string;\n /** User display name (optional). */\n displayName?: string;\n /** Roles assigned to the user (e.g. `['admin', 'user']`). */\n roles?: string[];\n /** Fine-grained permissions (e.g. `['ai:chat', 'ai:admin']`). */\n permissions?: string[];\n}\n\nexport interface RouteRequest {\n /** Parsed JSON body (for POST requests) */\n body?: unknown;\n /** Route/query parameters */\n params?: Record<string, string>;\n /** Query string parameters */\n query?: Record<string, string>;\n /** Authenticated user context (populated by auth middleware). */\n user?: RouteUserContext;\n}\n\nexport interface RouteResponse {\n /** HTTP status code */\n status: number;\n /** JSON-serializable body (for non-streaming responses) */\n body?: unknown;\n /** If true, `stream` provides SSE events */\n stream?: boolean;\n /** Async iterable of SSE events (when stream=true) */\n events?: AsyncIterable<unknown>;\n /**\n * When `true`, the HTTP server layer should encode the `events` iterable\n * using the Vercel AI Data Stream Protocol frame format (`0:`, `9:`, `d:`, …)\n * instead of generic SSE `data:` lines.\n *\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n */\n vercelDataStream?: boolean;\n}\n\n/** Valid message roles accepted by the AI routes. */\nconst VALID_ROLES = new Set<string>(['system', 'user', 'assistant', 'tool']);\n\n/**\n * Normalize a Vercel AI SDK v6 message (which may use `parts` instead of\n * `content`) into a plain `{ role, content }` ModelMessage.\n */\nfunction normalizeMessage(raw: Record<string, unknown>): ModelMessage {\n const role = raw.role as string;\n\n // If content is already a string, use it directly\n if (typeof raw.content === 'string') {\n return { role, content: raw.content } as unknown as ModelMessage;\n }\n\n // If content is an array (multi-part), pass through\n if (Array.isArray(raw.content)) {\n return { role, content: raw.content } as unknown as ModelMessage;\n }\n\n // Vercel AI SDK v6: extract text from `parts` array\n if (Array.isArray(raw.parts)) {\n const textParts = (raw.parts as Array<Record<string, unknown>>)\n .filter(p => p.type === 'text' && typeof p.text === 'string')\n .map(p => p.text as string);\n if (textParts.length > 0) {\n return { role, content: textParts.join('') } as unknown as ModelMessage;\n }\n }\n\n // Fallback: empty content (e.g. tool-only assistant messages)\n return { role, content: '' } as unknown as ModelMessage;\n}\n\n/**\n * Validate that `raw` is a well-formed message.\n * Returns null on success, or an error string on failure.\n *\n * Accepts:\n * - Simple string `content` (legacy)\n * - Array `content` (e.g. `[{ type: 'text', text: '...' }]`)\n * - Vercel AI SDK v6 `parts` format (content may be absent/null)\n */\nfunction validateMessage(raw: unknown): string | null {\n if (typeof raw !== 'object' || raw === null) {\n return 'each message must be an object';\n }\n const msg = raw as Record<string, unknown>;\n if (typeof msg.role !== 'string' || !VALID_ROLES.has(msg.role)) {\n return `message.role must be one of ${[...VALID_ROLES].map(r => `\"${r}\"`).join(', ')}`;\n }\n const content = msg.content;\n\n // Vercel AI SDK v6 sends `parts` instead of (or alongside) `content`.\n // Accept any message that carries a `parts` array, even when `content` is absent.\n if (Array.isArray(msg.parts)) {\n return null;\n }\n\n // content is a plain string — OK\n if (typeof content === 'string') {\n return null;\n }\n\n // content is an array of typed parts (legacy multi-part format)\n if (Array.isArray(content)) {\n for (const part of content as unknown[]) {\n if (typeof part !== 'object' || part === null) {\n return 'message.content array elements must be non-null objects';\n }\n const partObj = part as Record<string, unknown>;\n if (typeof partObj.type !== 'string') {\n return 'each message.content array element must have a string \"type\" property';\n }\n if (partObj.type === 'text' && typeof partObj.text !== 'string') {\n return 'message.content elements with type \"text\" must have a string \"text\" property';\n }\n }\n return null;\n }\n\n // Assistant / tool messages may legitimately have null or missing content\n if (content === null || content === undefined) {\n if (msg.role === 'assistant' || msg.role === 'tool') {\n return null;\n }\n }\n\n return 'message.content must be a string, an array, or include parts';\n}\n\n/**\n * Build the standard AI REST/SSE routes.\n *\n * Depends on contracts ({@link IAIService} + {@link IAIConversationService})\n * rather than concrete implementations, so any compliant service pair can\n * be wired in.\n *\n * Routes:\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | POST | /api/v1/ai/chat | Synchronous chat completion |\n * | POST | /api/v1/ai/chat/stream | SSE streaming chat completion |\n * | POST | /api/v1/ai/complete | Text completion |\n * | GET | /api/v1/ai/models | List available models |\n * | POST | /api/v1/ai/conversations | Create a conversation |\n * | GET | /api/v1/ai/conversations | List conversations |\n * | POST | /api/v1/ai/conversations/:id/messages | Add message to conversation |\n * | DELETE | /api/v1/ai/conversations/:id | Delete conversation |\n */\nexport function buildAIRoutes(\n aiService: IAIService,\n conversationService: IAIConversationService,\n logger: Logger,\n): RouteDefinition[] {\n return [\n // ── Chat ────────────────────────────────────────────────────\n //\n // Dual-mode endpoint compatible with both the legacy ObjectStack\n // format (`{ messages, options }`) and the Vercel AI SDK useChat\n // flat format (`{ messages, system, model, stream, … }`).\n //\n // Behaviour:\n // • `stream !== false` → Vercel Data Stream Protocol (SSE)\n // • `stream === false` → JSON response (legacy)\n //\n {\n method: 'POST',\n path: '/api/v1/ai/chat',\n description: 'Chat completion (supports Vercel AI Data Stream Protocol)',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n const body = (req.body ?? {}) as Record<string, unknown>;\n\n // ── Parse messages ───────────────────────────────────\n const messages = body.messages as unknown[] | undefined;\n if (!Array.isArray(messages) || messages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n\n for (const msg of messages) {\n const err = validateMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n // ── Resolve options ──────────────────────────────────\n // Accept legacy nested `options` object **or** Vercel-style\n // flat fields (`model`, `temperature`, `maxTokens`).\n const nested = (body.options ?? {}) as Record<string, unknown>;\n const resolvedOptions: Record<string, unknown> = {\n ...nested,\n ...(body.model != null && { model: body.model }),\n ...(body.temperature != null && { temperature: body.temperature }),\n ...(body.maxTokens != null && { maxTokens: body.maxTokens }),\n };\n\n // ── Prepend system prompt ────────────────────────────\n // Vercel useChat sends `system` (or the deprecated `systemPrompt`)\n // as a top-level field. We prepend it as a system message.\n const rawSystemPrompt = body.system ?? body.systemPrompt;\n if (rawSystemPrompt != null && typeof rawSystemPrompt !== 'string') {\n return { status: 400, body: { error: 'system/systemPrompt must be a string' } };\n }\n const systemPrompt = rawSystemPrompt as string | undefined;\n const finalMessages: ModelMessage[] = [\n ...(systemPrompt\n ? [{ role: 'system' as const, content: systemPrompt }]\n : []),\n ...messages.map(m => normalizeMessage(m as Record<string, unknown>)),\n ];\n\n // ── Choose response mode ─────────────────────────────\n const wantStream = body.stream !== false;\n\n if (wantStream) {\n // UI Message Stream Protocol (SSE with JSON payloads)\n try {\n if (!(aiService as any).streamChatWithTools) {\n return { status: 501, body: { error: 'Streaming is not supported by the configured AI service' } };\n }\n const events = (aiService as any).streamChatWithTools(finalMessages, resolvedOptions as any);\n return {\n status: 200,\n stream: true,\n vercelDataStream: true,\n contentType: 'text/event-stream',\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'x-vercel-ai-ui-message-stream': 'v1',\n },\n events: encodeVercelDataStream(events),\n };\n } catch (err) {\n logger.error('[AI Route] /chat stream error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n }\n\n // JSON response (non-streaming)\n try {\n const result = await (aiService as any).chatWithTools(finalMessages, resolvedOptions as any);\n return { status: 200, body: result };\n } catch (err) {\n logger.error('[AI Route] /chat error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Stream Chat (SSE) ──────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/chat/stream',\n description: 'SSE streaming chat completion',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n const { messages, options } = (req.body ?? {}) as {\n messages?: unknown[];\n options?: Record<string, unknown>;\n };\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n\n for (const msg of messages) {\n const err = validateMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n try {\n if (!aiService.streamChat) {\n return { status: 501, body: { error: 'Streaming is not supported by the configured AI service' } };\n }\n const events = aiService.streamChat(messages.map(m => normalizeMessage(m as Record<string, unknown>)), options as any);\n return { status: 200, stream: true, events };\n } catch (err) {\n logger.error('[AI Route] /chat/stream error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Complete ────────────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/complete',\n description: 'Text completion',\n auth: true,\n permissions: ['ai:complete'],\n handler: async (req) => {\n const { prompt, options } = (req.body ?? {}) as {\n prompt?: string;\n options?: Record<string, unknown>;\n };\n\n if (!prompt || typeof prompt !== 'string') {\n return { status: 400, body: { error: 'prompt string is required' } };\n }\n\n try {\n const result = await aiService.complete(prompt, options as any);\n return { status: 200, body: result };\n } catch (err) {\n logger.error('[AI Route] /complete error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Models ──────────────────────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/models',\n description: 'List available models',\n auth: true,\n permissions: ['ai:read'],\n handler: async () => {\n try {\n const models = aiService.listModels ? await aiService.listModels() : [];\n return { status: 200, body: { models } };\n } catch (err) {\n logger.error('[AI Route] /models error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Conversations ──────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/conversations',\n description: 'Create a conversation',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n try {\n // Ensure the request body is a non-null object before mutating it\n if (req.body !== undefined && req.body !== null && (typeof req.body !== 'object' || Array.isArray(req.body))) {\n return { status: 400, body: { error: 'Invalid request payload' } };\n }\n\n const options: Record<string, unknown> = { ...((req.body ?? {}) as Record<string, unknown>) };\n // Bind the conversation to the authenticated user\n if (req.user?.userId) {\n options.userId = req.user.userId;\n }\n const conversation = await conversationService.create(options as any);\n return { status: 201, body: conversation };\n } catch (err) {\n logger.error('[AI Route] POST /conversations error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n {\n method: 'GET',\n path: '/api/v1/ai/conversations',\n description: 'List conversations',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n try {\n const rawQuery = req.query ?? {};\n const options: Record<string, unknown> = { ...rawQuery };\n\n if (typeof rawQuery.limit === 'string') {\n const parsedLimit = Number(rawQuery.limit);\n if (!Number.isFinite(parsedLimit) || parsedLimit <= 0 || !Number.isInteger(parsedLimit)) {\n return { status: 400, body: { error: 'Invalid limit parameter' } };\n }\n options.limit = parsedLimit;\n }\n\n // Scope to the authenticated user's conversations\n if (req.user?.userId) {\n options.userId = req.user.userId;\n }\n\n const conversations = await conversationService.list(options as any);\n return { status: 200, body: { conversations } };\n } catch (err) {\n logger.error('[AI Route] GET /conversations error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n {\n method: 'POST',\n path: '/api/v1/ai/conversations/:id/messages',\n description: 'Add message to a conversation',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n const id = req.params?.id;\n if (!id) {\n return { status: 400, body: { error: 'conversation id is required' } };\n }\n\n const message = req.body;\n const validationError = validateMessage(message);\n if (validationError) {\n return { status: 400, body: { error: validationError } };\n }\n\n try {\n // Ownership check: verify the conversation belongs to the current user\n if (req.user?.userId) {\n const existing = await conversationService.get(id);\n if (!existing) {\n return { status: 404, body: { error: `Conversation \"${id}\" not found` } };\n }\n if (existing.userId && existing.userId !== req.user.userId) {\n return { status: 403, body: { error: 'You do not have access to this conversation' } };\n }\n }\n\n const conversation = await conversationService.addMessage(id, message as ModelMessage);\n return { status: 200, body: conversation };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found')) {\n return { status: 404, body: { error: msg } };\n }\n logger.error('[AI Route] POST /conversations/:id/messages error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n {\n method: 'DELETE',\n path: '/api/v1/ai/conversations/:id',\n description: 'Delete a conversation',\n auth: true,\n permissions: ['ai:conversations'],\n handler: async (req) => {\n const id = req.params?.id;\n if (!id) {\n return { status: 400, body: { error: 'conversation id is required' } };\n }\n\n try {\n // Ownership check: verify the conversation belongs to the current user\n if (req.user?.userId) {\n const existing = await conversationService.get(id);\n if (!existing) {\n return { status: 404, body: { error: `Conversation \"${id}\" not found` } };\n }\n if (existing.userId && existing.userId !== req.user.userId) {\n return { status: 403, body: { error: 'You do not have access to this conversation' } };\n }\n }\n\n await conversationService.delete(id);\n return { status: 204 };\n } catch (err) {\n logger.error('[AI Route] DELETE /conversations/:id error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n ];\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { ModelMessage } from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport type { AIService } from '../ai-service.js';\nimport type { AgentRuntime, AgentChatContext } from '../agent-runtime.js';\nimport type { RouteDefinition } from './ai-routes.js';\n\n/**\n * Allowed message roles for the agent chat endpoint.\n *\n * Only `user` and `assistant` are accepted from clients.\n * `system` messages are injected server-side from agent instructions,\n * and `tool` messages are produced by the tool-call loop — accepting\n * either from the client would allow callers to override agent\n * guardrails or inject fabricated tool results.\n */\nconst ALLOWED_AGENT_ROLES = new Set<string>(['user', 'assistant']);\n\nfunction validateAgentMessage(raw: unknown): string | null {\n if (typeof raw !== 'object' || raw === null) {\n return 'each message must be an object';\n }\n const msg = raw as Record<string, unknown>;\n if (typeof msg.role !== 'string' || !ALLOWED_AGENT_ROLES.has(msg.role)) {\n return `message.role must be one of ${[...ALLOWED_AGENT_ROLES].map(r => `\"${r}\"`).join(', ')} for agent chat`;\n }\n if (typeof msg.content !== 'string') {\n return 'message.content must be a string';\n }\n return null;\n}\n\n/**\n * Build agent-specific REST routes.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | GET | /api/v1/ai/agents | List all active agents |\n * | POST | /api/v1/ai/agents/:agentName/chat | Chat with a specific agent |\n */\nexport function buildAgentRoutes(\n aiService: AIService,\n agentRuntime: AgentRuntime,\n logger: Logger,\n): RouteDefinition[] {\n return [\n // ── List active agents ──────────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/agents',\n description: 'List all active AI agents',\n auth: true,\n permissions: ['ai:chat'],\n handler: async () => {\n try {\n const agents = await agentRuntime.listAgents();\n return { status: 200, body: { agents } };\n } catch (err) {\n logger.error(\n '[AI Route] /agents list error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Chat with a specific agent ──────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/agents/:agentName/chat',\n description: 'Chat with a specific AI agent',\n auth: true,\n permissions: ['ai:chat', 'ai:agents'],\n handler: async (req) => {\n const agentName = req.params?.agentName;\n if (!agentName) {\n return { status: 400, body: { error: 'agentName parameter is required' } };\n }\n\n // Parse request body\n const {\n messages: rawMessages,\n context: chatContext,\n options: extraOptions,\n } = (req.body ?? {}) as {\n messages?: unknown[];\n context?: AgentChatContext;\n options?: Record<string, unknown>;\n };\n\n if (!Array.isArray(rawMessages) || rawMessages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n\n for (const msg of rawMessages) {\n const err = validateAgentMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n // Load agent definition\n const agent = await agentRuntime.loadAgent(agentName);\n if (!agent) {\n return { status: 404, body: { error: `Agent \"${agentName}\" not found` } };\n }\n if (!agent.active) {\n return { status: 403, body: { error: `Agent \"${agentName}\" is not active` } };\n }\n\n try {\n // Build system messages from agent instructions + UI context\n const systemMessages = agentRuntime.buildSystemMessages(agent, chatContext);\n\n // Resolve agent model/tools → request options\n const agentOptions = agentRuntime.buildRequestOptions(\n agent,\n aiService.toolRegistry.getAll(),\n );\n\n // Whitelist only safe caller overrides — block tools/toolChoice/model\n // to prevent tool-definition injection or DoS via unregistered tools.\n const safeOverrides: Record<string, unknown> = {};\n if (extraOptions) {\n const ALLOWED_KEYS = new Set(['temperature', 'maxTokens', 'stop']);\n for (const key of Object.keys(extraOptions)) {\n if (ALLOWED_KEYS.has(key)) {\n safeOverrides[key] = extraOptions[key];\n }\n }\n }\n const mergedOptions = { ...agentOptions, ...safeOverrides };\n\n // Prepend system messages then user conversation\n const fullMessages: ModelMessage[] = [\n ...systemMessages,\n ...(rawMessages as ModelMessage[]),\n ];\n\n // Use chatWithTools for automatic tool resolution\n const result = await aiService.chatWithTools(fullMessages, {\n ...mergedOptions,\n maxIterations: agent.planning?.maxIterations,\n });\n\n return { status: 200, body: result };\n } catch (err) {\n logger.error(\n '[AI Route] /agents/:agentName/chat error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n ];\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n AIConversation,\n ModelMessage,\n ToolCallPart,\n ToolResultPart,\n IAIConversationService,\n IDataEngine,\n} from '@objectstack/spec/contracts';\n\n/** Object names used for persistence. */\nconst CONVERSATIONS_OBJECT = 'ai_conversations';\nconst MESSAGES_OBJECT = 'ai_messages';\n\n/** Database row shape for ai_conversations. */\ninterface DbConversationRow {\n id: string;\n title: string | null;\n agent_id: string | null;\n user_id: string | null;\n metadata: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/** Database row shape for ai_messages. */\ninterface DbMessageRow {\n id: string;\n conversation_id: string;\n role: 'system' | 'user' | 'assistant' | 'tool';\n content: string;\n tool_calls: string | null;\n tool_call_id: string | null;\n created_at: string;\n}\n\n/** Deterministic ordering for conversations (total order). */\nconst CONVERSATION_ORDER = [\n { field: 'created_at', order: 'asc' as const },\n { field: 'id', order: 'asc' as const },\n];\n\n/** Deterministic ordering for messages within a conversation. */\nconst MESSAGE_ORDER = [\n { field: 'created_at', order: 'asc' as const },\n { field: 'id', order: 'asc' as const },\n];\n\n/**\n * ObjectQLConversationService — Persistent implementation of IAIConversationService.\n *\n * Delegates all storage to an {@link IDataEngine} instance, using the\n * `ai_conversations` and `ai_messages` objects. This decouples the service\n * from any specific database driver (Turso, Postgres, SQLite, etc.).\n *\n * Production environments should use this implementation to ensure\n * conversation history survives service restarts.\n */\nexport class ObjectQLConversationService implements IAIConversationService {\n private readonly engine: IDataEngine;\n\n constructor(engine: IDataEngine) {\n this.engine = engine;\n }\n\n async create(options: {\n title?: string;\n agentId?: string;\n userId?: string;\n metadata?: Record<string, unknown>;\n } = {}): Promise<AIConversation> {\n const now = new Date().toISOString();\n const id = `conv_${randomUUID()}`;\n\n const record = {\n id,\n title: options.title ?? null,\n agent_id: options.agentId ?? null,\n user_id: options.userId ?? null,\n metadata: options.metadata ? JSON.stringify(options.metadata) : null,\n created_at: now,\n updated_at: now,\n };\n\n await this.engine.insert(CONVERSATIONS_OBJECT, record);\n\n return {\n id,\n title: options.title,\n agentId: options.agentId,\n userId: options.userId,\n messages: [],\n createdAt: now,\n updatedAt: now,\n metadata: options.metadata,\n };\n }\n\n async get(conversationId: string): Promise<AIConversation | null> {\n const row: DbConversationRow | null = await this.engine.findOne(CONVERSATIONS_OBJECT, {\n where: { id: conversationId },\n });\n\n if (!row) return null;\n\n const messages: DbMessageRow[] = await this.engine.find(MESSAGES_OBJECT, {\n where: { conversation_id: conversationId },\n orderBy: MESSAGE_ORDER,\n });\n\n return this.toConversation(row, messages);\n }\n\n async list(options: {\n userId?: string;\n agentId?: string;\n limit?: number;\n cursor?: string;\n } = {}): Promise<AIConversation[]> {\n const where: Record<string, unknown> = {};\n if (options.userId) where.user_id = options.userId;\n if (options.agentId) where.agent_id = options.agentId;\n\n // Stable cursor-based pagination using composite (created_at, id) order.\n // This avoids skips/duplicates when multiple conversations share a timestamp.\n if (options.cursor) {\n const cursorRow = await this.engine.findOne(CONVERSATIONS_OBJECT, {\n where: { id: options.cursor },\n fields: ['created_at', 'id'],\n });\n if (cursorRow) {\n where.$or = [\n { created_at: { $gt: cursorRow.created_at } },\n { created_at: cursorRow.created_at, id: { $gt: cursorRow.id } },\n ];\n }\n }\n\n const rows: DbConversationRow[] = await this.engine.find(CONVERSATIONS_OBJECT, {\n where: Object.keys(where).length > 0 ? where : undefined,\n orderBy: CONVERSATION_ORDER,\n limit: options.limit && options.limit > 0 ? options.limit : undefined,\n });\n\n // Load messages per conversation in parallel.\n // N+1 is bounded by the pagination limit; driver-agnostic $in is not guaranteed.\n const conversations: AIConversation[] = await Promise.all(\n rows.map(async (row) => {\n const messages: DbMessageRow[] = await this.engine.find(MESSAGES_OBJECT, {\n where: { conversation_id: row.id },\n orderBy: MESSAGE_ORDER,\n });\n return this.toConversation(row, messages);\n }),\n );\n\n return conversations;\n }\n\n async addMessage(conversationId: string, message: ModelMessage): Promise<AIConversation> {\n // Verify conversation exists\n const row: DbConversationRow | null = await this.engine.findOne(CONVERSATIONS_OBJECT, {\n where: { id: conversationId },\n });\n if (!row) {\n throw new Error(`Conversation \"${conversationId}\" not found`);\n }\n\n const now = new Date().toISOString();\n const msgId = `msg_${randomUUID()}`;\n\n // Extract flat fields from the discriminated union\n let contentStr: string;\n let toolCallsJson: string | null = null;\n let toolCallId: string | null = null;\n\n if (message.role === 'system' || message.role === 'user') {\n contentStr = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n } else if (message.role === 'assistant') {\n if (typeof message.content === 'string') {\n contentStr = message.content;\n } else {\n const parts = message.content;\n const textParts = parts.filter((p): p is { type: 'text'; text: string } => p.type === 'text').map(p => p.text);\n const toolCalls = parts.filter(p => p.type === 'tool-call');\n contentStr = textParts.join('');\n if (toolCalls.length > 0) toolCallsJson = JSON.stringify(toolCalls);\n }\n } else if (message.role === 'tool') {\n contentStr = JSON.stringify(message.content);\n const firstResult = Array.isArray(message.content) ? message.content[0] : undefined;\n if (firstResult && 'toolCallId' in firstResult) toolCallId = firstResult.toolCallId;\n } else {\n contentStr = '';\n }\n\n // Insert the message\n await this.engine.insert(MESSAGES_OBJECT, {\n id: msgId,\n conversation_id: conversationId,\n role: message.role,\n content: contentStr,\n tool_calls: toolCallsJson,\n tool_call_id: toolCallId,\n created_at: now,\n });\n\n // Update conversation timestamp\n await this.engine.update(CONVERSATIONS_OBJECT, { id: conversationId, updated_at: now }, {\n where: { id: conversationId },\n });\n\n // Return the full updated conversation\n return (await this.get(conversationId))!;\n }\n\n async delete(conversationId: string): Promise<void> {\n // Delete messages first (child records)\n await this.engine.delete(MESSAGES_OBJECT, {\n where: { conversation_id: conversationId },\n multi: true,\n });\n\n // Delete the conversation\n await this.engine.delete(CONVERSATIONS_OBJECT, {\n where: { id: conversationId },\n });\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n /**\n * Safely parse a JSON string, returning `undefined` on failure.\n */\n private safeParse<T>(value: string | null, fallback?: T): T | undefined {\n if (!value) return undefined;\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n }\n\n /**\n * Map a database row + message rows to an AIConversation.\n */\n private toConversation(row: DbConversationRow, messageRows: DbMessageRow[]): AIConversation {\n return {\n id: row.id,\n title: row.title ?? undefined,\n agentId: row.agent_id ?? undefined,\n userId: row.user_id ?? undefined,\n messages: messageRows.map(m => this.toMessage(m)),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n metadata: this.safeParse<Record<string, unknown>>(row.metadata),\n };\n }\n\n /**\n * Map a database row to a ModelMessage.\n */\n private toMessage(row: DbMessageRow): ModelMessage {\n switch (row.role) {\n case 'system':\n return { role: 'system', content: row.content };\n case 'user':\n return { role: 'user', content: row.content };\n case 'assistant': {\n const toolCalls = this.safeParse<ToolCallPart[]>(row.tool_calls);\n if (toolCalls && toolCalls.length > 0) {\n const content: Array<{ type: 'text'; text: string } | ToolCallPart> = [];\n if (row.content) content.push({ type: 'text', text: row.content });\n content.push(...toolCalls);\n return { role: 'assistant', content };\n }\n return { role: 'assistant', content: row.content };\n }\n case 'tool': {\n const toolResults = this.safeParse<ToolResultPart[]>(row.content);\n if (toolResults && toolResults.length > 0 && toolResults[0]?.type === 'tool-result') {\n return { role: 'tool', content: toolResults };\n }\n // Backward compat: old format was a plain string\n return {\n role: 'tool',\n content: [{\n type: 'tool-result' as const,\n toolCallId: row.tool_call_id ?? '',\n toolName: 'unknown',\n output: { type: 'text' as const, value: row.content },\n }],\n };\n }\n default:\n return { role: 'user', content: row.content };\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * ai_conversations — AI Conversation Object\n *\n * Stores conversation metadata for persistent AI conversation management.\n * Messages are stored separately in `ai_messages` to support efficient\n * querying and pagination.\n *\n * @namespace ai\n */\nexport const AiConversationObject = ObjectSchema.create({\n namespace: 'ai',\n name: 'conversations',\n label: 'AI Conversation',\n pluralLabel: 'AI Conversations',\n icon: 'message-square',\n isSystem: true,\n description: 'Persistent AI conversation metadata',\n\n fields: {\n id: Field.text({\n label: 'Conversation ID',\n required: true,\n readonly: true,\n }),\n\n title: Field.text({\n label: 'Title',\n required: false,\n maxLength: 500,\n description: 'Conversation title or summary',\n }),\n\n agent_id: Field.text({\n label: 'Agent ID',\n required: false,\n maxLength: 255,\n description: 'Associated AI agent identifier',\n }),\n\n user_id: Field.text({\n label: 'User ID',\n required: false,\n maxLength: 255,\n description: 'User who owns the conversation',\n }),\n\n metadata: Field.textarea({\n label: 'Metadata',\n required: false,\n description: 'JSON-serialized conversation metadata',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['user_id'] },\n { fields: ['agent_id'] },\n { fields: ['created_at'] },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * ai_messages — AI Message Object\n *\n * Stores individual messages within an AI conversation.\n * Each message belongs to a conversation via `conversation_id` foreign key.\n *\n * @namespace ai\n */\nexport const AiMessageObject = ObjectSchema.create({\n namespace: 'ai',\n name: 'messages',\n label: 'AI Message',\n pluralLabel: 'AI Messages',\n icon: 'message-circle',\n isSystem: true,\n description: 'Individual messages within AI conversations',\n\n fields: {\n id: Field.text({\n label: 'Message ID',\n required: true,\n readonly: true,\n }),\n\n conversation_id: Field.text({\n label: 'Conversation ID',\n required: true,\n description: 'Foreign key to ai_conversations',\n }),\n\n role: Field.select({\n label: 'Role',\n required: true,\n options: [\n { label: 'System', value: 'system' },\n { label: 'User', value: 'user' },\n { label: 'Assistant', value: 'assistant' },\n { label: 'Tool', value: 'tool' },\n ],\n }),\n\n content: Field.textarea({\n label: 'Content',\n required: true,\n description: 'Message content',\n }),\n\n tool_calls: Field.textarea({\n label: 'Tool Calls',\n required: false,\n description: 'JSON-serialized tool calls (when role=assistant)',\n }),\n\n tool_call_id: Field.text({\n label: 'Tool Call ID',\n required: false,\n maxLength: 255,\n description: 'ID of the tool call this message responds to (when role=tool)',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['conversation_id'] },\n { fields: ['conversation_id', 'created_at'] },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { AIToolDefinition, IDataEngine, IMetadataService } from '@objectstack/spec/contracts';\nimport type { ToolHandler } from './tool-registry.js';\nimport type { ToolRegistry } from './tool-registry.js';\n\n// ---------------------------------------------------------------------------\n// Internal type aliases for metadata payloads (returned as `unknown` from\n// IMetadataService — we cast to these lightweight shapes for field access).\n// ---------------------------------------------------------------------------\n\n/** Minimal shape of an object definition as returned by IMetadataService. */\ninterface ObjectDef {\n name: string;\n label?: string;\n fields?: Record<string, FieldDef>;\n}\n\n/** Minimal shape of a field definition inside an object. */\ninterface FieldDef {\n type?: string;\n label?: string;\n required?: boolean;\n reference?: string;\n options?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Data context — injected once at registration time\n// ---------------------------------------------------------------------------\n\n/**\n * Services required by the built-in data tools.\n *\n * These are provided by the kernel at `ai:ready` time and closed over\n * by the handler functions so they stay framework-agnostic.\n */\nexport interface DataToolContext {\n /** ObjectQL data engine for record-level operations. */\n dataEngine: IDataEngine;\n /** Metadata service for schema/object introspection. */\n metadataService: IMetadataService;\n}\n\n// ---------------------------------------------------------------------------\n// Tool Definitions\n// ---------------------------------------------------------------------------\n\n/** Maximum number of records a single query may return. */\nconst MAX_QUERY_LIMIT = 200;\n\n/** Default record limit when not specified. */\nconst DEFAULT_QUERY_LIMIT = 20;\n\nexport const LIST_OBJECTS_TOOL: AIToolDefinition = {\n name: 'list_objects',\n description: 'List all available data objects (tables) in the system. Returns object names and labels.',\n parameters: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n};\n\nexport const DESCRIBE_OBJECT_TOOL: AIToolDefinition = {\n name: 'describe_object',\n description:\n 'Get the schema (fields, types, labels) of a specific data object. ' +\n 'Use this to understand the structure of a table before querying it.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object to describe',\n },\n },\n required: ['objectName'],\n additionalProperties: false,\n },\n};\n\nexport const QUERY_RECORDS_TOOL: AIToolDefinition = {\n name: 'query_records',\n description:\n 'Query records from a data object with optional filters, field selection, ' +\n 'sorting, and pagination. Returns an array of matching records.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object to query',\n },\n where: {\n type: 'object',\n description:\n 'Filter conditions as key-value pairs (e.g. { \"status\": \"active\" }) ' +\n 'or MongoDB-style operators (e.g. { \"amount\": { \"$gt\": 100 } })',\n },\n fields: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of field names to return (omit for all fields)',\n },\n orderBy: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n field: { type: 'string' },\n order: { type: 'string', enum: ['asc', 'desc'] },\n },\n },\n description: 'Sort order (e.g. [{ \"field\": \"created_at\", \"order\": \"desc\" }])',\n },\n limit: {\n type: 'number',\n description: `Maximum number of records to return (default ${DEFAULT_QUERY_LIMIT}, max ${MAX_QUERY_LIMIT})`,\n },\n offset: {\n type: 'number',\n description: 'Number of records to skip for pagination',\n },\n },\n required: ['objectName'],\n additionalProperties: false,\n },\n};\n\nexport const GET_RECORD_TOOL: AIToolDefinition = {\n name: 'get_record',\n description: 'Get a single record by its ID from a data object.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object',\n },\n recordId: {\n type: 'string',\n description: 'The unique ID of the record',\n },\n fields: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of field names to return (omit for all fields)',\n },\n },\n required: ['objectName', 'recordId'],\n additionalProperties: false,\n },\n};\n\nexport const AGGREGATE_DATA_TOOL: AIToolDefinition = {\n name: 'aggregate_data',\n description:\n 'Perform aggregation/statistical operations on a data object. ' +\n 'Supports count, sum, avg, min, max with optional groupBy and where filters.',\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'The snake_case name of the object to aggregate',\n },\n aggregations: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n function: {\n type: 'string',\n enum: ['count', 'sum', 'avg', 'min', 'max', 'count_distinct'],\n description: 'Aggregation function',\n },\n field: {\n type: 'string',\n description: 'Field to aggregate (optional for count)',\n },\n alias: {\n type: 'string',\n description: 'Result column alias',\n },\n },\n required: ['function', 'alias'],\n },\n description: 'Aggregation definitions',\n },\n groupBy: {\n type: 'array',\n items: { type: 'string' },\n description: 'Fields to group by',\n },\n where: {\n type: 'object',\n description: 'Filter conditions applied before aggregation',\n },\n },\n required: ['objectName', 'aggregations'],\n additionalProperties: false,\n },\n};\n\n/** All built-in data tool definitions. */\nexport const DATA_TOOL_DEFINITIONS: AIToolDefinition[] = [\n LIST_OBJECTS_TOOL,\n DESCRIBE_OBJECT_TOOL,\n QUERY_RECORDS_TOOL,\n GET_RECORD_TOOL,\n AGGREGATE_DATA_TOOL,\n];\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createListObjectsHandler(ctx: DataToolContext): ToolHandler {\n return async () => {\n const objects = await ctx.metadataService.listObjects();\n const summary = (objects as ObjectDef[]).map(o => ({\n name: o.name,\n label: o.label ?? o.name,\n }));\n return JSON.stringify(summary);\n };\n}\n\nfunction createDescribeObjectHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const { objectName } = args as { objectName: string };\n const objectDef = await ctx.metadataService.getObject(objectName);\n if (!objectDef) {\n return JSON.stringify({ error: `Object \"${objectName}\" not found` });\n }\n\n const def = objectDef as ObjectDef;\n const fields = def.fields ?? {};\n const fieldSummary: Record<string, Record<string, unknown>> = {};\n for (const [key, f] of Object.entries(fields)) {\n fieldSummary[key] = {\n type: f.type,\n label: f.label ?? key,\n required: f.required ?? false,\n ...(f.reference ? { reference: f.reference } : {}),\n ...(f.options ? { options: f.options } : {}),\n };\n }\n\n return JSON.stringify({\n name: def.name,\n label: def.label ?? def.name,\n fields: fieldSummary,\n });\n };\n}\n\nfunction createQueryRecordsHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const {\n objectName,\n where,\n fields,\n orderBy,\n limit,\n offset,\n } = args as {\n objectName: string;\n where?: Record<string, unknown>;\n fields?: string[];\n orderBy?: Array<{ field: string; order: 'asc' | 'desc' }>;\n limit?: number;\n offset?: number;\n };\n\n // Validate and clamp limit to [1, MAX_QUERY_LIMIT]\n const rawLimit = limit ?? DEFAULT_QUERY_LIMIT;\n const safeLimit = Number.isFinite(rawLimit) && rawLimit > 0\n ? Math.min(Math.floor(rawLimit), MAX_QUERY_LIMIT)\n : DEFAULT_QUERY_LIMIT;\n\n // Validate offset: must be a non-negative finite integer\n const safeOffset = (Number.isFinite(offset) && (offset as number) >= 0)\n ? Math.floor(offset as number)\n : undefined;\n\n const records = await ctx.dataEngine.find(objectName, {\n where,\n fields,\n orderBy,\n limit: safeLimit,\n offset: safeOffset,\n });\n\n return JSON.stringify({ count: records.length, records });\n };\n}\n\nfunction createGetRecordHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, recordId, fields } = args as {\n objectName: string;\n recordId: string;\n fields?: string[];\n };\n\n const record = await ctx.dataEngine.findOne(objectName, {\n where: { id: recordId },\n fields,\n });\n\n if (!record) {\n return JSON.stringify({ error: `Record \"${recordId}\" not found in \"${objectName}\"` });\n }\n\n return JSON.stringify(record);\n };\n}\n\n/** Aggregation function names supported by the data engine. */\ntype AggFn = 'count' | 'sum' | 'avg' | 'min' | 'max' | 'count_distinct';\n\n/** Set of valid aggregation function names for runtime validation. */\nconst VALID_AGG_FUNCTIONS = new Set<string>([\n 'count', 'sum', 'avg', 'min', 'max', 'count_distinct',\n]);\n\nfunction createAggregateDataHandler(ctx: DataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, aggregations, groupBy, where } = args as {\n objectName: string;\n aggregations: Array<{ function: string; field?: string; alias: string }>;\n groupBy?: string[];\n where?: Record<string, unknown>;\n };\n\n // Validate aggregation functions at runtime\n for (const a of aggregations) {\n if (!VALID_AGG_FUNCTIONS.has(a.function)) {\n return JSON.stringify({\n error: `Invalid aggregation function \"${a.function}\". ` +\n `Allowed: ${[...VALID_AGG_FUNCTIONS].join(', ')}`,\n });\n }\n }\n\n const result = await ctx.dataEngine.aggregate(objectName, {\n where,\n groupBy,\n aggregations: aggregations.map(a => ({\n function: a.function as AggFn,\n field: a.field,\n alias: a.alias,\n })),\n });\n\n return JSON.stringify(result);\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public Registration Helper\n// ---------------------------------------------------------------------------\n\n/**\n * Register all built-in data tools on the given {@link ToolRegistry}.\n *\n * Typically called from the `ai:ready` hook after both the data engine\n * and metadata service are available.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const dataEngine = ctx.getService<IDataEngine>('data');\n * const metadataService = ctx.getService<IMetadataService>('metadata');\n * registerDataTools(aiService.toolRegistry, { dataEngine, metadataService });\n * });\n * ```\n */\nexport function registerDataTools(\n registry: ToolRegistry,\n context: DataToolContext,\n): void {\n registry.register(LIST_OBJECTS_TOOL, createListObjectsHandler(context));\n registry.register(DESCRIBE_OBJECT_TOOL, createDescribeObjectHandler(context));\n registry.register(QUERY_RECORDS_TOOL, createQueryRecordsHandler(context));\n registry.register(GET_RECORD_TOOL, createGetRecordHandler(context));\n registry.register(AGGREGATE_DATA_TOOL, createAggregateDataHandler(context));\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * create_object — AI Tool Metadata\n *\n * Creates a new data object (table) with schema validation.\n * Validates snake_case naming for object and initial fields,\n * checks for duplicates, and registers the object definition.\n */\nexport const createObjectTool = defineTool({\n name: 'create_object',\n label: 'Create Object',\n description:\n 'Creates a new data object (table) with the specified name, label, and optional field definitions. ' +\n 'Use this when the user wants to create a new entity, table, or data model.',\n category: 'data',\n builtIn: true,\n // NOTE: requiresConfirmation is intentionally false (default) because the\n // server-side tool-call loop in AIService.chatWithTools/streamChatWithTools\n // executes tool calls immediately without checking this flag. The flag\n // should only be set once server-side approval gating is implemented to\n // avoid giving users a false sense of safety.\n parameters: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n description: 'Machine name for the object (snake_case, e.g. project_task)',\n },\n label: {\n type: 'string',\n description: 'Human-readable display name (e.g. Project Task)',\n },\n fields: {\n type: 'array',\n description: 'Initial fields to create with the object',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Field machine name (snake_case)' },\n label: { type: 'string', description: 'Field display name' },\n type: {\n type: 'string',\n description: 'Field data type',\n enum: ['text', 'textarea', 'number', 'boolean', 'date', 'datetime', 'select', 'lookup', 'formula', 'autonumber'],\n },\n required: { type: 'boolean', description: 'Whether the field is required' },\n },\n required: ['name', 'type'],\n },\n },\n enableFeatures: {\n type: 'object',\n description: 'Object capability flags',\n properties: {\n trackHistory: { type: 'boolean' },\n apiEnabled: { type: 'boolean' },\n },\n },\n },\n required: ['name', 'label'],\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * add_field — AI Tool Metadata\n *\n * Adds a new field (column) to an existing data object.\n * Validates snake_case for objectName, field name, reference,\n * and select option values before merging into the definition.\n */\nexport const addFieldTool = defineTool({\n name: 'add_field',\n label: 'Add Field',\n description:\n 'Adds a new field (column) to an existing data object. ' +\n 'Use this when the user wants to add a property, column, or attribute to a table.',\n category: 'data',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'Target object machine name (snake_case)',\n },\n name: {\n type: 'string',\n description: 'Field machine name (snake_case, e.g. due_date)',\n },\n label: {\n type: 'string',\n description: 'Human-readable field label (e.g. Due Date)',\n },\n type: {\n type: 'string',\n description: 'Field data type',\n enum: ['text', 'textarea', 'number', 'boolean', 'date', 'datetime', 'select', 'lookup', 'formula', 'autonumber'],\n },\n required: {\n type: 'boolean',\n description: 'Whether the field is required',\n },\n defaultValue: {\n description: 'Default value for the field',\n },\n options: {\n type: 'array',\n description: 'Options for select/picklist fields',\n items: {\n type: 'object',\n properties: {\n label: { type: 'string' },\n value: {\n type: 'string',\n description: 'Option machine identifier (lowercase snake_case, e.g. high_priority)',\n pattern: '^[a-z_][a-z0-9_]*$',\n },\n },\n },\n },\n reference: {\n type: 'string',\n description: 'Referenced object name for lookup fields (snake_case, e.g. account)',\n },\n },\n required: ['objectName', 'name', 'type'],\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * modify_field — AI Tool Metadata\n *\n * Modifies an existing field definition (label, type, required, default value, etc.)\n * on a data object. Does not support renaming the field.\n */\nexport const modifyFieldTool = defineTool({\n name: 'modify_field',\n label: 'Modify Field',\n description:\n 'Modifies an existing field definition (label, type, required, default value, etc.) on a data object. ' +\n 'Use this when the user wants to change or reconfigure an existing column or attribute (not rename it).',\n category: 'data',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'Target object machine name (snake_case)',\n },\n fieldName: {\n type: 'string',\n description: 'Existing field machine name to modify (snake_case)',\n },\n changes: {\n type: 'object',\n description: 'Field properties to update (partial patch)',\n properties: {\n label: { type: 'string', description: 'New display label' },\n type: { type: 'string', description: 'New field type' },\n required: { type: 'boolean', description: 'Update required constraint' },\n defaultValue: { description: 'New default value' },\n },\n },\n },\n required: ['objectName', 'fieldName', 'changes'],\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * delete_field — AI Tool Metadata\n *\n * Removes a field (column) from an existing data object.\n * This is a destructive operation.\n */\nexport const deleteFieldTool = defineTool({\n name: 'delete_field',\n label: 'Delete Field',\n description:\n 'Removes a field (column) from an existing data object. This is a destructive operation. ' +\n 'Use this when the user explicitly wants to remove an attribute or column from a table.',\n category: 'data',\n builtIn: true,\n // NOTE: requiresConfirmation is intentionally false (default) because the\n // server-side tool-call loop in AIService.chatWithTools/streamChatWithTools\n // executes tool calls immediately without checking this flag. The flag\n // should only be set once server-side approval gating is implemented.\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'Target object machine name (snake_case)',\n },\n fieldName: {\n type: 'string',\n description: 'Field machine name to delete (snake_case)',\n },\n },\n required: ['objectName', 'fieldName'],\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * list_metadata_objects — AI Tool Metadata\n *\n * Lists all registered metadata objects (tables) with optional filtering.\n * Uses a unique name (`list_metadata_objects`) to avoid collision with\n * the data-tools `list_objects` tool.\n */\nexport const listMetadataObjectsTool = defineTool({\n name: 'list_metadata_objects',\n label: 'List Metadata Objects',\n description:\n 'Lists all registered metadata objects (tables) in the current environment. ' +\n 'Use this when the user wants to see what tables, entities, or data models are defined in metadata.',\n category: 'data',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n filter: {\n type: 'string',\n description: 'Optional name or label substring to filter objects',\n },\n includeFields: {\n type: 'boolean',\n description: 'Whether to include field summaries for each object (default: false)',\n },\n },\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * describe_metadata_object — AI Tool Metadata\n *\n * Returns the full metadata schema of a data object including all\n * fields, types, relationships, and configuration. Uses a unique name\n * (`describe_metadata_object`) to avoid collision with the data-tools\n * `describe_object` tool.\n */\nexport const describeMetadataObjectTool = defineTool({\n name: 'describe_metadata_object',\n label: 'Describe Metadata Object',\n description:\n 'Returns the full metadata schema details of a data object, including all fields, types, relationships, and configuration. ' +\n 'Use this when the user wants to inspect or understand the metadata structure of a specific table or entity.',\n category: 'data',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n objectName: {\n type: 'string',\n description: 'Object machine name to describe (snake_case)',\n },\n },\n required: ['objectName'],\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IMetadataService } from '@objectstack/spec/contracts';\nimport type { Tool } from '@objectstack/spec/ai';\nimport type { ToolHandler } from './tool-registry.js';\nimport type { ToolRegistry } from './tool-registry.js';\n\n// ---------------------------------------------------------------------------\n// Tool Metadata — individual .tool.ts files (single source of truth)\n// ---------------------------------------------------------------------------\n\nexport { createObjectTool } from './create-object.tool.js';\nexport { addFieldTool } from './add-field.tool.js';\nexport { modifyFieldTool } from './modify-field.tool.js';\nexport { deleteFieldTool } from './delete-field.tool.js';\nexport { listMetadataObjectsTool } from './list-metadata-objects.tool.js';\nexport { describeMetadataObjectTool } from './describe-metadata-object.tool.js';\n\nimport { createObjectTool } from './create-object.tool.js';\nimport { addFieldTool } from './add-field.tool.js';\nimport { modifyFieldTool } from './modify-field.tool.js';\nimport { deleteFieldTool } from './delete-field.tool.js';\nimport { listMetadataObjectsTool } from './list-metadata-objects.tool.js';\nimport { describeMetadataObjectTool } from './describe-metadata-object.tool.js';\n\n/** All built-in metadata management tool definitions (Tool metadata). */\nexport const METADATA_TOOL_DEFINITIONS: Tool[] = [\n createObjectTool,\n addFieldTool,\n modifyFieldTool,\n deleteFieldTool,\n listMetadataObjectsTool,\n describeMetadataObjectTool,\n];\n\n// ---------------------------------------------------------------------------\n// Internal type aliases for metadata payloads (returned as `unknown` from\n// IMetadataService — we cast to these lightweight shapes for field access).\n// ---------------------------------------------------------------------------\n\n/** Minimal shape of an object definition as returned by IMetadataService. */\ninterface ObjectDef {\n name: string;\n label?: string;\n fields?: Record<string, FieldDef>;\n enable?: Record<string, boolean>;\n}\n\n/** Minimal shape of a field definition inside an object. */\ninterface FieldDef {\n name?: string;\n type?: string;\n label?: string;\n required?: boolean;\n reference?: string;\n options?: unknown;\n defaultValue?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Shared validation helpers\n// ---------------------------------------------------------------------------\n\n/** snake_case identifier pattern (e.g. `project_task`, `due_date`). */\nconst SNAKE_CASE_RE = /^[a-z_][a-z0-9_]*$/;\n\n/** Validate that a value matches snake_case. */\nfunction isSnakeCase(value: string): boolean {\n return SNAKE_CASE_RE.test(value);\n}\n\n// ---------------------------------------------------------------------------\n// Context — injected once at registration time\n// ---------------------------------------------------------------------------\n\n/**\n * Services required by the metadata management tools.\n *\n * Provided by the kernel at `ai:ready` time and closed over\n * by the handler functions so they stay framework-agnostic.\n */\nexport interface MetadataToolContext {\n /** Metadata service for schema CRUD operations. */\n metadataService: IMetadataService;\n}\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createCreateObjectHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { name, label, fields, enableFeatures } = args as {\n name: string;\n label: string;\n fields?: Array<{ name: string; label?: string; type: string; required?: boolean }>;\n enableFeatures?: Record<string, boolean>;\n };\n\n if (!name || !label) {\n return JSON.stringify({ error: 'Both \"name\" and \"label\" are required' });\n }\n\n // Validate snake_case name\n if (!isSnakeCase(name)) {\n return JSON.stringify({ error: `Invalid object name \"${name}\". Must be snake_case.` });\n }\n\n // Check if the object already exists\n const existing = await ctx.metadataService.getObject(name);\n if (existing) {\n return JSON.stringify({ error: `Object \"${name}\" already exists` });\n }\n\n // Build field map from array input with per-field validation\n const fieldMap: Record<string, Record<string, unknown>> = {};\n if (fields && Array.isArray(fields)) {\n const seenNames = new Set<string>();\n for (const f of fields) {\n if (!f.name) {\n return JSON.stringify({ error: 'Each field must have a \"name\" property' });\n }\n if (!isSnakeCase(f.name)) {\n return JSON.stringify({ error: `Invalid field name \"${f.name}\". Must be snake_case.` });\n }\n if (seenNames.has(f.name)) {\n return JSON.stringify({ error: `Duplicate field name \"${f.name}\" in initial fields` });\n }\n seenNames.add(f.name);\n fieldMap[f.name] = {\n type: f.type,\n ...(f.label ? { label: f.label } : {}),\n ...(f.required !== undefined ? { required: f.required } : {}),\n };\n }\n }\n\n const objectDef: Record<string, unknown> = {\n name,\n label,\n ...(Object.keys(fieldMap).length > 0 ? { fields: fieldMap } : {}),\n ...(enableFeatures ? { enable: enableFeatures } : {}),\n };\n\n await ctx.metadataService.register('object', name, objectDef);\n\n return JSON.stringify({\n name,\n label,\n fieldCount: Object.keys(fieldMap).length,\n });\n };\n}\n\nfunction createAddFieldHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, name, label, type, required, defaultValue, options, reference } = args as {\n objectName: string;\n name: string;\n label?: string;\n type: string;\n required?: boolean;\n defaultValue?: unknown;\n options?: Array<{ label: string; value: string }>;\n reference?: string;\n };\n\n if (!objectName || !name || !type) {\n return JSON.stringify({ error: '\"objectName\", \"name\", and \"type\" are required' });\n }\n\n // Validate snake_case names\n if (!isSnakeCase(objectName)) {\n return JSON.stringify({ error: `Invalid object name \"${objectName}\". Must be snake_case.` });\n }\n if (!isSnakeCase(name)) {\n return JSON.stringify({ error: `Invalid field name \"${name}\". Must be snake_case.` });\n }\n\n // Validate reference as snake_case if provided\n if (reference && !isSnakeCase(reference)) {\n return JSON.stringify({ error: `Invalid reference \"${reference}\". Must be a snake_case object name.` });\n }\n\n // Validate select option values as snake_case if provided\n if (options && Array.isArray(options)) {\n for (const opt of options) {\n if (opt.value && !isSnakeCase(opt.value)) {\n return JSON.stringify({ error: `Invalid option value \"${opt.value}\". Must be lowercase snake_case.` });\n }\n }\n }\n\n // Verify the target object exists\n const objectDef = await ctx.metadataService.getObject(objectName);\n if (!objectDef) {\n return JSON.stringify({ error: `Object \"${objectName}\" not found` });\n }\n\n // Check if field already exists\n const def = objectDef as ObjectDef;\n if (def.fields && def.fields[name]) {\n return JSON.stringify({ error: `Field \"${name}\" already exists on object \"${objectName}\"` });\n }\n\n // Build new field definition\n const fieldDef: Record<string, unknown> = {\n type,\n ...(label ? { label } : {}),\n ...(required !== undefined ? { required } : {}),\n ...(defaultValue !== undefined ? { defaultValue } : {}),\n ...(options ? { options } : {}),\n ...(reference ? { reference } : {}),\n };\n\n // Merge the new field into the existing object definition and re-register\n const updatedFields = { ...(def.fields ?? {}), [name]: fieldDef };\n await ctx.metadataService.register('object', objectName, {\n ...def,\n fields: updatedFields,\n });\n\n return JSON.stringify({\n objectName,\n fieldName: name,\n fieldType: type,\n });\n };\n}\n\nfunction createModifyFieldHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, fieldName, changes } = args as {\n objectName: string;\n fieldName: string;\n changes: Record<string, unknown>;\n };\n\n if (!objectName || !fieldName || !changes) {\n return JSON.stringify({ error: '\"objectName\", \"fieldName\", and \"changes\" are required' });\n }\n\n // Validate snake_case names\n if (!isSnakeCase(objectName)) {\n return JSON.stringify({ error: `Invalid object name \"${objectName}\". Must be snake_case.` });\n }\n if (!isSnakeCase(fieldName)) {\n return JSON.stringify({ error: `Invalid field name \"${fieldName}\". Must be snake_case.` });\n }\n\n // Verify the target object exists\n const objectDef = await ctx.metadataService.getObject(objectName);\n if (!objectDef) {\n return JSON.stringify({ error: `Object \"${objectName}\" not found` });\n }\n\n const def = objectDef as ObjectDef;\n if (!def.fields || !def.fields[fieldName]) {\n return JSON.stringify({ error: `Field \"${fieldName}\" not found on object \"${objectName}\"` });\n }\n\n // Apply changes to the field definition\n const existingField = def.fields[fieldName];\n const updatedField = { ...existingField, ...changes };\n const updatedFields = { ...def.fields, [fieldName]: updatedField };\n\n await ctx.metadataService.register('object', objectName, {\n ...def,\n fields: updatedFields,\n });\n\n return JSON.stringify({\n objectName,\n fieldName,\n updatedProperties: Object.keys(changes),\n });\n };\n}\n\nfunction createDeleteFieldHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, fieldName } = args as {\n objectName: string;\n fieldName: string;\n };\n\n if (!objectName || !fieldName) {\n return JSON.stringify({ error: '\"objectName\" and \"fieldName\" are required' });\n }\n\n // Validate snake_case names\n if (!isSnakeCase(objectName)) {\n return JSON.stringify({ error: `Invalid object name \"${objectName}\". Must be snake_case.` });\n }\n if (!isSnakeCase(fieldName)) {\n return JSON.stringify({ error: `Invalid field name \"${fieldName}\". Must be snake_case.` });\n }\n\n // Verify the target object exists\n const objectDef = await ctx.metadataService.getObject(objectName);\n if (!objectDef) {\n return JSON.stringify({ error: `Object \"${objectName}\" not found` });\n }\n\n const def = objectDef as ObjectDef;\n if (!def.fields || !def.fields[fieldName]) {\n return JSON.stringify({ error: `Field \"${fieldName}\" not found on object \"${objectName}\"` });\n }\n\n // Remove the field and re-register\n const { [fieldName]: _removed, ...remainingFields } = def.fields;\n await ctx.metadataService.register('object', objectName, {\n ...def,\n fields: remainingFields,\n });\n\n return JSON.stringify({\n objectName,\n fieldName,\n success: true,\n });\n };\n}\n\nfunction createListObjectsHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { filter, includeFields } = (args ?? {}) as {\n filter?: string;\n includeFields?: boolean;\n };\n\n const objects = await ctx.metadataService.listObjects();\n let result = (objects as ObjectDef[]).map(o => {\n const base: Record<string, unknown> = {\n name: o.name,\n label: o.label ?? o.name,\n fieldCount: o.fields ? Object.keys(o.fields).length : 0,\n };\n if (includeFields && o.fields) {\n base.fields = Object.entries(o.fields).map(([key, f]) => ({\n name: key,\n type: f.type,\n label: f.label ?? key,\n }));\n }\n return base;\n });\n\n // Apply optional name/label substring filter\n if (filter) {\n const lower = filter.toLowerCase();\n result = result.filter(o =>\n (o.name as string).toLowerCase().includes(lower) ||\n (o.label as string).toLowerCase().includes(lower),\n );\n }\n\n return JSON.stringify({\n objects: result,\n totalCount: result.length,\n });\n };\n}\n\nfunction createDescribeObjectHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName } = args as { objectName: string };\n\n if (!objectName) {\n return JSON.stringify({ error: '\"objectName\" is required' });\n }\n\n // Validate snake_case name\n if (!isSnakeCase(objectName)) {\n return JSON.stringify({ error: `Invalid object name \"${objectName}\". Must be snake_case.` });\n }\n\n const objectDef = await ctx.metadataService.getObject(objectName);\n if (!objectDef) {\n return JSON.stringify({ error: `Object \"${objectName}\" not found` });\n }\n\n const def = objectDef as ObjectDef;\n const fields = def.fields ?? {};\n const fieldSummary = Object.entries(fields).map(([key, f]) => ({\n name: key,\n type: f.type,\n label: f.label ?? key,\n required: f.required ?? false,\n ...(f.reference ? { reference: f.reference } : {}),\n ...(f.options ? { options: f.options } : {}),\n }));\n\n return JSON.stringify({\n name: def.name,\n label: def.label ?? def.name,\n fields: fieldSummary,\n enableFeatures: def.enable ?? {},\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public Registration Helper\n// ---------------------------------------------------------------------------\n\n/**\n * Register all built-in metadata management tools on the given {@link ToolRegistry}.\n *\n * Typically called from the `ai:ready` hook after the metadata service is available.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const metadataService = ctx.getService<IMetadataService>('metadata');\n * registerMetadataTools(aiService.toolRegistry, { metadataService });\n * });\n * ```\n */\nexport function registerMetadataTools(\n registry: ToolRegistry,\n context: MetadataToolContext,\n): void {\n registry.register(createObjectTool, createCreateObjectHandler(context));\n registry.register(addFieldTool, createAddFieldHandler(context));\n registry.register(modifyFieldTool, createModifyFieldHandler(context));\n registry.register(deleteFieldTool, createDeleteFieldHandler(context));\n registry.register(listMetadataObjectsTool, createListObjectsHandler(context));\n registry.register(describeMetadataObjectTool, createDescribeObjectHandler(context));\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ModelMessage,\n AIRequestOptions,\n AIToolDefinition,\n IMetadataService,\n} from '@objectstack/spec/contracts';\nimport type { Agent } from '@objectstack/spec';\nimport { AgentSchema } from '@objectstack/spec/ai';\n\n/**\n * Context passed alongside a user message when chatting with an agent.\n *\n * UI clients set these fields to tell the agent which object, record,\n * or view the user is currently looking at so it can provide contextual\n * answers without additional tool calls.\n */\nexport interface AgentChatContext {\n /** Current object the user is viewing (e.g. \"account\") */\n objectName?: string;\n /** Currently selected record ID */\n recordId?: string;\n /** Current view name */\n viewName?: string;\n}\n\n/**\n * AgentRuntime — Resolves an agent definition into runnable chat parameters.\n *\n * Responsibilities:\n * 1. Load & validate agent metadata from the metadata service.\n * 2. Build the system prompt from agent `instructions` + UI context.\n * 3. Derive {@link AIRequestOptions} from agent `model` and `tools`.\n * 4. Map agent tool references to concrete {@link AIToolDefinition}s\n * registered in the {@link ToolRegistry}.\n */\nexport class AgentRuntime {\n constructor(private readonly metadataService: IMetadataService) {}\n\n // ── Public API ────────────────────────────────────────────────\n\n /**\n * List all active agents registered in the metadata service.\n *\n * Returns a summary for each agent (name, label, role) suitable\n * for populating an agent selector dropdown in the UI.\n */\n async listAgents(): Promise<Array<{ name: string; label: string; role: string }>> {\n const rawItems = await this.metadataService.list('agent');\n const agents: Array<{ name: string; label: string; role: string }> = [];\n\n for (const raw of rawItems) {\n const result = AgentSchema.safeParse(raw);\n if (result.success && result.data.active) {\n agents.push({\n name: result.data.name,\n label: result.data.label,\n role: result.data.role,\n });\n }\n }\n\n return agents;\n }\n\n /**\n * Load and validate an agent definition by name.\n *\n * The raw metadata is validated through {@link AgentSchema} to ensure\n * required fields (`instructions`, `name`, `role`, etc.) are present\n * and well-typed. Returns `undefined` when the agent does not exist\n * or validation fails.\n */\n async loadAgent(agentName: string): Promise<Agent | undefined> {\n const raw = await this.metadataService.get('agent', agentName);\n if (!raw) return undefined;\n\n const result = AgentSchema.safeParse(raw);\n if (!result.success) {\n return undefined;\n }\n return result.data;\n }\n\n /**\n * Build the system message(s) that should be prepended to the\n * conversation when chatting with the given agent.\n */\n buildSystemMessages(agent: Agent, context?: AgentChatContext): ModelMessage[] {\n const parts: string[] = [];\n\n // Base instructions\n parts.push(agent.instructions);\n\n // Contextual hints from the user's current UI state\n if (context) {\n const ctx: string[] = [];\n if (context.objectName) ctx.push(`Current object: ${context.objectName}`);\n if (context.recordId) ctx.push(`Selected record ID: ${context.recordId}`);\n if (context.viewName) ctx.push(`Current view: ${context.viewName}`);\n if (ctx.length > 0) {\n parts.push('\\n--- Current Context ---\\n' + ctx.join('\\n'));\n }\n }\n\n return [{ role: 'system' as const, content: parts.join('\\n') }];\n }\n\n /**\n * Derive {@link AIRequestOptions} from an agent definition.\n *\n * Tool references declared in `agent.tools` are resolved by name against\n * `availableTools` (i.e. the full set of ToolRegistry definitions).\n * Any unresolved references (tools the agent declares but that are not\n * registered) are silently skipped — this is intentional so that agents\n * can be defined before all tools are available.\n *\n * @param agent - The agent definition to derive options from\n * @param availableTools - All tool definitions currently registered in the ToolRegistry\n * @returns Request options with model config and resolved tool definitions\n */\n buildRequestOptions(\n agent: Agent,\n availableTools: AIToolDefinition[],\n ): AIRequestOptions {\n const options: AIRequestOptions = {};\n\n // Model config\n if (agent.model) {\n options.model = agent.model.model;\n options.temperature = agent.model.temperature;\n options.maxTokens = agent.model.maxTokens;\n }\n\n // Resolve agent tool references → concrete tool definitions\n if (agent.tools && agent.tools.length > 0) {\n const toolMap = new Map(availableTools.map(t => [t.name, t]));\n const resolved: AIToolDefinition[] = [];\n for (const ref of agent.tools) {\n const def = toolMap.get(ref.name);\n if (def) {\n resolved.push(def);\n }\n }\n if (resolved.length > 0) {\n options.tools = resolved;\n options.toolChoice = 'auto';\n }\n }\n\n return options;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Agent } from '@objectstack/spec';\n\n/**\n * Built-in `data_chat` agent definition.\n *\n * This agent powers the Airtable-style data conversation Chatbot.\n * It is registered automatically by the AI service plugin when a\n * data engine is available.\n *\n * @example\n * ```\n * POST /api/v1/ai/agents/data_chat/chat\n * {\n * \"messages\": [{ \"role\": \"user\", \"content\": \"Show me all active accounts\" }],\n * \"context\": { \"objectName\": \"account\" }\n * }\n * ```\n */\nexport const DATA_CHAT_AGENT: Agent = {\n name: 'data_chat',\n label: 'Data Assistant',\n role: 'Business Data Analyst',\n instructions: `You are a helpful data assistant that helps users explore and understand their business data through natural language.\n\nCapabilities:\n- List available data objects (tables) and their schemas\n- Query records with filters, sorting, and pagination\n- Look up individual records by ID\n- Perform aggregations and statistical analysis (count, sum, avg, min, max)\n\nGuidelines:\n1. Always use the describe_object tool first to understand a table's structure before querying it.\n2. Respect the user's current context — if they are viewing a specific object or record, use that as the default scope.\n3. When presenting data, format it in a clear and readable way using markdown tables or bullet lists.\n4. For large result sets, summarize the data and mention the total count.\n5. When performing aggregations, explain the results in plain language.\n6. If a query returns no results, suggest possible reasons and alternative queries.\n7. Never expose internal IDs unless the user explicitly asks for them.\n8. Always answer in the same language the user is using.`,\n\n model: {\n provider: 'openai',\n model: 'gpt-4',\n temperature: 0.3,\n maxTokens: 4096,\n },\n\n tools: [\n { type: 'query', name: 'list_objects', description: 'List all available data objects' },\n { type: 'query', name: 'describe_object', description: 'Get schema/fields of a data object' },\n { type: 'query', name: 'query_records', description: 'Query records with filters and pagination' },\n { type: 'query', name: 'get_record', description: 'Get a single record by ID' },\n { type: 'query', name: 'aggregate_data', description: 'Aggregate/statistics on data' },\n ],\n\n active: true,\n visibility: 'global',\n\n guardrails: {\n maxTokensPerInvocation: 8192,\n maxExecutionTimeSec: 30,\n blockedTopics: ['delete_records', 'drop_table', 'alter_schema'],\n },\n\n planning: {\n strategy: 'react',\n maxIterations: 5,\n allowReplan: false,\n },\n\n memory: {\n shortTerm: {\n maxMessages: 20,\n maxTokens: 4096,\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Agent } from '@objectstack/spec';\n\n/**\n * Built-in `metadata_assistant` agent definition.\n *\n * This agent powers AI-driven metadata management — users can create objects,\n * add/modify/delete fields, and inspect schema definitions through natural\n * language conversation.\n *\n * It is registered automatically by the AI service plugin alongside the\n * `data_chat` agent when the metadata service is available.\n *\n * @example\n * ```\n * POST /api/v1/ai/agents/metadata_assistant/chat\n * {\n * \"messages\": [{ \"role\": \"user\", \"content\": \"Create a contracts table with name, value, and status fields\" }],\n * \"context\": {}\n * }\n * ```\n */\nexport const METADATA_ASSISTANT_AGENT: Agent = {\n name: 'metadata_assistant',\n label: 'Metadata Assistant',\n role: 'Schema Architect',\n instructions: `You are an expert metadata architect that helps users design and manage their data models through natural language.\n\nCapabilities:\n- Create new data objects (tables) with fields\n- Add fields (columns) to existing objects\n- Modify field properties (label, type, required, default value)\n- Delete fields from objects\n- List all registered metadata objects and their schemas\n- Describe the full schema of a specific object\n\nGuidelines:\n1. Before creating a new object, use list_metadata_objects to check if a similar one already exists.\n2. Before modifying or deleting fields, use describe_metadata_object to understand the current schema.\n3. Always use snake_case for object names and field names (e.g. project_task, due_date).\n4. Suggest meaningful field types based on the user's description (e.g. \"deadline\" → date, \"active\" → boolean).\n5. When creating objects, propose a reasonable set of initial fields based on the entity type.\n6. Explain what changes you are about to make before executing them.\n7. After making changes, confirm the result by describing the updated schema.\n8. For destructive operations (deleting fields), always warn the user about potential data loss.\n9. Always answer in the same language the user is using.\n10. If the user's request is ambiguous, ask clarifying questions before proceeding.`,\n\n model: {\n provider: 'openai',\n model: 'gpt-4',\n temperature: 0.2,\n maxTokens: 4096,\n },\n\n tools: [\n { type: 'action', name: 'create_object', description: 'Create a new data object (table)' },\n { type: 'action', name: 'add_field', description: 'Add a field to an existing object' },\n { type: 'action', name: 'modify_field', description: 'Modify an existing field definition' },\n { type: 'action', name: 'delete_field', description: 'Delete a field from an object' },\n { type: 'query', name: 'list_metadata_objects', description: 'List all metadata objects' },\n { type: 'query', name: 'describe_metadata_object', description: 'Describe an object schema' },\n ],\n\n active: true,\n visibility: 'global',\n\n guardrails: {\n maxTokensPerInvocation: 8192,\n maxExecutionTimeSec: 60,\n blockedTopics: ['drop_database', 'raw_sql', 'system_tables'],\n },\n\n planning: {\n strategy: 'react',\n maxIterations: 10,\n allowReplan: true,\n },\n\n memory: {\n shortTerm: {\n maxMessages: 30,\n maxTokens: 8192,\n },\n },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n ModelMessage,\n AIRequestOptions,\n AIResult,\n TextStreamPart,\n ToolSet,\n} from '@objectstack/spec/contracts';\nimport type { LLMAdapter } from '@objectstack/spec/contracts';\nimport type { AIToolDefinition } from '@objectstack/spec/contracts';\nimport type { LanguageModelV2 } from '@ai-sdk/provider';\nimport { generateText, streamText, tool as vercelTool, jsonSchema } from 'ai';\n\n/**\n * Convert ObjectStack `AIRequestOptions` into the subset of Vercel AI SDK\n * options supported by `generateText` / `streamText`.\n *\n * Forwards: temperature, maxTokens, stop (→ stopSequences), tools, toolChoice.\n */\nfunction buildVercelOptions(options?: AIRequestOptions): Record<string, unknown> {\n if (!options) return {};\n\n const opts: Record<string, unknown> = {};\n\n if (options.temperature != null) opts.temperature = options.temperature;\n if (options.maxTokens != null) opts.maxTokens = options.maxTokens;\n if (options.stop?.length) opts.stopSequences = options.stop;\n\n if (options.tools?.length) {\n const tools: Record<string, unknown> = {};\n for (const t of options.tools as AIToolDefinition[]) {\n tools[t.name] = vercelTool({\n description: t.description,\n inputSchema: jsonSchema(t.parameters as any),\n });\n }\n opts.tools = tools;\n }\n\n if (options.toolChoice != null) {\n opts.toolChoice = options.toolChoice;\n }\n\n return opts;\n}\n\n/**\n * VercelLLMAdapter — Production LLM adapter powered by the Vercel AI SDK.\n *\n * Wraps `generateText` / `streamText` from the `ai` package, delegating to\n * any Vercel AI SDK–compatible model provider (OpenAI, Anthropic, Google,\n * Ollama, etc.).\n *\n * @example\n * ```typescript\n * import { openai } from '@ai-sdk/openai';\n * import { VercelLLMAdapter } from '@objectstack/service-ai';\n *\n * const adapter = new VercelLLMAdapter({ model: openai('gpt-4o') });\n * ```\n */\nexport class VercelLLMAdapter implements LLMAdapter {\n readonly name = 'vercel';\n\n private readonly model: LanguageModelV2;\n\n constructor(config: VercelLLMAdapterConfig) {\n this.model = config.model;\n }\n\n async chat(messages: ModelMessage[], options?: AIRequestOptions): Promise<AIResult> {\n const result = await generateText({\n model: this.model,\n messages,\n ...buildVercelOptions(options),\n });\n\n return {\n content: result.text,\n model: result.response?.modelId,\n toolCalls: result.toolCalls?.length ? result.toolCalls : undefined,\n usage: result.usage ? {\n promptTokens: result.usage.inputTokens ?? 0,\n completionTokens: result.usage.outputTokens ?? 0,\n totalTokens: result.usage.totalTokens ?? 0,\n } : undefined,\n };\n }\n\n async complete(prompt: string, options?: AIRequestOptions): Promise<AIResult> {\n const result = await generateText({\n model: this.model,\n prompt,\n ...buildVercelOptions(options),\n });\n\n return {\n content: result.text,\n model: result.response?.modelId,\n usage: result.usage ? {\n promptTokens: result.usage.inputTokens ?? 0,\n completionTokens: result.usage.outputTokens ?? 0,\n totalTokens: result.usage.totalTokens ?? 0,\n } : undefined,\n };\n }\n\n async *streamChat(\n messages: ModelMessage[],\n options?: AIRequestOptions,\n ): AsyncIterable<TextStreamPart<ToolSet>> {\n const result = streamText({\n model: this.model,\n messages,\n ...buildVercelOptions(options),\n });\n\n for await (const part of result.fullStream) {\n yield part as TextStreamPart<ToolSet>;\n }\n }\n\n async embed(_input: string | string[]): Promise<number[][]> {\n // Vercel AI SDK uses a separate EmbeddingModel — not supported via this adapter.\n throw new Error(\n '[VercelLLMAdapter] Embeddings require a dedicated EmbeddingModel. ' +\n 'Configure an embedding adapter instead.',\n );\n }\n\n async listModels(): Promise<string[]> {\n // Model listing is provider-specific and not available through the base SDK.\n return [];\n }\n}\n\n/**\n * Configuration for the Vercel LLM adapter.\n */\nexport interface VercelLLMAdapterConfig {\n /**\n * A Vercel AI SDK–compatible language model instance.\n *\n * @example `openai('gpt-4o')` or `anthropic('claude-sonnet-4-20250514')`\n */\n model: LanguageModelV2;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { IAIService, IAIConversationService, IDataEngine, IMetadataService, LLMAdapter } from '@objectstack/spec/contracts';\nimport { AIService } from './ai-service.js';\nimport type { AIServiceConfig } from './ai-service.js';\nimport { buildAIRoutes } from './routes/ai-routes.js';\nimport { buildAgentRoutes } from './routes/agent-routes.js';\nimport { ObjectQLConversationService } from './conversation/objectql-conversation-service.js';\nimport { AiConversationObject, AiMessageObject } from './objects/index.js';\nimport { registerDataTools } from './tools/data-tools.js';\nimport { registerMetadataTools } from './tools/metadata-tools.js';\nimport { AgentRuntime } from './agent-runtime.js';\nimport { DATA_CHAT_AGENT, METADATA_ASSISTANT_AGENT } from './agents/index.js';\nimport { VercelLLMAdapter } from './adapters/vercel-adapter.js';\nimport { MemoryLLMAdapter } from './adapters/memory-adapter.js';\n\n/**\n * Configuration options for the AIServicePlugin.\n */\nexport interface AIServicePluginOptions {\n /** LLM adapter to use (defaults to MemoryLLMAdapter). */\n adapter?: LLMAdapter;\n /** Enable debug logging. */\n debug?: boolean;\n /** Explicit conversation service override. When set, auto-detection is skipped. */\n conversationService?: IAIConversationService;\n}\n\n/**\n * AIServicePlugin — Kernel plugin for the unified AI capability service.\n *\n * Lifecycle:\n * 1. **init** — Creates {@link AIService}, registers as `'ai'` service.\n * If an existing AI service is already registered, it is replaced.\n * 2. **start** — Triggers `'ai:ready'` hook so other plugins can register\n * tools or extend the service. Registers REST/SSE routes.\n * 3. **destroy** — Cleans up references.\n *\n * @example\n * ```ts\n * import { LiteKernel } from '@objectstack/core';\n * import { AIServicePlugin } from '@objectstack/service-ai';\n *\n * const kernel = new LiteKernel();\n * kernel.use(new AIServicePlugin());\n * await kernel.bootstrap();\n *\n * const ai = kernel.getService<IAIService>('ai');\n * const result = await ai.chat([{ role: 'user', content: 'Hello' }]);\n * ```\n */\nexport class AIServicePlugin implements Plugin {\n name = 'com.objectstack.service-ai';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies: string[] = ['com.objectstack.engine.objectql']; // manifest service required\n\n private service?: AIService;\n private readonly options: AIServicePluginOptions;\n\n constructor(options: AIServicePluginOptions = {}) {\n this.options = options;\n }\n\n /**\n * Auto-detect LLM provider from environment variables.\n *\n * Priority order:\n * 1. AI_GATEWAY_MODEL → Vercel AI Gateway\n * 2. OPENAI_API_KEY → OpenAI\n * 3. ANTHROPIC_API_KEY → Anthropic\n * 4. GOOGLE_GENERATIVE_AI_API_KEY → Google\n * 5. Fallback → MemoryLLMAdapter\n *\n * Returns the adapter and a description for logging.\n */\n private async detectAdapter(ctx: PluginContext): Promise<{ adapter: LLMAdapter; description: string }> {\n // 1. Vercel AI Gateway — works with any provider via gateway('provider/model')\n const gatewayModel = process.env.AI_GATEWAY_MODEL;\n if (gatewayModel) {\n try {\n const gatewayPkg = '@ai-sdk/gateway';\n const { gateway } = await import(/* webpackIgnore: true */ gatewayPkg);\n const adapter = new VercelLLMAdapter({ model: gateway(gatewayModel) });\n return { adapter, description: `Vercel AI Gateway (model: ${gatewayModel})` };\n } catch (err) {\n ctx.logger.warn(\n `[AI] Failed to load @ai-sdk/gateway for AI_GATEWAY_MODEL=${gatewayModel}, trying next provider`,\n err instanceof Error ? { error: err.message } : undefined\n );\n }\n }\n\n // 2. Direct provider SDKs\n const providerConfigs: Array<{\n envKey: string;\n pkg: string;\n factory: string;\n defaultModel: string;\n displayName: string;\n }> = [\n {\n envKey: 'OPENAI_API_KEY',\n pkg: '@ai-sdk/openai',\n factory: 'openai',\n defaultModel: 'gpt-4o',\n displayName: 'OpenAI'\n },\n {\n envKey: 'ANTHROPIC_API_KEY',\n pkg: '@ai-sdk/anthropic',\n factory: 'anthropic',\n defaultModel: 'claude-sonnet-4-20250514',\n displayName: 'Anthropic'\n },\n {\n envKey: 'GOOGLE_GENERATIVE_AI_API_KEY',\n pkg: '@ai-sdk/google',\n factory: 'google',\n defaultModel: 'gemini-2.0-flash',\n displayName: 'Google'\n },\n ];\n\n for (const { envKey, pkg, factory, defaultModel, displayName } of providerConfigs) {\n if (process.env[envKey]) {\n try {\n const mod = await import(/* webpackIgnore: true */ pkg);\n const createModel = mod[factory] ?? mod.default;\n if (typeof createModel === 'function') {\n const modelId = process.env.AI_MODEL ?? defaultModel;\n const adapter = new VercelLLMAdapter({ model: createModel(modelId) });\n return { adapter, description: `${displayName} (model: ${modelId})` };\n }\n } catch (err) {\n ctx.logger.warn(\n `[AI] Failed to load ${pkg} for ${envKey}, trying next provider`,\n err instanceof Error ? { error: err.message } : undefined\n );\n }\n }\n }\n\n // 3. Fallback to MemoryLLMAdapter\n ctx.logger.warn('[AI] No LLM provider configured via environment variables. Falling back to MemoryLLMAdapter (echo mode). Set AI_GATEWAY_MODEL, OPENAI_API_KEY, ANTHROPIC_API_KEY, or GOOGLE_GENERATIVE_AI_API_KEY to use a real LLM.');\n return { adapter: new MemoryLLMAdapter(), description: 'MemoryLLMAdapter (echo mode - for testing only)' };\n }\n\n async init(ctx: PluginContext): Promise<void> {\n // Check if there is an existing AI service (e.g. from dev-plugin)\n let hasExisting = false;\n try {\n const existing = ctx.getService<IAIService>('ai');\n if (existing && typeof existing.chat === 'function') {\n hasExisting = true;\n ctx.logger.debug('[AI] Found existing AI service, replacing');\n }\n } catch {\n // No existing service — that's fine\n }\n\n // Determine conversation service: explicit > auto-detect IDataEngine > InMemory fallback\n let conversationService: IAIConversationService | undefined = this.options.conversationService;\n if (!conversationService) {\n try {\n const engine = ctx.getService<IDataEngine>('data');\n if (engine && typeof engine.find === 'function') {\n conversationService = new ObjectQLConversationService(engine);\n ctx.logger.info('[AI] Using ObjectQLConversationService (IDataEngine detected)');\n }\n } catch {\n // No data engine — fall back to InMemory\n }\n }\n\n // Determine LLM adapter: explicit > auto-detect from env > MemoryLLMAdapter fallback\n let adapter: LLMAdapter;\n let adapterDescription: string;\n\n if (this.options.adapter) {\n // User provided an explicit adapter\n adapter = this.options.adapter;\n adapterDescription = `${adapter.name} (explicitly configured)`;\n } else {\n // Auto-detect from environment variables\n const detected = await this.detectAdapter(ctx);\n adapter = detected.adapter;\n adapterDescription = detected.description;\n }\n\n // Log the selected adapter\n ctx.logger.info(`[AI] Using LLM adapter: ${adapterDescription}`);\n\n const config: AIServiceConfig = {\n adapter,\n logger: ctx.logger,\n conversationService,\n };\n\n this.service = new AIService(config);\n\n // Register or replace the AI service\n if (hasExisting) {\n ctx.replaceService('ai', this.service);\n } else {\n ctx.registerService('ai', this.service);\n }\n\n // Register AI system objects via the manifest service.\n ctx.getService<{ register(m: any): void }>('manifest').register({\n id: 'com.objectstack.service-ai',\n name: 'AI Service',\n version: '1.0.0',\n type: 'plugin',\n namespace: 'ai',\n objects: [AiConversationObject, AiMessageObject],\n });\n\n if (this.options.debug) {\n ctx.hook('ai:beforeChat', async (messages: unknown) => {\n ctx.logger.debug('[AI] Before chat', { messages });\n });\n }\n\n // Contribute navigation items to the Setup App (if SetupPlugin is loaded).\n try {\n const setupNav = ctx.getService<{ contribute(c: any): void }>('setupNav');\n if (setupNav) {\n setupNav.contribute({\n areaId: 'area_ai',\n items: [\n { id: 'nav_ai_conversations', type: 'object', label: { key: 'setup.nav.ai_conversations', defaultValue: 'Conversations' }, objectName: 'conversations', icon: 'message-square', order: 10 },\n { id: 'nav_ai_messages', type: 'object', label: { key: 'setup.nav.ai_messages', defaultValue: 'Messages' }, objectName: 'messages', icon: 'messages-square', order: 20 },\n ],\n });\n ctx.logger.info('[AI] Navigation items contributed to Setup App');\n }\n } catch {\n // SetupPlugin not loaded — skip silently\n }\n\n ctx.logger.info('[AI] Service initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (!this.service) return;\n\n // ── Auto-register built-in tools & agents when services are available ──\n let metadataService: IMetadataService | undefined;\n try {\n metadataService = ctx.getService<IMetadataService>('metadata');\n } catch {\n ctx.logger.debug('[AI] Metadata service not available');\n }\n\n // Data tools require both data engine and metadata service\n try {\n const dataEngine = ctx.getService<IDataEngine>('data');\n if (dataEngine && metadataService) {\n registerDataTools(this.service.toolRegistry, { dataEngine, metadataService });\n ctx.logger.info('[AI] Built-in data tools registered');\n\n // Register the built-in data_chat agent only if it does not already exist\n const agentExists =\n typeof metadataService.exists === 'function'\n ? await metadataService.exists('agent', DATA_CHAT_AGENT.name)\n : false;\n\n if (!agentExists) {\n await metadataService.register('agent', DATA_CHAT_AGENT.name, DATA_CHAT_AGENT);\n ctx.logger.info('[AI] data_chat agent registered');\n } else {\n ctx.logger.debug('[AI] data_chat agent already exists, skipping auto-registration');\n }\n }\n } catch {\n ctx.logger.debug('[AI] Data engine not available, skipping data tools');\n }\n\n // Metadata tools require only the metadata service\n if (metadataService) {\n try {\n registerMetadataTools(this.service.toolRegistry, { metadataService });\n ctx.logger.info('[AI] Built-in metadata tools registered');\n\n // Register the built-in metadata_assistant agent\n const agentExists =\n typeof metadataService.exists === 'function'\n ? await metadataService.exists('agent', METADATA_ASSISTANT_AGENT.name)\n : false;\n\n if (!agentExists) {\n await metadataService.register('agent', METADATA_ASSISTANT_AGENT.name, METADATA_ASSISTANT_AGENT);\n ctx.logger.info('[AI] metadata_assistant agent registered');\n } else {\n ctx.logger.debug('[AI] metadata_assistant agent already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.debug('[AI] Failed to register metadata tools', err instanceof Error ? err : undefined);\n }\n }\n\n // Trigger hook to notify AI service is ready — other plugins can register tools\n await ctx.trigger('ai:ready', this.service);\n\n // Build and expose route definitions\n const routes = buildAIRoutes(this.service, this.service.conversationService, ctx.logger);\n\n // Build agent routes if metadata service is available\n try {\n const metadataService = ctx.getService<IMetadataService>('metadata');\n if (metadataService) {\n const agentRuntime = new AgentRuntime(metadataService);\n const agentRoutes = buildAgentRoutes(this.service, agentRuntime, ctx.logger);\n routes.push(...agentRoutes);\n }\n } catch {\n ctx.logger.debug('[AI] Metadata service not available, skipping agent routes');\n }\n\n // Trigger hook so HTTP server plugins can mount these routes\n await ctx.trigger('ai:routes', routes);\n\n // Cache routes on the kernel so HttpDispatcher can find them\n const kernel = ctx.getKernel();\n if (kernel) {\n (kernel as any).__aiRoutes = routes;\n }\n\n ctx.logger.info(\n `[AI] Service started — adapter=\"${this.service.adapterName}\", ` +\n `tools=${this.service.toolRegistry.size}, ` +\n `routes=${routes.length}`,\n );\n }\n\n async destroy(): Promise<void> {\n this.service = undefined;\n }\n}\n"],"mappings":"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","names":["result","import_data","import_ai","import_ai","import_ai","import_ai","import_ai","createListObjectsHandler","createDescribeObjectHandler","import_ai","import_ai","vercelTool","metadataService"]}
|