@objectstack/service-ai 6.5.1 → 6.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../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-objects.tool.ts","../src/tools/describe-object.tool.ts","../src/tools/metadata-tools.ts","../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/trace-recorder.ts","../src/stream/vercel-stream-encoder.ts","../src/routes/message-utils.ts","../src/routes/ai-routes.ts","../src/routes/agent-routes.ts","../src/routes/assistant-routes.ts","../src/routes/tool-routes.ts","../src/routes/pending-action-routes.ts","../src/conversation/objectql-conversation-service.ts","../src/objects/ai-conversation.object.ts","../src/objects/ai-message.object.ts","../src/objects/ai-trace.object.ts","../src/objects/ai-pending-action.object.ts","../src/views/ai-trace.view.ts","../src/views/ai-pending-action.view.ts","../src/plugin.ts","../src/tools/query-data.tool.ts","../src/schema-retriever.ts","../src/tools/action-tools.ts","../src/agent-runtime.ts","../src/skill-registry.ts","../src/agents/data-chat-agent.ts","../src/agents/metadata-assistant-agent.ts","../src/skills/data-explorer-skill.ts","../src/skills/metadata-authoring-skill.ts","../src/skills/actions-executor-skill.ts","../src/adapters/vercel-adapter.ts","../src/model-registry.ts","../src/tools/knowledge-tools.ts","../src/tools/list-packages.tool.ts","../src/tools/get-package.tool.ts","../src/tools/create-package.tool.ts","../src/tools/get-active-package.tool.ts","../src/tools/set-active-package.tool.ts","../src/tools/package-tools.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIToolDefinition,\n IDataEngine,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport type { ToolHandler, ToolExecutionContext } from './tool-registry.js';\nimport type { ToolRegistry } from './tool-registry.js';\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}\n\n/**\n * Translate a {@link ToolExecutionContext} into the ObjectQL\n * {@link ExecutionContext} that data-engine calls expect.\n *\n * When the AI tool call carries an authenticated `actor`, we forward\n * the user/roles/permissions and explicitly set `isSystem: false` so\n * row-level security and field masking kick in just like they would\n * for a normal REST request.\n *\n * When no actor is supplied (legacy callers, cron jobs, plugin-level\n * bootstraps) we send `isSystem: true` to preserve today's\n * unrestricted behaviour — closing the agent-permission gap is\n * opt-in at the call site that knows the user.\n */\nfunction buildEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\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 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 required: ['field', 'order'],\n additionalProperties: false,\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 additionalProperties: false,\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 tools definitions. */\nexport const DATA_TOOL_DEFINITIONS: AIToolDefinition[] = [\n QUERY_RECORDS_TOOL,\n GET_RECORD_TOOL,\n AGGREGATE_DATA_TOOL,\n];\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createQueryRecordsHandler(ctx: DataToolContext): ToolHandler {\n return async (args, execCtx) => {\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 context: buildEngineContext(execCtx),\n });\n\n return JSON.stringify({ count: records.length, records });\n };\n}\n\nfunction createGetRecordHandler(ctx: DataToolContext): ToolHandler {\n return async (args, execCtx) => {\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 context: buildEngineContext(execCtx),\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, execCtx) => {\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 context: buildEngineContext(execCtx),\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 the data engine is available.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const dataEngine = ctx.getService<IDataEngine>('data');\n * registerDataTools(aiService.toolRegistry, { dataEngine });\n * });\n * ```\n */\nexport function registerDataTools(\n registry: ToolRegistry,\n context: DataToolContext,\n): void {\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 packageId: {\n type: 'string',\n description: 'Package ID that will own this object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\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 packageId: {\n type: 'string',\n description: 'Package ID that owns the target object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\n },\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 packageId: {\n type: 'string',\n description: 'Package ID that owns the target object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\n },\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 packageId: {\n type: 'string',\n description: 'Package ID that owns the target object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\n },\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_objects — AI Tool Metadata\n *\n * Lists all registered data objects (tables) with optional filtering\n * and field summaries. This is the single, unified tool for listing\n * objects — used by both data_chat and metadata_assistant agents.\n */\nexport const listObjectsTool = defineTool({\n name: 'list_objects',\n label: 'List Objects',\n description:\n 'Lists all registered data objects (tables) in the current environment. ' +\n 'Use this when the user wants to see what tables, entities, or data models are available.',\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_object — AI Tool Metadata\n *\n * Returns the full schema of a data object including all fields, types,\n * relationships, and configuration. This is the single, unified tool for\n * describing objects — used by both data_chat and metadata_assistant agents.\n */\nexport const describeObjectTool = defineTool({\n name: 'describe_object',\n label: 'Describe Object',\n description:\n 'Returns the full schema details of a data object, including all fields, types, relationships, and configuration. ' +\n 'Use this to understand the structure of a table before querying or modifying it.',\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 { listObjectsTool } from './list-objects.tool.js';\nexport { describeObjectTool } from './describe-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 { listObjectsTool } from './list-objects.tool.js';\nimport { describeObjectTool } from './describe-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 listObjectsTool,\n describeObjectTool,\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// Package Resolution Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Retrieves the active package ID from the conversation context.\n * Returns null if no conversation service is available or no active package is set.\n */\nasync function getActivePackageId(ctx: MetadataToolContext): Promise<string | null> {\n if (!ctx.conversationService?.getMetadata || !ctx.conversationId) {\n return null;\n }\n\n const metadata = await ctx.conversationService.getMetadata(ctx.conversationId);\n return (metadata?.activePackageId as string) ?? null;\n}\n\n/**\n * Resolves the package ID to use for a metadata operation.\n * Priority: explicit packageId > active package from conversation > error\n *\n * Also validates that the package exists and checks if it's read-only.\n *\n * @returns Object with packageId or error message\n */\nasync function resolvePackageId(\n ctx: MetadataToolContext,\n explicitPackageId?: string,\n): Promise<{ packageId: string | null; error?: string; warning?: string }> {\n let packageId: string | null = null;\n\n // 1. Try explicit packageId parameter\n if (explicitPackageId) {\n packageId = explicitPackageId;\n } else {\n // 2. Try active package from conversation\n packageId = await getActivePackageId(ctx);\n }\n\n // If no package ID could be resolved, return null (backward compatibility)\n // This allows metadata to be stored without package association\n if (!packageId) {\n return {\n packageId: null,\n warning: 'No package specified. Metadata will be created without package association. Consider using set_active_package or providing packageId parameter.',\n };\n }\n\n // Validate package exists (if registry is available)\n if (ctx.packageRegistry) {\n const exists = await ctx.packageRegistry.exists(packageId);\n if (!exists) {\n return {\n packageId: null,\n error: `Package \"${packageId}\" not found. Use list_packages to see available packages or create_package to create a new one.`,\n };\n }\n\n // Check if package is read-only (code-based)\n const pkg = await ctx.packageRegistry.get(packageId);\n if (pkg?.manifest.source === 'filesystem') {\n return {\n packageId: null,\n error: `Package \"${packageId}\" is read-only (loaded from code). Only database packages can be modified. Use create_package to create a new database package.`,\n };\n }\n }\n\n return { packageId };\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 /** Optional: Conversation service for retrieving active package context */\n conversationService?: {\n getMetadata?(conversationId: string): Promise<Record<string, unknown> | undefined>;\n };\n\n /** Optional: Current conversation ID (if in a conversation context) */\n conversationId?: string;\n\n /** Optional: Package registry for validating package existence */\n packageRegistry?: {\n exists(packageId: string): Promise<boolean>;\n get(packageId: string): Promise<{ manifest: { scope?: string; source?: string } } | undefined>;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createCreateObjectHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { name, label, packageId: explicitPackageId, fields, enableFeatures } = args as {\n name: string;\n label: string;\n packageId?: 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 // Resolve package ID\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\n }\n const packageId = resolved.packageId;\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 ...(packageId ? { packageId } : {}),\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 ...(packageId ? { packageId } : {}),\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, packageId: explicitPackageId } = 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 packageId?: string;\n };\n\n if (!objectName || !name || !type) {\n return JSON.stringify({ error: '\"objectName\", \"name\", and \"type\" are required' });\n }\n\n // Resolve package ID (for validation and tracking)\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\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 packageId: resolved.packageId,\n });\n };\n}\n\nfunction createModifyFieldHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, fieldName, changes, packageId: explicitPackageId } = args as {\n objectName: string;\n fieldName: string;\n changes: Record<string, unknown>;\n packageId?: string;\n };\n\n if (!objectName || !fieldName || !changes) {\n return JSON.stringify({ error: '\"objectName\", \"fieldName\", and \"changes\" are required' });\n }\n\n // Resolve package ID (for validation and tracking)\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\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 packageId: resolved.packageId,\n });\n };\n}\n\nfunction createDeleteFieldHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, fieldName, packageId: explicitPackageId } = args as {\n objectName: string;\n fieldName: string;\n packageId?: string;\n };\n\n if (!objectName || !fieldName) {\n return JSON.stringify({ error: '\"objectName\" and \"fieldName\" are required' });\n }\n\n // Resolve package ID (for validation and tracking)\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\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 packageId: resolved.packageId,\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(listObjectsTool, createListObjectsHandler(context));\n registry.register(describeObjectTool, createDescribeObjectHandler(context));\n}\n","// 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// Knowledge tools\nexport { registerKnowledgeTools, SEARCH_KNOWLEDGE_TOOL } from './tools/knowledge-tools.js';\nexport type { KnowledgeToolContext } from './tools/knowledge-tools.js';\n\n// Individual tool metadata (first-class Tool definitions via defineTool)\nexport {\n createObjectTool,\n addFieldTool,\n modifyFieldTool,\n deleteFieldTool,\n listObjectsTool,\n describeObjectTool,\n} from './tools/metadata-tools.js';\n\n// Package tools\nexport { registerPackageTools, PACKAGE_TOOL_DEFINITIONS } from './tools/package-tools.js';\nexport type { PackageToolContext, IPackageRegistry, IConversationService } from './tools/package-tools.js';\n\n// Individual package tool metadata\nexport {\n listPackagesTool,\n getPackageTool,\n createPackageTool,\n getActivePackageTool,\n setActivePackageTool,\n} from './tools/package-tools.js';\n\n// Action tools (write-side: turn declarative Actions into AI-callable tools)\nexport {\n registerActionsAsTools,\n actionToToolDefinition,\n actionToolName,\n actionSkipReason,\n} from './tools/action-tools.js';\nexport type { ActionToolsContext } from './tools/action-tools.js';\n\n// Agent runtime\nexport { AgentRuntime } from './agent-runtime.js';\nexport type { AgentChatContext } from './agent-runtime.js';\n\n// Skill registry (Agent → Skill → Tool composition)\nexport { SkillRegistry } from './skill-registry.js';\nexport type { SkillContext, SkillSummary } from './skill-registry.js';\n\n// Built-in agents\nexport { DATA_CHAT_AGENT, METADATA_ASSISTANT_AGENT } from './agents/index.js';\n\n// Built-in skills\nexport {\n DATA_EXPLORER_SKILL,\n METADATA_AUTHORING_SKILL,\n ACTIONS_EXECUTOR_SKILL,\n} from './skills/index.js';\n\n// Object definitions\nexport { AiConversationObject, AiMessageObject, AiTraceObject } from './objects/index.js';\n\n// View definitions (built-in Studio surfaces)\nexport { AiTraceView } from './views/index.js';\n\n// Model registry\nexport { ModelRegistry, computeCost } from './model-registry.js';\nexport type { ModelRegistryConfig, CostEstimate, TokenUsage } from './model-registry.js';\n\n// Trace recorder\nexport {\n NullTraceRecorder,\n ObjectQLTraceRecorder,\n buildTraceEvent,\n} from './trace-recorder.js';\nexport type { TraceRecorder, TraceEvent, TraceOperation } from './trace-recorder.js';\n\n// Schema retriever (keyword-based metadata retrieval for AI prompts)\nexport { SchemaRetriever } from './schema-retriever.js';\nexport type {\n SchemaHit,\n SchemaRetrieverOptions,\n ObjectShape,\n FieldShape,\n} from './schema-retriever.js';\n\n// query_data tool (NL → ObjectQL via structured output)\nexport {\n QUERY_DATA_TOOL,\n createQueryDataHandler,\n registerQueryDataTool,\n} from './tools/query-data.tool.js';\nexport type { QueryDataToolContext, QueryPlan } from './tools/query-data.tool.js';\n\n// Routes\nexport { buildAIRoutes } from './routes/ai-routes.js';\nexport { buildAgentRoutes } from './routes/agent-routes.js';\nexport { buildAssistantRoutes } from './routes/assistant-routes.js';\nexport { buildToolRoutes } from './routes/tool-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 AIObjectResult,\n GenerateObjectOptions,\n IAIService,\n IAIConversationService,\n IDataEngine,\n ChatWithToolsOptions,\n LLMAdapter,\n PendingActionRow,\n PendingActionStatus,\n ProposePendingActionInput,\n} from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport type { z } from 'zod';\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';\nimport { ModelRegistry } from './model-registry.js';\nimport {\n NullTraceRecorder,\n buildTraceEvent,\n type TraceRecorder,\n type TraceOperation,\n} from './trace-recorder.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 /** Model registry for pricing + default model resolution. Optional. */\n modelRegistry?: ModelRegistry;\n /** Trace recorder for per-call observability. Defaults to no-op. */\n traceRecorder?: TraceRecorder;\n /**\n * Data engine used to persist `ai_pending_actions` rows for the\n * actions-as-tools HITL queue. Optional — when omitted, the\n * `proposePendingAction` / `approvePendingAction` methods throw if\n * called. Wired by `AIServicePlugin` after the data driver is up.\n */\n dataEngine?: IDataEngine;\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 readonly modelRegistry?: ModelRegistry;\n readonly traceRecorder: TraceRecorder;\n /**\n * Map of tool-name → dispatcher used to re-run an approved pending\n * action. Populated by `registerActionsAsTools()` when action\n * approval is enabled. Kept private because callers should go\n * through `approvePendingAction()`.\n */\n private readonly pendingDispatchers = new Map<\n string,\n (input: Record<string, unknown>) => Promise<unknown>\n >();\n /** Data engine for `ai_pending_actions` persistence. */\n private readonly dataEngine?: IDataEngine;\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 this.modelRegistry = config.modelRegistry;\n this.traceRecorder = config.traceRecorder ?? new NullTraceRecorder();\n this.dataEngine = config.dataEngine;\n\n this.logger.info(\n `[AI] Service initialized with adapter=\"${this.adapter.name}\", ` +\n `tools=${this.toolRegistry.size}, models=${this.modelRegistry?.size ?? 0}`,\n );\n }\n\n /** The name of the active LLM adapter. */\n get adapterName(): string {\n return this.adapter.name;\n }\n\n /**\n * Best-effort persistence of a single chat message to the conversation\n * store. Failures are logged at warn level and swallowed — chat requests\n * must never fail because the history write failed. Mirrors the\n * precedent set by `ObjectQLTraceRecorder.record`.\n */\n private async persistMessage(conversationId: string, message: ModelMessage): Promise<void> {\n try {\n await this.conversationService.addMessage(conversationId, message);\n } catch (err) {\n this.logger.warn('[AI] persist message failed', {\n conversationId,\n role: (message as { role?: string }).role,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /**\n * Run an adapter call and emit a trace event.\n *\n * Records both success and failure. Tracing failures never escape — the\n * recorder is expected to be defensive.\n */\n private async instrument<T extends { model?: string; usage?: AIResult['usage'] }>(\n operation: TraceOperation,\n options: AIRequestOptions | undefined,\n fn: () => Promise<T>,\n ): Promise<T> {\n const started = Date.now();\n try {\n const result = await fn();\n void this.traceRecorder.record(buildTraceEvent({\n operation,\n adapter: this.adapter.name,\n model: result.model ?? options?.model,\n usage: result.usage,\n latencyMs: Date.now() - started,\n status: 'success',\n registry: this.modelRegistry,\n }));\n return result;\n } catch (err) {\n void this.traceRecorder.record(buildTraceEvent({\n operation,\n adapter: this.adapter.name,\n model: options?.model,\n latencyMs: Date.now() - started,\n status: 'error',\n error: err instanceof Error ? err.message : String(err),\n registry: this.modelRegistry,\n }));\n throw err;\n }\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.instrument('chat', options, () => 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.instrument('complete', options, () => this.adapter.complete(prompt, options));\n }\n\n /**\n * Generate a strongly-typed object validated against a Zod schema.\n *\n * Delegates to the adapter's `generateObject` when supported; throws a\n * descriptive error when the adapter does not implement structured output.\n *\n * @example\n * ```ts\n * import { z } from 'zod';\n * const Schema = z.object({ name: z.string(), priority: z.number().int() });\n * const { object } = await ai.generateObject(messages, Schema);\n * ```\n */\n async generateObject<T>(\n messages: ModelMessage[],\n schema: z.ZodType<T>,\n options?: GenerateObjectOptions,\n ): Promise<AIObjectResult<T>> {\n this.logger.debug('[AI] generateObject', { messageCount: messages.length, model: options?.model });\n if (!this.adapter.generateObject) {\n throw new Error(\n `[AI] Adapter \"${this.adapter.name}\" does not support generateObject. ` +\n `Use VercelLLMAdapter with a structured-output-capable model.`,\n );\n }\n return this.instrument('generate_object', options, () =>\n this.adapter.generateObject!(messages, schema, options),\n );\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 return this.instrument('chat_with_tools', options, () =>\n this.chatWithToolsImpl(messages, options),\n );\n }\n\n private async chatWithToolsImpl(\n messages: ModelMessage[],\n options?: ChatWithToolsOptions,\n ): Promise<AIResult> {\n // Destructure loop-specific options so they are never forwarded to the adapter\n const {\n maxIterations: maxIter,\n onToolError,\n toolExecutionContext,\n ...restOptions\n } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n const conversationId = toolExecutionContext?.conversationId;\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 // Persist the inbound user turn when a conversationId is supplied.\n // Only the last message is written — callers are assumed to pass\n // prior history alongside the new turn; we don't diff.\n if (conversationId && messages.length > 0) {\n const last = messages[messages.length - 1];\n if (last && (last as { role?: string }).role === 'user') {\n await this.persistMessage(conversationId, last);\n }\n }\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: result.content,\n } as ModelMessage);\n }\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 const assistantTurn = {\n role: 'assistant',\n content: assistantContent,\n } as ModelMessage;\n conversation.push(assistantTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, assistantTurn);\n }\n\n // Execute all tool calls in parallel, threading the per-request\n // execution context so handlers can attribute work to the actor\n // and enforce row-level security.\n const toolResults: ToolExecutionResult[] = await this.toolRegistry.executeAll(\n result.toolCalls,\n toolExecutionContext,\n );\n\n // Process results: track errors, honour onToolError callback, and\n // append each tool result as a `role: 'tool'` message so the\n // model can react in the next loop iteration.\n for (const tr of toolResults) {\n if (tr.isError) {\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 const toolTurn = {\n role: 'tool',\n content: [tr],\n } as ModelMessage;\n conversation.push(toolTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, toolTurn);\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: finalResult.content,\n } as ModelMessage);\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 {\n maxIterations: maxIter,\n onToolError,\n toolExecutionContext,\n ...restOptions\n } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n const conversationId = toolExecutionContext?.conversationId;\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 if (conversationId && messages.length > 0) {\n const last = messages[messages.length - 1];\n if (last && (last as { role?: string }).role === 'user') {\n await this.persistMessage(conversationId, last);\n }\n }\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: result.content,\n } as ModelMessage);\n }\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 const assistantTurn = {\n role: 'assistant',\n content: assistantContent,\n } as ModelMessage;\n conversation.push(assistantTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, assistantTurn);\n }\n\n const toolResults: ToolExecutionResult[] = await this.toolRegistry.executeAll(\n result.toolCalls,\n toolExecutionContext,\n );\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 // Emit tool-result so the client can see tool output via SSE\n yield {\n type: 'tool-result',\n toolCallId: tr.toolCallId,\n toolName: tr.toolName,\n output: tr.output,\n } as TextStreamPart<ToolSet>;\n const toolTurn = {\n role: 'tool',\n content: [tr],\n } as ModelMessage;\n conversation.push(toolTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, toolTurn);\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: result.content,\n } as ModelMessage);\n }\n yield textDeltaPart('stream', result.content);\n yield finishPart(result);\n }\n\n // ── HITL: pending-action queue ─────────────────────────────────\n\n /**\n * Register a dispatcher callback for a tool. Called by\n * `registerActionsAsTools()` when action approval is enabled so the\n * approval handler can re-run the exact same code path the LLM\n * would have triggered.\n */\n registerPendingActionDispatcher(\n toolName: string,\n dispatch: (input: Record<string, unknown>) => Promise<unknown>,\n ): void {\n this.pendingDispatchers.set(toolName, dispatch);\n }\n\n async proposePendingAction(input: ProposePendingActionInput): Promise<{ id: string }> {\n if (!this.dataEngine) {\n throw new Error('proposePendingAction requires a dataEngine — wire it via AIServiceConfig.');\n }\n const id = `pa_${cryptoRandomId()}`;\n const row = {\n id,\n conversation_id: input.conversationId ?? null,\n message_id: input.messageId ?? null,\n object_name: input.objectName,\n action_name: input.actionName,\n tool_name: input.toolName,\n tool_input: JSON.stringify(input.toolInput ?? {}),\n status: 'pending',\n proposed_by: input.proposedBy ?? 'ai_agent',\n proposed_at: new Date().toISOString(),\n };\n await this.dataEngine.insert('ai_pending_actions', row);\n this.logger.info(\n `[AI] pending action proposed: ${id} (${input.toolName} on ${input.objectName})`,\n );\n return { id };\n }\n\n async approvePendingAction(\n id: string,\n actorId: string,\n ): Promise<{ status: 'executed' | 'failed'; result?: unknown; error?: string }> {\n if (!this.dataEngine) {\n throw new Error('approvePendingAction requires a dataEngine.');\n }\n const row = await this.loadPendingRow(id);\n if (row.status !== 'pending') {\n throw new Error(`pending action ${id} is already ${row.status}`);\n }\n const dispatch = this.pendingDispatchers.get(row.tool_name);\n if (!dispatch) {\n throw new Error(\n `no dispatcher registered for tool '${row.tool_name}' — was the AI plugin restarted without re-registering actions?`,\n );\n }\n await this.dataEngine.update(\n 'ai_pending_actions',\n {\n id,\n status: 'approved',\n decided_by: actorId,\n decided_at: new Date().toISOString(),\n },\n { where: { id } },\n );\n let parsed: Record<string, unknown> = {};\n try {\n parsed = row.tool_input ? (JSON.parse(row.tool_input) as Record<string, unknown>) : {};\n } catch {\n parsed = {};\n }\n try {\n const out = await dispatch(parsed);\n await this.dataEngine.update(\n 'ai_pending_actions',\n { id, status: 'executed', result: JSON.stringify(out ?? null) },\n { where: { id } },\n );\n this.logger.info(`[AI] pending action ${id} executed by ${actorId}`);\n return { status: 'executed', result: out };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n await this.dataEngine.update(\n 'ai_pending_actions',\n { id, status: 'failed', error: msg },\n { where: { id } },\n );\n this.logger.warn(`[AI] pending action ${id} failed after approval: ${msg}`);\n return { status: 'failed', error: msg };\n }\n }\n\n async rejectPendingAction(id: string, actorId: string, reason?: string): Promise<void> {\n if (!this.dataEngine) {\n throw new Error('rejectPendingAction requires a dataEngine.');\n }\n const row = await this.loadPendingRow(id);\n if (row.status !== 'pending') {\n throw new Error(`pending action ${id} is already ${row.status}`);\n }\n await this.dataEngine.update(\n 'ai_pending_actions',\n {\n id,\n status: 'rejected',\n decided_by: actorId,\n decided_at: new Date().toISOString(),\n rejection_reason: reason ?? null,\n },\n { where: { id } },\n );\n this.logger.info(`[AI] pending action ${id} rejected by ${actorId}`);\n }\n\n async listPendingActions(filter?: {\n status?: PendingActionStatus | PendingActionStatus[];\n conversationId?: string;\n objectName?: string;\n limit?: number;\n }): Promise<PendingActionRow[]> {\n if (!this.dataEngine) return [];\n const where: Record<string, unknown> = {};\n if (filter?.status) {\n where.status = Array.isArray(filter.status) ? { in: filter.status } : filter.status;\n }\n if (filter?.conversationId) where.conversation_id = filter.conversationId;\n if (filter?.objectName) where.object_name = filter.objectName;\n const rows = (await this.dataEngine.find('ai_pending_actions', {\n where,\n limit: filter?.limit ?? 100,\n orderBy: [{ field: 'proposed_at', order: 'desc' }],\n })) as PendingActionRow[];\n return rows;\n }\n\n private async loadPendingRow(id: string): Promise<PendingActionRow> {\n const rows = (await this.dataEngine!.find('ai_pending_actions', {\n where: { id },\n limit: 1,\n })) as PendingActionRow[];\n const row = rows[0];\n if (!row) throw new Error(`pending action ${id} not found`);\n return row;\n }\n}\n\nfunction cryptoRandomId(): string {\n // crypto.randomUUID is available in Node 16+ and modern browsers; fall\n // back to a timestamp+random pair for environments that lack it.\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { z } from 'zod';\nimport type {\n ModelMessage,\n AIRequestOptions,\n AIResult,\n AIObjectResult,\n GenerateObjectOptions,\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 userText = typeof userContent === 'string' ? userContent : '(complex content)';\n\n // ── Heuristic tool-calling support ──────────────────────────────────────\n // When `chatWithTools` injects available tools the adapter drives a\n // small two-step plan so demos/tests work end-to-end without a real\n // LLM provider:\n //\n // 1. If the user's message looks like an *action* request\n // (verbs like \"complete\", \"start\", \"clone\", ...) and an\n // `action_<name>` tool is registered, prefer it. Resolve the\n // record id from any prior `query_data` result.\n // 2. Otherwise, if a `query_data` tool is present and hasn't been\n // called yet, call it with the user's text.\n // 3. After a `role: 'tool'` result comes back, summarise it.\n const tools = options?.tools as Array<{ name: string; description?: string }> | undefined;\n const hasQueryDataTool = Array.isArray(tools) && tools.some(t => t?.name === 'query_data');\n const alreadyCalledQueryData = messages.some(\n m =>\n m.role === 'tool' &&\n Array.isArray(m.content) &&\n (m.content as Array<{ toolName?: string }>).some(c => c?.toolName === 'query_data'),\n );\n const alreadyCalledAction = messages.some(\n m =>\n m.role === 'tool' &&\n Array.isArray(m.content) &&\n (m.content as Array<{ toolName?: string }>).some(\n c => typeof c?.toolName === 'string' && c.toolName.startsWith('action_'),\n ),\n );\n\n // ── Step 1: route action verbs to a matching `action_<name>` tool ──\n if (Array.isArray(tools) && !alreadyCalledAction && lastUserMessage) {\n const actionTools = tools.filter(t => typeof t?.name === 'string' && t.name.startsWith('action_'));\n const chosen = pickActionTool(userText, actionTools);\n if (chosen) {\n const recordId = extractRecordIdFromMessages(messages, userText);\n if (recordId) {\n const toolCallId = `memory_tc_${Date.now().toString(36)}`;\n return {\n content: '',\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n toolCalls: [\n {\n type: 'tool-call',\n toolCallId,\n toolName: chosen.name,\n input: { recordId },\n } as unknown as NonNullable<AIResult['toolCalls']>[number],\n ],\n };\n }\n // Need a record id but don't have one — fall through to query_data\n // first so we can resolve the target record.\n }\n }\n\n // ── Step 2: route data questions to `query_data` ──\n\n if (hasQueryDataTool && !alreadyCalledQueryData && lastUserMessage) {\n const toolCallId = `memory_tc_${Date.now().toString(36)}`;\n return {\n content: '',\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n toolCalls: [\n {\n type: 'tool-call',\n toolCallId,\n toolName: 'query_data',\n input: { request: userText },\n } as unknown as NonNullable<AIResult['toolCalls']>[number],\n ],\n };\n }\n\n // If a query_data result is already in the conversation, summarise it\n // (or fall through to step 1 if the action wasn't yet routable).\n if (alreadyCalledAction) {\n const lastTool = [...messages].reverse().find(m => m.role === 'tool');\n const part = Array.isArray(lastTool?.content)\n ? (lastTool!.content as Array<{\n toolName?: string;\n output?: { type?: string; value?: unknown };\n result?: unknown;\n }>).find(c => typeof c?.toolName === 'string' && c.toolName.startsWith('action_'))\n : undefined;\n const raw =\n part?.output && typeof part.output === 'object' && 'value' in part.output\n ? part.output.value\n : part?.result;\n let payload: { ok?: boolean; message?: string; error?: string; action?: string } = {};\n if (typeof raw === 'string') {\n try { payload = JSON.parse(raw); } catch { /* leave empty */ }\n } else if (raw && typeof raw === 'object') {\n payload = raw as typeof payload;\n }\n if (payload.error) {\n return {\n content: `[memory] action ${payload.action ?? ''} failed: ${payload.error}`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n return {\n content: `[memory] ${payload.message ?? 'Action executed.'} (${payload.action ?? 'action'})`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n if (alreadyCalledQueryData) {\n const lastTool = [...messages].reverse().find(m => m.role === 'tool');\n const part = Array.isArray(lastTool?.content)\n ? (lastTool!.content as Array<{\n toolName?: string;\n output?: { type?: string; value?: unknown };\n result?: unknown;\n }>).find(c => c?.toolName === 'query_data')\n : undefined;\n let payload: { records?: unknown[]; count?: number; error?: string } = {};\n const raw =\n part?.output && typeof part.output === 'object' && 'value' in part.output\n ? part.output.value\n : part?.result;\n if (typeof raw === 'string') {\n try {\n payload = JSON.parse(raw);\n } catch {\n payload = {};\n }\n } else if (raw && typeof raw === 'object') {\n payload = raw as typeof payload;\n }\n if (payload.error) {\n return {\n content: `[memory] query_data failed: ${payload.error}`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n const records = payload.records ?? [];\n const count = payload.count ?? records.length;\n return {\n content: `[memory] Found ${count} record${count === 1 ? '' : 's'} for \"${userText}\".`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n const content = lastUserMessage\n ? `[memory] ${userText}`\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 /**\n * Heuristic structured-output for testing & demos — NOT a real LLM.\n *\n * Strategy:\n * 1. Extract candidate object names from the system messages by matching\n * schema-context headers (`### name — Label`) emitted by\n * {@link SchemaRetriever.renderSnippet}.\n * 2. Pick the candidate whose tokens overlap most with the last user\n * message (falls back to the first candidate).\n * 3. Try `schema.safeParse({ objectName, limit: 20 })` — this satisfies the\n * `QueryPlanSchema` used by the built-in `query_data` tool.\n * 4. If that fails, fall back to `schema.safeParse({})` for schemas that\n * accept defaults.\n * 5. Otherwise throw with a clear message — the demo needs a real provider.\n */\n async generateObject<T = unknown>(\n messages: ModelMessage[],\n schema: z.ZodType<T>,\n options?: GenerateObjectOptions,\n ): Promise<AIObjectResult<T>> {\n const sys = messages\n .filter(m => m.role === 'system')\n .map(m => (typeof m.content === 'string' ? m.content : ''))\n .join('\\n');\n\n // Parse headers of the form `### machine_name — Label (Plural)` emitted\n // by SchemaRetriever.renderSnippet. Capture every alias so we can match\n // against natural-language user queries like \"show me my tasks\".\n const headerRe = /^###\\s+([a-z0-9_]+)(?:\\s+—\\s+([^\\n]+))?/gim;\n type Candidate = { name: string; aliasTokens: Set<string> };\n const candidates: Candidate[] = [];\n for (const match of sys.matchAll(headerRe)) {\n const machineName = match[1];\n if (!machineName) continue;\n const aliasText = match[2] ?? '';\n const aliasTokens = new Set<string>();\n // Tokens from the snake_case machine name\n for (const t of machineName.split(/[^a-z0-9]+/)) {\n if (t) aliasTokens.add(t);\n }\n // Tokens from the label / plural label (everything after the em dash)\n for (const t of aliasText.toLowerCase().split(/[^a-z0-9]+/)) {\n if (t) aliasTokens.add(t);\n }\n // Naive stem: include singular form of plural tokens ending in \"s\"\n for (const t of [...aliasTokens]) {\n if (t.length > 3 && t.endsWith('s')) aliasTokens.add(t.slice(0, -1));\n }\n candidates.push({ name: machineName, aliasTokens });\n }\n\n const lastUser = [...messages].reverse().find(m => m.role === 'user');\n const userText = typeof lastUser?.content === 'string'\n ? lastUser.content.toLowerCase()\n : '';\n const userTokens = new Set(\n userText.split(/[^a-z0-9_]+/).filter(t => t.length > 1),\n );\n // Apply the same naive plural→singular stem to user tokens so \"tasks\"\n // also looks up as \"task\".\n for (const t of [...userTokens]) {\n if (t.length > 3 && t.endsWith('s')) userTokens.add(t.slice(0, -1));\n }\n\n let chosen = candidates[0]?.name;\n let bestScore = -1;\n for (const cand of candidates) {\n let score = 0;\n for (const tok of cand.aliasTokens) {\n if (userTokens.has(tok)) score += 1;\n }\n if (score > bestScore) {\n bestScore = score;\n chosen = cand.name;\n }\n }\n\n const attempts: Array<Record<string, unknown>> = [];\n if (chosen) attempts.push({ objectName: chosen, limit: 20 });\n attempts.push({});\n\n for (const attempt of attempts) {\n const result = schema.safeParse(attempt);\n if (result.success) {\n return {\n object: result.data,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n }\n\n throw new Error(\n 'MemoryLLMAdapter.generateObject: unable to synthesise a value for the ' +\n 'requested schema. The memory adapter only handles QueryPlan-shaped ' +\n 'schemas — wire a real LLM adapter (OpenAI / Anthropic / Google) for ' +\n 'arbitrary structured output.',\n );\n }\n}\n\n// ── Heuristic helpers (memory adapter only) ─────────────────────────\n\n/**\n * Naive intent matcher for action-style requests.\n *\n * Returns the best matching `action_*` tool when:\n * 1. user text contains an \"action verb\" (a token shared with the tool's\n * name *that isn't the object noun*), AND\n * 2. that match isn't a pure query verb (\"show\", \"list\", \"find\", ...).\n *\n * Query verbs alone are routed to query_data instead.\n */\nfunction pickActionTool(\n userText: string,\n actionTools: Array<{ name: string; description?: string }>,\n): { name: string; description?: string } | null {\n if (actionTools.length === 0 || !userText) return null;\n const userTokens = new Set(\n userText\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter(t => t.length > 2),\n );\n // Action verbs imply a write — query verbs alone never route here.\n const ACTION_VERBS = new Set([\n 'complete', 'finish', 'done', 'close',\n 'start', 'begin', 'resume',\n 'clone', 'copy', 'duplicate',\n 'cancel', 'abort',\n 'archive', 'restore',\n 'approve', 'reject',\n 'assign', 'unassign',\n 'export', 'import',\n 'send', 'notify',\n 'publish', 'unpublish',\n 'mark',\n 'delete', 'remove', 'purge', 'destroy', 'erase',\n ]);\n const hasActionVerb = [...userTokens].some(t => ACTION_VERBS.has(t));\n if (!hasActionVerb) return null;\n\n let best: { name: string; description?: string } | null = null;\n let bestScore = 0;\n for (const tool of actionTools) {\n // Score by overlap on the action verb portion of the tool name. We\n // intentionally weight verbs higher than nouns (\"task\"/\"record\"/...)\n // so `action_complete_task` beats `action_clone_task` for \"complete\n // my groceries\".\n const nameTokens = tool.name\n .replace(/^action_/, '')\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter(t => t.length > 2);\n let score = 0;\n for (const tok of nameTokens) {\n if (!userTokens.has(tok)) continue;\n score += ACTION_VERBS.has(tok) ? 3 : 1;\n }\n if (score > bestScore) {\n bestScore = score;\n best = tool;\n }\n }\n // Require an action-verb match (score ≥ 3) to avoid noun-only false hits.\n return bestScore >= 3 ? best : null;\n}\n\n/**\n * Look back through the conversation for a `query_data` tool result and\n * pull a record id out of it. Picks the first record id whose subject /\n * label / name tokens overlap with the user's request — the same\n * heuristic the action picker uses but applied to record fields.\n */\nfunction extractRecordIdFromMessages(\n messages: ModelMessage[],\n userText: string,\n): string | undefined {\n const userTokens = userText\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter(t => t.length > 2);\n\n for (let i = messages.length - 1; i >= 0; i--) {\n const m = messages[i];\n if (m.role !== 'tool' || !Array.isArray(m.content)) continue;\n const parts = m.content as Array<{\n toolName?: string;\n output?: { value?: unknown };\n result?: unknown;\n }>;\n for (const part of parts) {\n if (part?.toolName !== 'query_data') continue;\n const raw =\n part.output && typeof part.output === 'object' && 'value' in part.output\n ? part.output.value\n : part.result;\n let payload: { records?: Array<Record<string, unknown>> } = {};\n if (typeof raw === 'string') {\n try { payload = JSON.parse(raw); } catch { /* ignore */ }\n } else if (raw && typeof raw === 'object') {\n payload = raw as typeof payload;\n }\n const records = payload.records ?? [];\n if (records.length === 0) continue;\n\n // Pick the record whose text fields best overlap user tokens.\n let bestId: string | undefined;\n let bestScore = -1;\n for (const rec of records) {\n if (!rec || typeof rec !== 'object') continue;\n const id = rec.id;\n if (typeof id !== 'string' && typeof id !== 'number') continue;\n const hay = Object.values(rec)\n .filter((v): v is string => typeof v === 'string')\n .join(' ')\n .toLowerCase();\n const hayTokens = hay.split(/[^a-z0-9]+/).filter(Boolean);\n let score = 0;\n for (const ut of userTokens) {\n if (hayTokens.includes(ut)) score += 1;\n }\n if (score > bestScore) {\n bestScore = score;\n bestId = String(id);\n }\n }\n // Fallback to the first record id when no tokens overlap.\n return bestId ?? String(records[0].id);\n }\n }\n return undefined;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIToolDefinition,\n ToolCallPart,\n ToolResultPart,\n ToolExecutionContext,\n} from '@objectstack/spec/contracts';\n\n/**\n * Re-exported {@link ToolExecutionContext} from `@objectstack/spec` so\n * tool implementations in this package can import a single canonical\n * symbol without depending on spec internals.\n *\n * The spec hosts the authoritative shape because `ChatWithToolsOptions`\n * exposes the same type to external callers (HTTP routes, custom\n * agents).\n */\nexport type { ToolExecutionContext };\n\n/**\n * Handler function for a registered tool.\n *\n * Receives parsed arguments and an optional per-call execution context.\n * Returns the tool output as a string (typically JSON). Tools that\n * require permission enforcement should use `ctx.actor` and propagate\n * it into the underlying engine call.\n */\nexport type ToolHandler = (\n args: Record<string, unknown>,\n ctx?: ToolExecutionContext,\n) => 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 * @param toolCall The decoded tool-call part from the model response.\n * @param ctx Optional per-call execution context (actor, conversation,\n * environment). Handlers may use this to enforce RLS,\n * attribute audit entries, or correlate traces. When\n * omitted, handlers should fall back to system-level\n * behaviour for backward compatibility.\n */\n async execute(\n toolCall: ToolCallPart,\n ctx?: ToolExecutionContext,\n ): 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, ctx);\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, threading the same\n * execution context to each handler.\n */\n async executeAll(\n toolCalls: ToolCallPart[],\n ctx?: ToolExecutionContext,\n ): Promise<ToolExecutionResult[]> {\n return Promise.all(toolCalls.map(tc => this.execute(tc, ctx)));\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\nimport { randomUUID } from 'node:crypto';\nimport type { IDataEngine, Logger } from '@objectstack/spec/contracts';\nimport type { ModelRegistry, CostEstimate } from './model-registry.js';\n\n/** Object name used for persistence. */\nconst TRACE_OBJECT = 'ai_traces';\n\n/**\n * The operation that produced a trace.\n */\nexport type TraceOperation =\n | 'chat'\n | 'complete'\n | 'stream_chat'\n | 'chat_with_tools'\n | 'generate_object'\n | 'embed';\n\n/**\n * Data captured for every LLM invocation.\n *\n * Token counts default to 0 when the adapter does not report usage.\n * Cost fields are populated only when a {@link ModelRegistry} can resolve\n * pricing for the reported model.\n */\nexport interface TraceEvent {\n operation: TraceOperation;\n adapter: string;\n model?: string;\n agentId?: string;\n conversationId?: string;\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n latencyMs: number;\n status: 'success' | 'error';\n error?: string;\n cost?: CostEstimate;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * TraceRecorder — Records {@link TraceEvent}s.\n *\n * Implementations are expected to be non-throwing — a tracing failure must\n * never crash an AI call. The default {@link ObjectQLTraceRecorder} swallows\n * errors and logs at `warn`.\n */\nexport interface TraceRecorder {\n record(event: TraceEvent): Promise<void> | void;\n}\n\n/** Discard all traces. Default when no data engine is wired. */\nexport class NullTraceRecorder implements TraceRecorder {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n record(_event: TraceEvent): void {\n // intentional no-op\n }\n}\n\n/**\n * ObjectQLTraceRecorder — Persists traces via {@link IDataEngine}.\n *\n * Writes one row per call to the `ai_traces` object. Failures are logged\n * but never propagated.\n *\n * @example\n * ```ts\n * const recorder = new ObjectQLTraceRecorder(dataEngine, { logger });\n * ```\n */\nexport class ObjectQLTraceRecorder implements TraceRecorder {\n private readonly engine: IDataEngine;\n private readonly logger?: Logger;\n\n constructor(engine: IDataEngine, options: { logger?: Logger } = {}) {\n this.engine = engine;\n this.logger = options.logger;\n }\n\n async record(event: TraceEvent): Promise<void> {\n const row = {\n id: `trace_${randomUUID()}`,\n conversation_id: event.conversationId ?? null,\n agent_id: event.agentId ?? null,\n operation: event.operation,\n model: event.model ?? null,\n adapter: event.adapter,\n prompt_tokens: event.promptTokens,\n completion_tokens: event.completionTokens,\n total_tokens: event.totalTokens,\n input_cost: event.cost?.inputCost ?? null,\n output_cost: event.cost?.outputCost ?? null,\n total_cost: event.cost?.totalCost ?? null,\n currency: event.cost?.currency ?? null,\n latency_ms: event.latencyMs,\n status: event.status,\n error: event.error ?? null,\n metadata: event.metadata ? JSON.stringify(event.metadata) : null,\n created_at: new Date().toISOString(),\n };\n\n try {\n await this.engine.insert(TRACE_OBJECT, row);\n } catch (err) {\n this.logger?.warn('[AI] Failed to record trace (non-fatal)',\n err instanceof Error ? { error: err.message } : { error: String(err) });\n }\n }\n}\n\n/**\n * Helper: build a {@link TraceEvent} from a measured call.\n *\n * Resolves cost via the optional {@link ModelRegistry} when the model is\n * reported and pricing is available.\n */\nexport function buildTraceEvent(input: {\n operation: TraceOperation;\n adapter: string;\n model?: string;\n agentId?: string;\n conversationId?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n latencyMs: number;\n status: 'success' | 'error';\n error?: string;\n registry?: ModelRegistry;\n metadata?: Record<string, unknown>;\n}): TraceEvent {\n const usage = input.usage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n const cost = input.model && input.registry\n ? input.registry.estimateCost(input.model, usage)\n : undefined;\n return {\n operation: input.operation,\n adapter: input.adapter,\n model: input.model,\n agentId: input.agentId,\n conversationId: input.conversationId,\n promptTokens: usage.promptTokens,\n completionTokens: usage.completionTokens,\n totalTokens: usage.totalTokens,\n latencyMs: input.latencyMs,\n status: input.status,\n error: input.error,\n cost,\n metadata: input.metadata,\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/**\n * Encode data using Vercel AI SDK Data Stream Protocol prefixes.\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n */\nfunction dataStreamLine(prefix: string, data: object): string {\n return `${prefix}:${JSON.stringify(data)}\\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 // Handle reasoning/thinking streams (DeepSeek R1, o1-style models)\n // Use 'g:' prefix for reasoning content per Vercel AI SDK protocol\n case 'reasoning-start':\n return dataStreamLine('g', { text: '' });\n\n case 'reasoning-delta':\n return dataStreamLine('g', { text: part.text });\n\n case 'reasoning-end':\n return ''; // No specific end marker needed for reasoning\n\n // finish-step and finish are handled by the generator, not here\n default:\n // Pass through any unknown event types that might be custom\n // (e.g., step-start, step-finish from custom providers)\n if ((part as any).type?.startsWith('step-')) {\n return sse(part as any);\n }\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 let errorMessage: string | undefined;\n\n try {\n for await (const part of events) {\n // Surface error parts emitted by the underlying provider stream.\n if ((part as { type: string }).type === 'error') {\n const errPart = part as unknown as { error?: unknown };\n const raw = errPart.error;\n errorMessage =\n (raw && typeof raw === 'object' && 'message' in raw\n ? String((raw as { message: unknown }).message)\n : typeof raw === 'string'\n ? raw\n : 'Unknown provider error');\n finishReason = 'error';\n break;\n }\n\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 } catch (err) {\n // Upstream provider threw (auth failure, network error, etc.). Without\n // this catch the SSE response would hang half-open and the client would\n // never leave its \"streaming\" state.\n errorMessage = err instanceof Error ? err.message : String(err);\n finishReason = 'error';\n }\n\n // Close text if still open (safety)\n if (textOpen) {\n yield sse({ type: 'text-end', id: '0' });\n }\n\n // If we recorded an error, emit it as a UI Message Stream `error` part so\n // the client can display it instead of spinning forever.\n if (errorMessage) {\n yield sse({ type: 'error', errorText: errorMessage });\n }\n\n // Postamble — always emit so the client transitions out of \"streaming\".\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 { ModelMessage } from '@objectstack/spec/contracts';\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 *\n * Shared between the general chat routes and agent chat routes.\n */\nexport function 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 message content/parts format (role-agnostic).\n *\n * Returns `null` when the content shape is valid, or an error string\n * describing the first violation found.\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 * - Null/undefined `content` for assistant messages (when `allowEmpty` is true)\n */\nexport function validateMessageContent(\n msg: Record<string, unknown>,\n opts?: { allowEmptyContent?: boolean },\n): string | null {\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 // Allow empty content for certain roles (e.g. assistant tool-call messages)\n if ((content === null || content === undefined) && opts?.allowEmptyContent) {\n return null;\n }\n\n return 'message.content must be a string, an array, or include parts';\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';\nimport { normalizeMessage, validateMessageContent } from './message-utils.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 * 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\n // Assistant / tool messages may legitimately have null or missing content\n const allowEmpty = msg.role === 'assistant' || msg.role === 'tool';\n return validateMessageContent(msg, { allowEmptyContent: allowEmpty });\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: 'GET',\n path: '/api/v1/ai/conversations/:id',\n description: 'Get a conversation with its full message history',\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 try {\n const conversation = await conversationService.get(id);\n if (!conversation) {\n return { status: 404, body: { error: `Conversation \"${id}\" not found` } };\n }\n if (req.user?.userId && conversation.userId && conversation.userId !== req.user.userId) {\n return { status: 403, body: { error: 'You do not have access to this conversation' } };\n }\n return { status: 200, body: conversation };\n } catch (err) {\n logger.error('[AI Route] GET /conversations/:id 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';\nimport { normalizeMessage, validateMessageContent } from './message-utils.js';\nimport { encodeVercelDataStream } from '../stream/vercel-stream-encoder.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\n // Assistant messages may legitimately have empty content (e.g. tool-call-only)\n const allowEmpty = msg.role === 'assistant';\n return validateMessageContent(msg, { allowEmptyContent: allowEmpty });\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 // Dual-mode endpoint matching the general chat route 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/agents/:agentName/chat',\n description: 'Chat with a specific AI agent (supports Vercel AI Data Stream Protocol)',\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 body = (req.body ?? {}) as Record<string, unknown>;\n const {\n messages: rawMessages,\n context: chatContext,\n options: extraOptions,\n } = 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 // Resolve active skills for this agent in the current context\n const activeSkills = await agentRuntime.resolveActiveSkills(agent, chatContext);\n\n // Build system messages from agent instructions + UI context + skills\n const systemMessages = agentRuntime.buildSystemMessages(agent, chatContext, activeSkills);\n\n // Resolve agent model/tools + skill tools → request options\n const agentOptions = agentRuntime.buildRequestOptions(\n agent,\n aiService.toolRegistry.getAll(),\n activeSkills,\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.map(m => normalizeMessage(m as Record<string, unknown>)),\n ];\n\n const chatWithToolsOptions = {\n ...mergedOptions,\n maxIterations: agent.planning?.maxIterations,\n // Forward authenticated actor → built-in data tools enforce\n // ObjectQL RLS, action tools attribute audit to the user.\n toolExecutionContext: req.user\n ? {\n actor: {\n id: req.user.userId,\n name: req.user.displayName,\n roles: req.user.roles,\n permissions: req.user.permissions,\n },\n conversationId:\n typeof body.conversationId === 'string' ? body.conversationId : undefined,\n environmentId:\n typeof chatContext?.environmentId === 'string'\n ? chatContext.environmentId\n : undefined,\n }\n : undefined,\n };\n\n // ── Choose response mode ─────────────────────────────\n const wantStream = body.stream !== false;\n\n if (wantStream) {\n // Vercel Data Stream Protocol (SSE) — matches general chat behaviour\n if (!aiService.streamChatWithTools) {\n return { status: 501, body: { error: 'Streaming is not supported by the configured AI service' } };\n }\n const events = aiService.streamChatWithTools(fullMessages, chatWithToolsOptions);\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 }\n\n // JSON response (non-streaming / legacy)\n const result = await aiService.chatWithTools(fullMessages, chatWithToolsOptions);\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 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 { SkillRegistry } from '../skill-registry.js';\nimport type { RouteDefinition } from './ai-routes.js';\nimport { normalizeMessage, validateMessageContent } from './message-utils.js';\nimport { encodeVercelDataStream } from '../stream/vercel-stream-encoder.js';\n\nconst ALLOWED_ROLES = new Set<string>(['user', 'assistant']);\n\nfunction validateAssistantMessage(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_ROLES.has(msg.role)) {\n return `message.role must be one of ${[...ALLOWED_ROLES].map(r => `\"${r}\"`).join(', ')} for assistant chat`;\n }\n const allowEmpty = msg.role === 'assistant';\n return validateMessageContent(msg, { allowEmptyContent: allowEmpty });\n}\n\nfunction parseContext(raw: unknown): AgentChatContext {\n if (typeof raw !== 'object' || raw === null) return {};\n const obj = raw as Record<string, unknown>;\n const ctx: AgentChatContext = {};\n for (const key of Object.keys(obj)) {\n ctx[key] = obj[key];\n }\n return ctx;\n}\n\n/**\n * Build ambient assistant routes — the \"single chat entry\" pattern\n * inspired by Claude Code, Salesforce Agentforce, and ServiceNow Now\n * Assist.\n *\n * Unlike `/api/v1/ai/agents/:name/chat`, these endpoints do not require\n * the caller to pre-select an agent. The default agent for the active\n * application is resolved automatically from metadata, skills are\n * filtered by the runtime context, and the LLM decides which tool to\n * invoke.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | GET | /api/v1/ai/assistant | Resolve the active assistant + skills for the given context |\n * | GET | /api/v1/ai/assistant/skills | List active skills (for slash-command palettes) |\n * | POST | /api/v1/ai/assistant/chat | Ambient chat against the resolved default agent |\n */\nexport function buildAssistantRoutes(\n aiService: AIService,\n agentRuntime: AgentRuntime,\n skillRegistry: SkillRegistry,\n logger: Logger,\n): RouteDefinition[] {\n return [\n // ── Resolve current assistant + skill set ──────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/assistant',\n description: 'Resolve the default AI assistant and active skills for a given context',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n try {\n const context = parseContextFromQuery(req.query);\n // Optional explicit agent override (e.g. Studio passes\n // `?agent=metadata_assistant`). Falls back to the standard\n // resolution chain (app.defaultAgent → first active).\n const explicitAgentName = typeof req.query?.agent === 'string' ? req.query.agent : undefined;\n const agent = explicitAgentName\n ? await agentRuntime.loadAgent(explicitAgentName)\n : await agentRuntime.resolveDefaultAgent(context);\n if (!agent) {\n return {\n status: 200,\n body: { agent: null, skills: [] },\n };\n }\n const skills = await agentRuntime.resolveActiveSkills(agent, context);\n return {\n status: 200,\n body: {\n agent: {\n name: agent.name,\n label: agent.label,\n role: agent.role,\n avatar: agent.avatar,\n instructions: agent.instructions,\n },\n skills: skills.map((s) => skillRegistry.toSummary(s)),\n context,\n },\n };\n } catch (err) {\n logger.error('[AI Route] /assistant error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── List active skills (slash-command palette) ─────────────\n {\n method: 'GET',\n path: '/api/v1/ai/assistant/skills',\n description: 'List active AI skills for a given context (used by slash-command palettes)',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n try {\n const context = parseContextFromQuery(req.query);\n // Optional: restrict by query param `agent` to scope to one agent's skill set\n const agentName = typeof req.query?.agent === 'string' ? req.query.agent : undefined;\n let restrictTo: readonly string[] | undefined;\n if (agentName) {\n const agent = await agentRuntime.loadAgent(agentName);\n if (agent?.skills) restrictTo = agent.skills;\n }\n const skills = await skillRegistry.listActiveSkills(context, restrictTo);\n return {\n status: 200,\n body: { skills: skills.map((s) => skillRegistry.toSummary(s)) },\n };\n } catch (err) {\n logger.error('[AI Route] /assistant/skills error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Ambient chat (the \"single entry\" Claude-Code pattern) ──\n {\n method: 'POST',\n path: '/api/v1/ai/assistant/chat',\n description: 'Ambient AI chat — auto-resolves agent and skills from context (supports Vercel Data Stream Protocol)',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n const body = (req.body ?? {}) as Record<string, unknown>;\n const {\n messages: rawMessages,\n context: rawContext,\n options: extraOptions,\n agent: explicitAgentName,\n skill: explicitSkillName,\n } = body as {\n messages?: unknown[];\n context?: unknown;\n options?: Record<string, unknown>;\n agent?: string;\n skill?: string;\n };\n\n if (!Array.isArray(rawMessages) || rawMessages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n for (const msg of rawMessages) {\n const err = validateAssistantMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n const context = parseContext(rawContext);\n\n // Resolve agent: explicit > defaultAgent(app) > first active\n const agent = explicitAgentName\n ? await agentRuntime.loadAgent(explicitAgentName)\n : await agentRuntime.resolveDefaultAgent(context);\n\n if (!agent) {\n return {\n status: 404,\n body: { error: 'No active assistant available — register at least one agent or set defaultAgent on the app metadata' },\n };\n }\n if (agent.active === false) {\n return { status: 403, body: { error: `Agent \"${agent.name}\" is not active` } };\n }\n\n try {\n // Resolve active skills. When the caller pinned a slash command via\n // `skill: '<name>'` we restrict to that single skill so the LLM is\n // forced to use it (Claude-Code `/skill-name` semantics).\n let activeSkills = await agentRuntime.resolveActiveSkills(agent, context);\n if (explicitSkillName) {\n activeSkills = activeSkills.filter((s) => s.name === explicitSkillName);\n if (activeSkills.length === 0) {\n const direct = await skillRegistry.loadSkill(explicitSkillName);\n if (direct && direct.active !== false) activeSkills = [direct];\n }\n }\n\n const systemMessages = agentRuntime.buildSystemMessages(agent, context, activeSkills);\n const agentOptions = agentRuntime.buildRequestOptions(\n agent,\n aiService.toolRegistry.getAll(),\n activeSkills,\n );\n\n // Whitelist only safe caller overrides\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)) safeOverrides[key] = extraOptions[key];\n }\n }\n const mergedOptions = { ...agentOptions, ...safeOverrides };\n\n const fullMessages: ModelMessage[] = [\n ...systemMessages,\n ...rawMessages.map((m) => normalizeMessage(m as Record<string, unknown>)),\n ];\n\n const chatWithToolsOptions = {\n ...mergedOptions,\n maxIterations: agent.planning?.maxIterations,\n // Forward the authenticated actor into every tool the loop\n // invokes — built-in data tools promote this into the\n // ObjectQL execution context so row-level security scopes\n // the LLM to whatever the human user can already see/do.\n toolExecutionContext: req.user\n ? {\n actor: {\n id: req.user.userId,\n name: req.user.displayName,\n roles: req.user.roles,\n permissions: req.user.permissions,\n },\n conversationId:\n typeof body.conversationId === 'string' ? body.conversationId : undefined,\n environmentId:\n typeof context.environmentId === 'string' ? context.environmentId : undefined,\n }\n : undefined,\n };\n\n const wantStream = body.stream !== false;\n\n if (wantStream) {\n if (!aiService.streamChatWithTools) {\n return { status: 501, body: { error: 'Streaming is not supported by the configured AI service' } };\n }\n const events = aiService.streamChatWithTools(fullMessages, chatWithToolsOptions);\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 'x-objectstack-agent': agent.name,\n 'x-objectstack-skills': activeSkills.map((s) => s.name).join(','),\n },\n events: encodeVercelDataStream(events),\n };\n }\n\n const result = await aiService.chatWithTools(fullMessages, chatWithToolsOptions);\n\n return {\n status: 200,\n body: {\n ...((result as object) ?? {}),\n _agent: agent.name,\n _skills: activeSkills.map((s) => s.name),\n },\n };\n } catch (err) {\n logger.error(\n '[AI Route] /assistant/chat error',\n err instanceof Error ? err : undefined,\n );\n // Surface a brief upstream message so the client UI can render it\n // instead of an opaque \"Internal AI service error\". Stack traces\n // stay in the logger.\n const upstreamMsg = err instanceof Error ? err.message : String(err);\n return {\n status: 500,\n body: { error: 'Internal AI service error', detail: upstreamMsg },\n };\n }\n },\n },\n ];\n}\n\n/**\n * Parse the runtime context from query-string parameters.\n *\n * Accepts the same field set as {@link AgentChatContext}:\n * `appName`, `objectName`, `recordId`, `viewName`, `channel`, `userRole`.\n * Unknown fields are passed through verbatim so caller-defined trigger\n * conditions remain extensible.\n */\nfunction parseContextFromQuery(query: Record<string, string> | undefined): AgentChatContext {\n if (!query) return {};\n const ctx: AgentChatContext = {};\n for (const [key, value] of Object.entries(query)) {\n if (value == null) continue;\n ctx[key] = value;\n }\n return ctx;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Logger } from '@objectstack/spec/contracts';\nimport type { AIService } from '../ai-service.js';\nimport type { RouteDefinition } from './ai-routes.js';\n\n/**\n * Extract string value from tool execution result output.\n */\nfunction extractOutputValue(output: any): string {\n if (!output) return '';\n if (typeof output === 'string') return output;\n if (typeof output === 'object' && 'value' in output) {\n return String(output.value ?? '');\n }\n return JSON.stringify(output);\n}\n\n/**\n * Build tool-specific REST routes.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | GET | /api/v1/ai/tools | List all registered tools |\n * | POST | /api/v1/ai/tools/:toolName/execute | Execute a tool with parameters |\n */\nexport function buildToolRoutes(\n aiService: AIService,\n logger: Logger,\n): RouteDefinition[] {\n return [\n // ── List registered tools ──────────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/tools',\n description: 'List all registered AI tools',\n auth: true,\n permissions: ['ai:tools'],\n handler: async () => {\n try {\n const tools = aiService.toolRegistry.getAll();\n return {\n status: 200,\n body: {\n tools: tools.map(t => ({\n name: t.name,\n description: t.description,\n category: (t as any).category,\n }))\n }\n };\n } catch (err) {\n logger.error(\n '[AI Route] /tools list error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Execute a tool ──────────────────────────────────────────────\n //\n // Executes a tool with the provided parameters.\n // This is intended for testing/playground use.\n //\n {\n method: 'POST',\n path: '/api/v1/ai/tools/:toolName/execute',\n description: 'Execute a tool with parameters (playground/testing)',\n auth: true,\n permissions: ['ai:tools', 'ai:execute'],\n handler: async (req) => {\n const toolName = req.params?.toolName;\n if (!toolName) {\n return { status: 400, body: { error: 'toolName parameter is required' } };\n }\n\n // Parse request body\n const body = (req.body ?? {}) as Record<string, unknown>;\n const { parameters } = body as {\n parameters?: Record<string, unknown>;\n };\n\n if (!parameters || typeof parameters !== 'object') {\n return { status: 400, body: { error: 'parameters object is required' } };\n }\n\n try {\n // Check if tool exists\n if (!aiService.toolRegistry.has(toolName)) {\n return { status: 404, body: { error: `Tool \"${toolName}\" not found` } };\n }\n\n // Execute the tool using ToolRegistry's execute method\n const startTime = Date.now();\n\n const toolCallPart = {\n type: 'tool-call' as const,\n toolCallId: `playground-${Date.now()}`,\n toolName,\n input: parameters,\n };\n\n const result = await aiService.toolRegistry.execute(toolCallPart);\n const duration = Date.now() - startTime;\n\n // Check if execution resulted in an error\n if (result.isError) {\n const errorMsg = extractOutputValue(result.output);\n logger.error(\n `[AI Route] Tool execution error: ${toolName}`,\n new Error(errorMsg),\n );\n return {\n status: 500,\n body: {\n error: errorMsg,\n duration,\n },\n };\n }\n\n return {\n status: 200,\n body: {\n result: extractOutputValue(result.output),\n duration,\n toolName,\n },\n };\n } catch (err) {\n logger.error(\n '[AI Route] /tools/:toolName/execute 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 type { Logger } from '@objectstack/spec/contracts';\nimport type { IAIService } from '@objectstack/spec/contracts';\nimport type { RouteDefinition } from './ai-routes.js';\n\n/**\n * Build pending-action (HITL approval) REST routes.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | GET | /api/v1/ai/pending-actions | List pending actions (filter by status) |\n * | GET | /api/v1/ai/pending-actions/:id | Get a single pending action |\n * | POST | /api/v1/ai/pending-actions/:id/approve | Approve & execute |\n * | POST | /api/v1/ai/pending-actions/:id/reject | Reject with optional reason |\n *\n * Auth: requires `ai:approve` permission for approve/reject. Listing/reads\n * require the lighter `ai:read` permission so operators can monitor the\n * queue without execution rights.\n */\nexport function buildPendingActionRoutes(\n aiService: IAIService,\n logger: Logger,\n): RouteDefinition[] {\n // Guard: if the AI service doesn't implement HITL methods (e.g. older\n // build or no dataEngine wired), surface a clear 501 instead of NPE.\n const supported =\n typeof aiService.listPendingActions === 'function' &&\n typeof aiService.approvePendingAction === 'function' &&\n typeof aiService.rejectPendingAction === 'function';\n\n if (!supported) {\n logger.warn(\n '[AI] HITL pending-action methods not implemented on AI service — routes return 501.',\n );\n }\n\n const notImpl = () => ({\n status: 501,\n body: { error: 'Pending-action queue not available (dataEngine not wired)' },\n });\n\n return [\n // ── List pending actions ───────────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/pending-actions',\n description: 'List pending actions in the HITL approval queue',\n auth: true,\n permissions: ['ai:read'],\n handler: async (req) => {\n if (!supported) return notImpl();\n try {\n const query = (req.query ?? {}) as Record<string, unknown>;\n const status = typeof query.status === 'string' ? (query.status as any) : undefined;\n const conversationId =\n typeof query.conversationId === 'string' ? query.conversationId : undefined;\n const limitRaw = query.limit;\n const limit = typeof limitRaw === 'string' ? Number(limitRaw) : undefined;\n const rows = await aiService.listPendingActions!({\n status,\n conversationId,\n limit: Number.isFinite(limit) ? limit : undefined,\n });\n return { status: 200, body: { items: rows, total: rows.length } };\n } catch (err) {\n logger.error(\n '[AI Route] /pending-actions list error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Failed to list pending actions' } };\n }\n },\n },\n\n // ── Get a single pending action ────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/pending-actions/:id',\n description: 'Get a single pending action by id',\n auth: true,\n permissions: ['ai:read'],\n handler: async (req) => {\n if (!supported) return notImpl();\n const id = req.params?.id;\n if (!id) return { status: 400, body: { error: 'id is required' } };\n try {\n const rows = await aiService.listPendingActions!({});\n const found = rows.find(r => r.id === id);\n if (!found) return { status: 404, body: { error: `Pending action ${id} not found` } };\n return { status: 200, body: found };\n } catch (err) {\n logger.error(\n '[AI Route] /pending-actions/:id error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Failed to load pending action' } };\n }\n },\n },\n\n // ── Approve & execute ──────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/pending-actions/:id/approve',\n description: 'Approve a pending action and execute it immediately',\n auth: true,\n permissions: ['ai:approve'],\n handler: async (req) => {\n if (!supported) return notImpl();\n const id = req.params?.id;\n if (!id) return { status: 400, body: { error: 'id is required' } };\n const actorId = req.user?.id ?? 'system';\n try {\n const outcome = await aiService.approvePendingAction!(id, actorId);\n // outcome.status is 'executed' on success, 'failed' on dispatch error\n const httpStatus = outcome.status === 'executed' ? 200 : 500;\n return { status: httpStatus, body: outcome };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error('[AI Route] /pending-actions/:id/approve error', err instanceof Error ? err : undefined);\n // 409 = state conflict (already approved/rejected/etc.); 404 = missing\n if (/not found/i.test(msg)) return { status: 404, body: { error: msg } };\n if (/already|not pending|no dispatcher/i.test(msg)) {\n return { status: 409, body: { error: msg } };\n }\n return { status: 500, body: { error: msg } };\n }\n },\n },\n\n // ── Reject ─────────────────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/pending-actions/:id/reject',\n description: 'Reject a pending action (will not be executed)',\n auth: true,\n permissions: ['ai:approve'],\n handler: async (req) => {\n if (!supported) return notImpl();\n const id = req.params?.id;\n if (!id) return { status: 400, body: { error: 'id is required' } };\n const actorId = req.user?.id ?? 'system';\n const body = (req.body ?? {}) as Record<string, unknown>;\n const reason = typeof body.reason === 'string' ? body.reason : undefined;\n try {\n await aiService.rejectPendingAction!(id, actorId, reason);\n return { status: 200, body: { status: 'rejected', id } };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error('[AI Route] /pending-actions/:id/reject error', err instanceof Error ? err : undefined);\n if (/not found/i.test(msg)) return { status: 404, body: { error: msg } };\n if (/already|not pending/i.test(msg)) {\n return { status: 409, body: { error: msg } };\n }\n return { status: 500, body: { error: msg } };\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 name: 'ai_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',\n required: false,\n maxLength: 128,\n description: 'Associated AI agent (metadata name — agents live as JSON in sys_metadata, no lookup table)',\n }),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n required: false,\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 name: 'ai_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.lookup('ai_conversations', {\n label: 'Conversation',\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 { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * ai_traces — AI Call Trace Object\n *\n * Records every LLM call made through the {@link AIService} for observability,\n * cost attribution, and debugging.\n *\n * One row per `chat()` / `complete()` invocation (tool-call loops produce\n * multiple rows). Persisted via {@link ObjectQLTraceRecorder} when a data\n * engine is available; otherwise traces are no-op.\n *\n * @namespace ai\n */\nexport const AiTraceObject = ObjectSchema.create({\n name: 'ai_traces',\n label: 'AI Trace',\n pluralLabel: 'AI Traces',\n icon: 'activity',\n isSystem: true,\n description: 'Per-call LLM invocation trace with token usage and cost',\n\n fields: {\n id: Field.text({\n label: 'Trace ID',\n required: true,\n readonly: true,\n }),\n\n conversation_id: Field.lookup('ai_conversations', {\n label: 'Conversation',\n required: false,\n description: 'Parent conversation, if any',\n }),\n\n agent_id: Field.text({\n label: 'Agent',\n required: false,\n maxLength: 128,\n description: 'Agent metadata name that originated the call',\n }),\n\n operation: Field.select({\n label: 'Operation',\n required: true,\n options: [\n { label: 'Chat', value: 'chat' },\n { label: 'Complete', value: 'complete' },\n { label: 'Stream Chat', value: 'stream_chat' },\n { label: 'Chat With Tools', value: 'chat_with_tools' },\n { label: 'Generate Object', value: 'generate_object' },\n { label: 'Embed', value: 'embed' },\n ],\n }),\n\n model: Field.text({\n label: 'Model',\n required: false,\n maxLength: 128,\n description: 'Model identifier reported by the adapter',\n }),\n\n adapter: Field.text({\n label: 'Adapter',\n required: false,\n maxLength: 64,\n description: 'LLM adapter name (e.g. \"vercel\", \"memory\")',\n }),\n\n prompt_tokens: Field.number({\n label: 'Prompt Tokens',\n required: false,\n defaultValue: 0,\n }),\n\n completion_tokens: Field.number({\n label: 'Completion Tokens',\n required: false,\n defaultValue: 0,\n }),\n\n total_tokens: Field.number({\n label: 'Total Tokens',\n required: false,\n defaultValue: 0,\n }),\n\n input_cost: Field.number({\n label: 'Input Cost',\n required: false,\n description: 'Cost attributable to prompt tokens (currency in `currency` field)',\n }),\n\n output_cost: Field.number({\n label: 'Output Cost',\n required: false,\n description: 'Cost attributable to completion tokens',\n }),\n\n total_cost: Field.number({\n label: 'Total Cost',\n required: false,\n description: 'input_cost + output_cost',\n }),\n\n currency: Field.text({\n label: 'Currency',\n required: false,\n maxLength: 8,\n defaultValue: 'USD',\n }),\n\n latency_ms: Field.number({\n label: 'Latency (ms)',\n required: true,\n defaultValue: 0,\n description: 'Wall-clock duration of the LLM call',\n }),\n\n status: Field.select({\n label: 'Status',\n required: true,\n options: [\n { label: 'Success', value: 'success' },\n { label: 'Error', value: 'error' },\n ],\n }),\n\n error: Field.textarea({\n label: 'Error',\n required: false,\n description: 'Error message when status=error',\n }),\n\n metadata: Field.textarea({\n label: 'Metadata',\n required: false,\n description: 'JSON-serialized extra fields (request id, user id, …)',\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: ['agent_id'] },\n { fields: ['model'] },\n { fields: ['status'] },\n { fields: ['created_at'] },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list'],\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_pending_actions — Human-in-the-Loop queue for AI-initiated actions.\n *\n * When the agent picks a tool that maps to a dangerous declarative action\n * (delete, danger variant, or any action with `confirmText`), the tool\n * runtime does **not** dispatch immediately. Instead it persists a row\n * here and returns a `{ status: 'pending_approval', pendingActionId }`\n * envelope so the LLM can summarise the request. A human then approves\n * (or rejects) via Studio's pending-actions inbox, at which point the\n * service re-dispatches the action with full permissions.\n *\n * One row per proposed tool call. Lifecycle:\n * pending → approved → executed (happy path)\n * ↘ approved → failed (execution blew up)\n * ↘ rejected (human said no)\n *\n * @namespace ai\n */\nexport const AiPendingActionObject = ObjectSchema.create({\n name: 'ai_pending_actions',\n label: 'AI Pending Action',\n pluralLabel: 'AI Pending Actions',\n icon: 'shield-check',\n isSystem: true,\n description: 'Queue of AI-proposed action invocations awaiting human approval',\n\n fields: {\n id: Field.text({\n label: 'Request ID',\n required: true,\n readonly: true,\n }),\n\n conversation_id: Field.lookup('ai_conversations', {\n label: 'Conversation',\n required: false,\n description: 'Conversation that produced this proposal, if any',\n }),\n\n message_id: Field.lookup('ai_messages', {\n label: 'Message',\n required: false,\n description: 'Assistant message containing the proposed tool call',\n }),\n\n object_name: Field.text({\n label: 'Object',\n required: true,\n maxLength: 128,\n description: 'Target object name (e.g. \"task\")',\n }),\n\n action_name: Field.text({\n label: 'Action',\n required: true,\n maxLength: 128,\n description: 'Declarative action name (e.g. \"delete_task\")',\n }),\n\n tool_name: Field.text({\n label: 'Tool',\n required: true,\n maxLength: 128,\n description: 'AI tool name exposed to the LLM (e.g. \"action_delete_task\")',\n }),\n\n tool_input: Field.textarea({\n label: 'Tool Input',\n required: true,\n description: 'JSON-serialised tool arguments the LLM passed',\n }),\n\n status: Field.select({\n label: 'Status',\n required: true,\n defaultValue: 'pending',\n options: [\n { label: 'Pending Approval', value: 'pending' },\n { label: 'Approved (queued)', value: 'approved' },\n { label: 'Executed', value: 'executed' },\n { label: 'Failed', value: 'failed' },\n { label: 'Rejected', value: 'rejected' },\n ],\n }),\n\n result: Field.textarea({\n label: 'Execution Result',\n required: false,\n description: 'JSON-serialised result from the action when executed',\n }),\n\n error: Field.textarea({\n label: 'Error',\n required: false,\n description: 'Error message when status=failed',\n }),\n\n rejection_reason: Field.textarea({\n label: 'Rejection Reason',\n required: false,\n description: 'Why the reviewer rejected (shown back to the LLM)',\n }),\n\n proposed_by: Field.text({\n label: 'Proposed By',\n required: false,\n maxLength: 128,\n description: 'Principal id of the AI agent that proposed the action',\n }),\n\n decided_by: Field.text({\n label: 'Decided By',\n required: false,\n maxLength: 128,\n description: 'User id of the human who approved/rejected',\n }),\n\n proposed_at: Field.datetime({\n label: 'Proposed At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n decided_at: Field.datetime({\n label: 'Decided At',\n required: false,\n description: 'When approve/reject happened',\n }),\n },\n\n indexes: [\n { fields: ['status'] },\n { fields: ['conversation_id'] },\n { fields: ['object_name'] },\n { fields: ['proposed_at'] },\n ],\n\n actions: [\n {\n name: 'approve_pending_action',\n label: 'Approve',\n type: 'api',\n target: '/api/v1/ai/pending-actions/{recordId}/approve',\n method: 'POST',\n locations: ['list_item', 'record_header'],\n variant: 'primary',\n confirmText: 'Approve and execute this action now?',\n successMessage: 'Action approved and executed.',\n // The approval click is the operator's authorisation gesture —\n // the LLM must not be allowed to bypass HITL by approving itself.\n aiExposed: false,\n },\n {\n name: 'reject_pending_action',\n label: 'Reject',\n type: 'api',\n target: '/api/v1/ai/pending-actions/{recordId}/reject',\n method: 'POST',\n locations: ['list_item', 'record_header'],\n variant: 'danger',\n confirmText: 'Reject this pending action? It will not be executed.',\n successMessage: 'Action rejected.',\n aiExposed: false,\n },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineView } from '@objectstack/spec';\n\n/**\n * ai_traces — built-in Studio list view.\n *\n * Exposes per-call observability for every LLM invocation that flowed\n * through the `AIService`. Ships with the platform so users don't have\n * to author a view for an object they didn't create.\n *\n * - Default list: grid sorted by `created_at` desc, showing the columns an\n * operator usually wants at a glance (operation, model, latency, tokens,\n * cost, status).\n * - `errors` view: pre-filtered to status=\"error\" for triage.\n * - `by_model` view: grouped by model for cost / quality comparison.\n *\n * Registered via the AIService plugin's manifest payload — appears\n * automatically in Studio when AIService is loaded.\n */\nexport const AiTraceView = defineView({\n list: {\n type: 'grid',\n data: { provider: 'object', object: 'ai_traces' },\n columns: [\n { field: 'created_at', label: 'Time' },\n { field: 'operation' },\n { field: 'model' },\n { field: 'agent_id', label: 'Agent' },\n { field: 'latency_ms', label: 'Latency (ms)' },\n { field: 'total_tokens', label: 'Tokens' },\n { field: 'cost_total', label: 'Cost' },\n { field: 'status' },\n ],\n sort: [{ field: 'created_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n searchableFields: ['conversation_id', 'agent_id', 'model', 'error'],\n filterableFields: ['operation', 'model', 'status'],\n },\n listViews: {\n errors: {\n label: 'Errors',\n type: 'grid',\n data: { provider: 'object', object: 'ai_traces' },\n columns: [\n { field: 'created_at', label: 'Time' },\n { field: 'operation' },\n { field: 'model' },\n { field: 'latency_ms', label: 'Latency (ms)' },\n { field: 'error' },\n ],\n filter: [\n { field: 'status', operator: '=', value: 'error' },\n ],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n by_model: {\n label: 'By Model',\n type: 'grid',\n data: { provider: 'object', object: 'ai_traces' },\n columns: [\n { field: 'model' },\n { field: 'operation' },\n { field: 'latency_ms', label: 'Latency (ms)' },\n { field: 'total_tokens', label: 'Tokens' },\n { field: 'cost_total', label: 'Cost' },\n { field: 'status' },\n { field: 'created_at', label: 'Time' },\n ],\n grouping: { fields: [{ field: 'model' }] },\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineView } from '@objectstack/spec';\n\n/**\n * ai_pending_actions — built-in Studio inbox view.\n *\n * Surfaces the HITL approval queue: every action the LLM proposed that\n * was classified \"dangerous\" (confirmText, mode='delete', variant='danger')\n * and gated behind human approval. Operators triage from this list and\n * either Approve (re-runs the action immediately under the AI principal)\n * or Reject (closes the row without execution).\n *\n * ## UI shape\n *\n * Studio renders three things from this definition:\n *\n * 1. A **list view** with four named tabs — pending / executed / rejected /\n * failed — sorted reverse-chronologically. Each row is clickable.\n * 2. A **drawer detail view** (opened on row click) that shows the full\n * tool-call envelope, the LLM context (conversation + message links),\n * decision trail (proposed_at / decided_at relative timestamps), and\n * outcome (result / error / rejection_reason in collapsible sections).\n * 3. The two object-level actions (`approve_pending_action`,\n * `reject_pending_action`, declared on the object schema with\n * `locations: ['list_item', 'record_header']`) are surfaced as both\n * row-level buttons in the grid and primary buttons in the drawer\n * header, hitting the REST contract directly.\n *\n * The drawer is conditionally-actionable: Approve/Reject buttons are only\n * useful for `status='pending'` rows, but Studio's per-row action filtering\n * handles that via the underlying record state.\n *\n * Bundled with the platform so users don't need to author a view for\n * a system table. Appears automatically in Studio when AIService is\n * loaded with `enableActionApproval: true`.\n */\nexport const AiPendingActionView = defineView({\n list: {\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'proposed_at', label: 'Proposed', type: 'datetime-relative', width: 140 },\n { field: 'status', width: 130 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'proposed_by', label: 'Proposed by', width: 160 },\n { field: 'decided_by', label: 'Decided by', width: 160 },\n { field: 'decided_at', label: 'Decided', type: 'datetime-relative', width: 140 },\n ],\n sort: [{ field: 'proposed_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n searchableFields: ['action_name', 'object_name', 'tool_name', 'proposed_by'],\n filterableFields: ['status', 'object_name', 'action_name'],\n rowActions: ['approve_pending_action', 'reject_pending_action'],\n // Click a row → open the detail drawer instead of navigating to a page.\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n rowColor: {\n field: 'status',\n mapping: {\n pending: 'amber',\n approved: 'blue',\n executed: 'green',\n failed: 'red',\n rejected: 'gray',\n },\n } as never,\n },\n\n form: {\n type: 'drawer',\n data: { provider: 'object', object: 'ai_pending_actions' },\n sections: [\n {\n label: 'Proposal',\n columns: 2,\n fields: [\n { field: 'status', readonly: true },\n { field: 'proposed_at', readonly: true, widget: 'datetime-relative' },\n { field: 'object_name', label: 'Target object', readonly: true },\n { field: 'action_name', label: 'Action', readonly: true },\n { field: 'tool_name', label: 'Tool exposed to LLM', readonly: true, colSpan: 2 },\n { field: 'proposed_by', label: 'Proposed by (AI agent)', readonly: true, colSpan: 2 },\n ],\n },\n {\n label: 'Tool input',\n collapsible: true,\n columns: 1,\n fields: [\n {\n field: 'tool_input',\n label: 'Arguments the LLM sent',\n readonly: true,\n widget: 'json',\n colSpan: 1,\n helpText: 'Pretty-printed JSON. Review carefully before approving — this is the exact payload that will be re-played against the handler.',\n },\n ],\n },\n {\n label: 'Conversation context',\n collapsible: true,\n collapsed: true,\n columns: 2,\n fields: [\n // Both are lookups — Studio renders them as links to the related\n // ai_conversations / ai_messages record so operators can jump to\n // the full transcript for context.\n { field: 'conversation_id', label: 'Conversation', readonly: true },\n { field: 'message_id', label: 'Assistant message', readonly: true },\n ],\n },\n {\n label: 'Decision',\n collapsible: true,\n // Only meaningful once the row has been actioned; left collapsed\n // by default for pending rows so the eye lands on the proposal.\n collapsed: true,\n columns: 2,\n fields: [\n { field: 'decided_by', label: 'Decided by', readonly: true },\n { field: 'decided_at', label: 'Decided', readonly: true, widget: 'datetime-relative' },\n {\n field: 'rejection_reason',\n label: 'Rejection reason',\n readonly: true,\n colSpan: 2,\n visibleOn: 'record.status == \"rejected\"',\n },\n {\n field: 'result',\n label: 'Execution result',\n readonly: true,\n widget: 'json',\n colSpan: 2,\n visibleOn: 'record.status == \"executed\"',\n },\n {\n field: 'error',\n label: 'Error',\n readonly: true,\n colSpan: 2,\n visibleOn: 'record.status == \"failed\"',\n },\n ],\n },\n ],\n },\n\n formViews: {\n detail: {\n type: 'drawer',\n data: { provider: 'object', object: 'ai_pending_actions' },\n // Mirror of the default form. Named separately so the list's\n // `navigation.view: 'detail'` resolves explicitly — Studio falls back\n // to `form` if a named view isn't registered, but being explicit\n // makes the wiring legible to readers of the metadata.\n sections: [\n {\n label: 'Proposal',\n columns: 2,\n fields: [\n { field: 'status', readonly: true },\n { field: 'proposed_at', readonly: true, widget: 'datetime-relative' },\n { field: 'object_name', label: 'Target object', readonly: true },\n { field: 'action_name', label: 'Action', readonly: true },\n { field: 'tool_name', label: 'Tool exposed to LLM', readonly: true, colSpan: 2 },\n { field: 'proposed_by', label: 'Proposed by (AI agent)', readonly: true, colSpan: 2 },\n ],\n },\n {\n label: 'Tool input',\n collapsible: true,\n columns: 1,\n fields: [\n { field: 'tool_input', label: 'Arguments the LLM sent', readonly: true, widget: 'json' },\n ],\n },\n {\n label: 'Conversation context',\n collapsible: true,\n collapsed: true,\n columns: 2,\n fields: [\n { field: 'conversation_id', label: 'Conversation', readonly: true },\n { field: 'message_id', label: 'Assistant message', readonly: true },\n ],\n },\n {\n label: 'Decision',\n collapsible: true,\n collapsed: true,\n columns: 2,\n fields: [\n { field: 'decided_by', label: 'Decided by', readonly: true },\n { field: 'decided_at', label: 'Decided', readonly: true, widget: 'datetime-relative' },\n { field: 'rejection_reason', label: 'Rejection reason', readonly: true, colSpan: 2, visibleOn: 'record.status == \"rejected\"' },\n { field: 'result', label: 'Execution result', readonly: true, widget: 'json', colSpan: 2, visibleOn: 'record.status == \"executed\"' },\n { field: 'error', label: 'Error', readonly: true, colSpan: 2, visibleOn: 'record.status == \"failed\"' },\n ],\n },\n ],\n },\n },\n\n listViews: {\n pending: {\n label: 'Pending',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'proposed_at', label: 'Proposed', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'proposed_by', label: 'Proposed by', width: 160 },\n { field: 'tool_name', label: 'Tool', width: 200 },\n ],\n filter: [{ field: 'status', operator: '=', value: 'pending' }],\n sort: [{ field: 'proposed_at', order: 'desc' }],\n rowActions: ['approve_pending_action', 'reject_pending_action'],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n },\n executed: {\n label: 'Executed',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'decided_at', label: 'Approved', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'decided_by', label: 'Approved by', width: 160 },\n { field: 'proposed_by', label: 'Proposed by', width: 160 },\n ],\n filter: [{ field: 'status', operator: '=', value: 'executed' }],\n sort: [{ field: 'decided_at', order: 'desc' }],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n },\n rejected: {\n label: 'Rejected',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'decided_at', label: 'Rejected', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'decided_by', label: 'Rejected by', width: 160 },\n { field: 'rejection_reason', label: 'Reason', wrap: true },\n ],\n filter: [{ field: 'status', operator: '=', value: 'rejected' }],\n sort: [{ field: 'decided_at', order: 'desc' }],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n },\n failed: {\n label: 'Failed',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'decided_at', label: 'When', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'error', wrap: true },\n ],\n filter: [{ field: 'status', operator: '=', value: 'failed' }],\n sort: [{ field: 'decided_at', order: 'desc' }],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\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, IAutomationService, IDataEngine, IMetadataService, LLMAdapter } from '@objectstack/spec/contracts';\nimport type * as AI from '@objectstack/spec/ai';\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 { buildAssistantRoutes } from './routes/assistant-routes.js';\nimport { buildToolRoutes } from './routes/tool-routes.js';\nimport { buildPendingActionRoutes } from './routes/pending-action-routes.js';\nimport { ObjectQLConversationService } from './conversation/objectql-conversation-service.js';\nimport { AiConversationObject, AiMessageObject, AiPendingActionObject, AiTraceObject } from './objects/index.js';\nimport { AiTraceView, AiPendingActionView } from './views/index.js';\nimport { registerDataTools } from './tools/data-tools.js';\nimport { registerMetadataTools } from './tools/metadata-tools.js';\nimport { registerQueryDataTool } from './tools/query-data.tool.js';\nimport { registerActionsAsTools } from './tools/action-tools.js';\nimport { AgentRuntime } from './agent-runtime.js';\nimport { SkillRegistry } from './skill-registry.js';\nimport { DATA_CHAT_AGENT, METADATA_ASSISTANT_AGENT } from './agents/index.js';\nimport { DATA_EXPLORER_SKILL, METADATA_AUTHORING_SKILL, ACTIONS_EXECUTOR_SKILL } from './skills/index.js';\nimport { VercelLLMAdapter } from './adapters/vercel-adapter.js';\nimport { MemoryLLMAdapter } from './adapters/memory-adapter.js';\nimport { ModelRegistry } from './model-registry.js';\nimport { ObjectQLTraceRecorder, type TraceRecorder } from './trace-recorder.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 * Models to register in the runtime {@link ModelRegistry}.\n *\n * Used for default-model resolution and cost attribution in traces.\n * If omitted, the registry starts empty and trace `cost_*` fields are null.\n */\n models?: AI.ModelConfig[];\n /** Default model id (must appear in `models`). */\n defaultModelId?: string;\n /**\n * Explicit trace recorder override. When set, auto-detection\n * of {@link ObjectQLTraceRecorder} is skipped.\n *\n * Set to `null` to disable tracing entirely.\n */\n /**\n * Explicit trace recorder override. When set, auto-detection\n * of {@link ObjectQLTraceRecorder} is skipped.\n *\n * Set to `null` to disable tracing entirely.\n */\n traceRecorder?: TraceRecorder | null;\n /**\n * Base URL prepended to relative `target` paths for `type:'api'`\n * actions invoked by the AI tool runtime. When unset, falls back to\n * `process.env.OS_AI_ACTION_API_BASE_URL`. If neither is set, api\n * actions are skipped at registration with a clear reason.\n */\n apiActionBaseUrl?: string;\n /**\n * Extra HTTP headers (e.g. `{ Authorization: 'Bearer ...' }`) applied\n * to every `type:'api'` action dispatch. Useful for forwarding the\n * caller's session token so server-side authorization still applies.\n */\n apiActionHeaders?: Record<string, string>;\n /**\n * Opt into Human-In-The-Loop approval for dangerous actions exposed\n * as AI tools. When `true`, actions with `confirmText`, `mode:'delete'`,\n * or `variant:'danger'` are still registered as tools — but invoking\n * them enqueues an `ai_pending_actions` row and returns\n * `{ status: 'pending_approval' }` instead of running. A human\n * operator approves via Studio's pending-actions inbox to execute.\n *\n * Defaults to `false` (safer: dangerous actions stay invisible to LLM\n * until an operator explicitly enables this routing).\n */\n enableActionApproval?: boolean;\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 provider = mod[factory] ?? mod.default;\n if (typeof provider === 'function') {\n const modelId = process.env.AI_MODEL ?? defaultModel;\n // For OpenAI, prefer the Chat Completions API (`openai.chat(...)`)\n // over the new Responses API. The Responses endpoint\n // (`/v1/responses`) is not supported by common reverse proxies\n // such as the Vercel AI Gateway, Cloudflare AI Gateway, or\n // Azure-style OpenAI deployments — calling it returns 403\n // Forbidden and the chat completion silently fails. The Chat\n // Completions endpoint (`/v1/chat/completions`) is the\n // industry-standard contract every gateway supports.\n const useChatApi = factory === 'openai' && typeof (provider as any).chat === 'function';\n const model = useChatApi\n ? (provider as any).chat(modelId)\n : provider(modelId);\n const adapter = new VercelLLMAdapter({ model });\n const apiSuffix = useChatApi ? ' [chat-completions]' : '';\n return { adapter, description: `${displayName} (model: ${modelId})${apiSuffix}` };\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 // Model registry — empty by default; populated from plugin options.\n const modelRegistry = new ModelRegistry({\n models: this.options.models,\n defaultModelId: this.options.defaultModelId,\n });\n if (modelRegistry.size > 0) {\n ctx.logger.info(`[AI] ModelRegistry initialised with ${modelRegistry.size} model(s)`);\n }\n\n // Trace recorder — explicit > auto-detect IDataEngine > NullTraceRecorder\n let traceRecorder: TraceRecorder | undefined;\n let dataEngine: IDataEngine | undefined;\n try {\n const engine = ctx.getService<IDataEngine>('data');\n if (engine && typeof engine.insert === 'function') {\n dataEngine = engine;\n }\n } catch {\n // No data engine — pending-action queue will be a no-op.\n }\n if (this.options.traceRecorder === null) {\n // Explicit opt-out\n ctx.logger.debug('[AI] Tracing disabled (traceRecorder=null)');\n } else if (this.options.traceRecorder) {\n traceRecorder = this.options.traceRecorder;\n } else if (dataEngine) {\n traceRecorder = new ObjectQLTraceRecorder(dataEngine, { logger: ctx.logger });\n ctx.logger.info('[AI] Using ObjectQLTraceRecorder (IDataEngine detected)');\n }\n\n const config: AIServiceConfig = {\n adapter,\n logger: ctx.logger,\n conversationService,\n modelRegistry,\n traceRecorder,\n dataEngine,\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 scope: 'project',\n namespace: 'ai',\n objects: [AiConversationObject, AiMessageObject, AiTraceObject, AiPendingActionObject],\n views: [AiTraceView, AiPendingActionView],\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 tools & agents when services are available ──\n let metadataService: IMetadataService | undefined;\n // Helper: race a promise against a timeout, resolving null on timeout\n const withTimeout = <T>(promise: Promise<T>, ms = 2000): Promise<T | null> =>\n Promise.race([promise, new Promise<null>(resolve => setTimeout(() => resolve(null), ms))]);\n try {\n metadataService = ctx.getService<IMetadataService>('metadata');\n console.log('[AI Plugin] Retrieved metadata service:', !!metadataService, 'has getRegisteredTypes:', typeof (metadataService as any)?.getRegisteredTypes);\n } catch (e: any) {\n console.log('[AI] Metadata service not available:', e.message);\n ctx.logger.debug('[AI] Metadata service not available');\n }\n\n // Probe metadata service reachability with a short timeout.\n // If the backing store (e.g. Turso) is unreachable, exists() will hang.\n // A single probe determines whether persistence is available for all subsequent calls.\n if (metadataService && typeof metadataService.exists === 'function') {\n const probeResult = await withTimeout(metadataService.exists('tool', '__probe__'), 3000);\n if (probeResult === null) {\n ctx.logger.warn('[AI] Metadata service unreachable (timed out) — AI tools/agents will work but Studio visibility unavailable');\n metadataService = undefined; // disable persistence for this boot\n }\n }\n\n // Data tools require only the data engine\n try {\n const dataEngine = ctx.getService<IDataEngine>('data');\n if (dataEngine) {\n registerDataTools(this.service.toolRegistry, { dataEngine });\n ctx.logger.info('[AI] Built-in data tools registered');\n\n // Register query_data tool when metadata service is also available —\n // it composes AI + Metadata + Data into a single NL-to-records call.\n if (metadataService) {\n registerQueryDataTool(this.service.toolRegistry, {\n ai: this.service,\n metadata: metadataService,\n dataEngine,\n });\n ctx.logger.info('[AI] query_data tool registered');\n\n // Register actions-as-tools: enumerate every object's actions[]\n // and surface the script-type ones as `action_<name>` tools.\n // This is what gives agents the ability to *do things* (mark\n // task complete, clone record, ...) — the write-side counterpart\n // to query_data.\n try {\n // Resolve automation service (optional — flow actions get\n // skipped gracefully if unavailable).\n let automation: IAutomationService | undefined;\n try {\n automation = ctx.getService<IAutomationService>('automation');\n } catch {\n automation = undefined;\n }\n const apiBaseUrl =\n this.options.apiActionBaseUrl ?? process.env.OS_AI_ACTION_API_BASE_URL;\n const apiHeaders = this.options.apiActionHeaders;\n const { registered, skipped } = await registerActionsAsTools(\n this.service.toolRegistry,\n {\n metadata: metadataService,\n dataEngine,\n automation,\n apiBaseUrl,\n apiHeaders,\n enableActionApproval: this.options.enableActionApproval ?? false,\n aiService: this.service,\n },\n );\n if (registered.length > 0) {\n ctx.logger.info(\n `[AI] ${registered.length} action tool(s) registered: ${registered.join(', ')}`,\n );\n }\n if (skipped.length > 0) {\n ctx.logger.debug(\n `[AI] Skipped ${skipped.length} action(s) for AI exposure`,\n { skipped },\n );\n }\n } catch (err) {\n ctx.logger.warn(\n '[AI] Failed to register action tools',\n err instanceof Error ? { error: err.message } : { error: String(err) },\n );\n }\n }\n\n // Register data tools as metadata (for Studio visibility)\n if (metadataService) {\n const { DATA_TOOL_DEFINITIONS } = await import('./tools/data-tools.js');\n for (const toolDef of DATA_TOOL_DEFINITIONS) {\n const toolExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('tool', toolDef.name))\n : false;\n\n if (toolExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence');\n break;\n }\n\n if (!toolExists) {\n try {\n await withTimeout(metadataService.register('tool', toolDef.name, toolDef));\n } catch (err) {\n ctx.logger.warn('[AI] Failed to persist tool metadata (non-fatal)',\n err instanceof Error ? { tool: toolDef.name, error: err.message } : { tool: toolDef.name });\n }\n }\n }\n ctx.logger.info(`[AI] ${DATA_TOOL_DEFINITIONS.length} data tools registered as metadata`);\n }\n\n // Register the built-in data_chat agent (requires metadata service)\n if (metadataService) {\n try {\n const agentExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('agent', DATA_CHAT_AGENT.name))\n : false;\n\n if (agentExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking data_chat agent, skipping');\n } else if (!agentExists) {\n await withTimeout(metadataService.register('agent', DATA_CHAT_AGENT.name, DATA_CHAT_AGENT));\n console.log('[AI] Registered data_chat agent to metadataService');\n ctx.logger.info('[AI] data_chat agent registered');\n } else {\n console.log('[AI] data_chat agent already exists, skipping');\n ctx.logger.debug('[AI] data_chat agent already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register data_chat agent', err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });\n }\n\n // Register the built-in data_explorer skill (capability bundle for data_chat)\n try {\n const skillExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('skill', DATA_EXPLORER_SKILL.name))\n : false;\n\n if (skillExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking data_explorer skill, skipping');\n } else if (!skillExists) {\n await withTimeout(metadataService.register('skill', DATA_EXPLORER_SKILL.name, DATA_EXPLORER_SKILL));\n ctx.logger.info('[AI] data_explorer skill registered');\n } else {\n ctx.logger.debug('[AI] data_explorer skill already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register data_explorer skill', err instanceof Error ? { error: err.message } : { error: String(err) });\n }\n\n // Register the built-in actions_executor skill (write-side bundle for data_chat)\n try {\n const skillExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('skill', ACTIONS_EXECUTOR_SKILL.name))\n : false;\n\n if (skillExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking actions_executor skill, skipping');\n } else if (!skillExists) {\n await withTimeout(metadataService.register('skill', ACTIONS_EXECUTOR_SKILL.name, ACTIONS_EXECUTOR_SKILL));\n ctx.logger.info('[AI] actions_executor skill registered');\n } else {\n ctx.logger.debug('[AI] actions_executor skill already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register actions_executor skill', err instanceof Error ? { error: err.message } : { error: String(err) });\n }\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 metadata tools as metadata (for Studio visibility)\n const { METADATA_TOOL_DEFINITIONS } = await import('./tools/metadata-tools.js');\n for (const toolDef of METADATA_TOOL_DEFINITIONS) {\n const toolExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('tool', toolDef.name))\n : false;\n\n if (toolExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence');\n break;\n }\n\n if (!toolExists) {\n try {\n await withTimeout(metadataService.register('tool', toolDef.name, toolDef));\n } catch (err) {\n ctx.logger.warn('[AI] Failed to persist tool metadata (non-fatal)',\n err instanceof Error ? { tool: toolDef.name, error: err.message } : { tool: toolDef.name });\n }\n }\n }\n ctx.logger.info(`[AI] ${METADATA_TOOL_DEFINITIONS.length} metadata tools registered as metadata`);\n\n // Register the built-in metadata_assistant agent\n try {\n const agentExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('agent', METADATA_ASSISTANT_AGENT.name))\n : false;\n\n if (agentExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking metadata_assistant agent, skipping');\n } else if (!agentExists) {\n await withTimeout(metadataService.register('agent', METADATA_ASSISTANT_AGENT.name, METADATA_ASSISTANT_AGENT));\n console.log('[AI] Registered metadata_assistant agent to metadataService');\n ctx.logger.info('[AI] metadata_assistant agent registered');\n } else {\n console.log('[AI] metadata_assistant agent already exists, skipping');\n ctx.logger.debug('[AI] metadata_assistant agent already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register metadata_assistant agent', err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });\n }\n\n // Register the built-in metadata_authoring skill (capability bundle for metadata_assistant)\n try {\n const skillExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('skill', METADATA_AUTHORING_SKILL.name))\n : false;\n\n if (skillExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking metadata_authoring skill, skipping');\n } else if (!skillExists) {\n await withTimeout(metadataService.register('skill', METADATA_AUTHORING_SKILL.name, METADATA_AUTHORING_SKILL));\n ctx.logger.info('[AI] metadata_authoring skill registered');\n } else {\n ctx.logger.debug('[AI] metadata_authoring skill already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register metadata_authoring skill', err instanceof Error ? { error: err.message } : { error: String(err) });\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 // ── Bridge stack-defined agents from the ObjectQL registry into the\n // MetadataService so AgentRuntime.listAgents() / loadAgent() can see\n // them. Agents declared via defineStack({ agents: [...] }) are stored\n // in the ObjectQL registry by the AppPlugin, but the MetadataManager\n // keeps an independent in-memory store. Without this bridge,\n // /api/v1/ai/agents would only return agents the AI plugin registered\n // itself (data_chat, metadata_assistant).\n if (metadataService) {\n try {\n const objectql = ctx.getService<any>('objectql');\n const registry = objectql?.registry;\n if (registry && typeof registry.listItems === 'function') {\n const stackAgents = registry.listItems('agent') as Array<any>;\n let bridged = 0;\n for (const entry of stackAgents) {\n const agent = entry?.content ?? entry;\n const agentName = agent?.name;\n if (!agentName || typeof agentName !== 'string') continue;\n const exists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('agent', agentName))\n : false;\n if (exists === true) continue;\n try {\n await withTimeout(metadataService.register('agent', agentName, agent));\n bridged++;\n } catch (err) {\n ctx.logger.warn(\n '[AI] Failed to bridge stack agent into metadata service (non-fatal)',\n err instanceof Error ? { agent: agentName, error: err.message } : { agent: agentName },\n );\n }\n }\n if (bridged > 0) {\n ctx.logger.info(`[AI] Bridged ${bridged} stack-defined agent(s) from ObjectQL registry`);\n console.log(`[AI] Bridged ${bridged} stack-defined agent(s) from ObjectQL registry`);\n }\n }\n } catch (err) {\n ctx.logger.debug('[AI] ObjectQL registry not available, skipping agent bridge', err instanceof Error ? err : undefined);\n }\n }\n\n // Build and expose route definitions\n const routes = buildAIRoutes(this.service, this.service.conversationService, ctx.logger);\n\n // Build tool routes\n const toolRoutes = buildToolRoutes(this.service, ctx.logger);\n routes.push(...toolRoutes);\n ctx.logger.info(`[AI] Tool routes registered (${toolRoutes.length} routes)`);\n\n // Build HITL pending-action routes\n const pendingRoutes = buildPendingActionRoutes(this.service, ctx.logger);\n routes.push(...pendingRoutes);\n ctx.logger.info(`[AI] Pending-action routes registered (${pendingRoutes.length} routes)`);\n\n // Build agent routes if metadata service is available\n if (metadataService) {\n const skillRegistry = new SkillRegistry(metadataService);\n const agentRuntime = new AgentRuntime(metadataService, skillRegistry);\n const agentRoutes = buildAgentRoutes(this.service, agentRuntime, ctx.logger);\n routes.push(...agentRoutes);\n ctx.logger.info(`[AI] Agent routes registered (${agentRoutes.length} routes)`);\n\n const assistantRoutes = buildAssistantRoutes(this.service, agentRuntime, skillRegistry, ctx.logger);\n routes.push(...assistantRoutes);\n ctx.logger.info(`[AI] Assistant (ambient) routes registered (${assistantRoutes.length} routes)`);\n } else {\n ctx.logger.debug('[AI] Metadata service not available, skipping agent and assistant 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","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { z } from 'zod';\nimport type {\n AIToolDefinition,\n IAIService,\n IDataEngine,\n IMetadataService,\n ModelMessage,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport { SchemaRetriever } from '../schema-retriever.js';\nimport type { ToolHandler, ToolRegistry, ToolExecutionContext } from './tool-registry.js';\n\n/** See `data-tools.ts#buildEngineContext` — duplicated here to keep\n * this single-tool module dependency-free from the data-tools file. */\nfunction buildAiEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\n}\n\n/**\n * Context for the `query_data` tool.\n *\n * Wires together the three services it needs:\n * - {@link IAIService} for structured-output generation of the ObjectQL query\n * - {@link IMetadataService} for schema discovery\n * - {@link IDataEngine} for actually executing the resolved query\n */\nexport interface QueryDataToolContext {\n ai: IAIService;\n metadata: IMetadataService;\n dataEngine: IDataEngine;\n /** Maximum number of records returned per call (default: 100). */\n maxLimit?: number;\n}\n\n/**\n * Zod schema used to constrain the LLM's structured output.\n *\n * Kept small and strict — every property is documented so providers like\n * OpenAI Structured Outputs and Anthropic Tool Use can render high-quality\n * prompts from the schema metadata.\n *\n * NOTE: `where` is intentionally typed as a JSON string rather than a free-form\n * record. OpenAI's Structured Outputs surface rejects `propertyNames`\n * (which Zod's `z.record(z.string(), ...)` emits), and Anthropic's tool-use\n * surface dislikes open-ended object schemas without `additionalProperties`.\n * Having the model emit a JSON-encoded filter sidesteps both restrictions and\n * keeps the tool portable across providers.\n */\nconst QueryPlanSchema = z.object({\n objectName: z\n .string()\n .min(1)\n .describe('The snake_case object name to query (e.g. \"task\", \"account\").'),\n whereJson: z\n .string()\n .nullable()\n .describe(\n 'Filter conditions encoded as a JSON object string. Examples: ' +\n '`{\"status\":\"completed\"}`, `{\"subject\":{\"$contains\":\"Build\"}}`, ' +\n '`{\"amount\":{\"$gt\":100}}`. Pass null to match all records.',\n ),\n fields: z\n .array(z.string())\n .nullable()\n .describe('Field names to return. Pass null to return all fields.'),\n orderBy: z\n .array(\n z.object({\n field: z.string(),\n order: z.enum(['asc', 'desc']),\n }),\n )\n .nullable()\n .describe('Sort order. First entry is primary sort key. Pass null for no sort.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(200)\n .nullable()\n .describe('Maximum number of records (default 20, max 200). Pass null for default.'),\n});\n\n/** Strongly-typed query plan inferred from the LLM. */\nexport type QueryPlan = z.infer<typeof QueryPlanSchema>;\n\n/**\n * Tool definition advertised to the LLM in the outer tool-call loop.\n *\n * The model invokes this tool with a single `request` argument — a\n * paraphrased question. The handler then performs:\n * 1. Schema retrieval (keyword match on the metadata catalogue)\n * 2. Structured-output generation of an ObjectQL plan (via Zod schema)\n * 3. Execution of that plan against the data engine\n * 4. Returns the results as JSON for the model to summarise.\n *\n * This collapses what used to be \"schema retriever middleware + NLQ service\"\n * into one tool, fully consistent with the platform's tool-calling pattern.\n */\nexport const QUERY_DATA_TOOL: AIToolDefinition = {\n name: 'query_data',\n description:\n 'Answer a natural-language question about the user\\'s data. ' +\n 'Internally retrieves the relevant object schema, generates an ObjectQL ' +\n 'query, executes it, and returns the matching records. Prefer this tool ' +\n 'over `query_records` / `aggregate_data` when the user\\'s intent is ' +\n 'expressed in plain language.',\n parameters: {\n type: 'object',\n properties: {\n request: {\n type: 'string',\n description:\n 'The natural-language question to answer (paraphrase the user\\'s ' +\n 'request if needed for clarity).',\n },\n },\n required: ['request'],\n additionalProperties: false,\n },\n};\n\n/**\n * Create a handler for the `query_data` tool.\n *\n * The handler is intentionally stateless — every call performs a fresh\n * schema lookup so newly registered objects are picked up immediately.\n */\nexport function createQueryDataHandler(ctx: QueryDataToolContext): ToolHandler {\n const retriever = new SchemaRetriever(ctx.metadata);\n const maxLimit = ctx.maxLimit ?? 100;\n\n return async (args, execCtx) => {\n const { request } = args as { request: string };\n\n if (!request || typeof request !== 'string') {\n return JSON.stringify({ error: 'query_data: `request` is required' });\n }\n\n if (!ctx.ai.generateObject) {\n return JSON.stringify({\n error:\n 'query_data requires structured-output support. Configure a ' +\n 'Vercel-AI-SDK-backed adapter (OpenAI, Anthropic, Google).',\n });\n }\n\n // 1. Schema retrieval\n const hits = await retriever.retrieve(request);\n if (hits.length === 0) {\n return JSON.stringify({\n error:\n 'No matching objects in metadata. Ask the user which object(s) ' +\n 'to query, or list available objects via list_objects.',\n });\n }\n const snippet = SchemaRetriever.renderSnippet(hits);\n\n // 2. Plan generation\n const planMessages: ModelMessage[] = [\n {\n role: 'system',\n content:\n 'You translate user data questions into a single ObjectQL query plan. ' +\n 'Use ONLY the objects and fields listed in the schema context below. ' +\n 'Never invent field names. If the question is ambiguous, pick the ' +\n 'most likely interpretation and use a reasonable `limit`.\\n\\n' +\n 'Filter operator hints:\\n' +\n ' • For partial string matches (e.g. \"task named Foo\", \"find X\"), ' +\n 'use case-insensitive substring matching with `$contains`: ' +\n '`{\"subject\": {\"$contains\": \"Foo\"}}`. Do NOT use equality unless ' +\n 'the user clearly supplied the exact full value.\\n' +\n ' • For numeric/date ranges use `$gt` / `$gte` / `$lt` / `$lte`.\\n' +\n ' • For \"is one of\" use `$in: [...]`.\\n' +\n ' • For exact equality just write the value: `{\"status\": \"completed\"}`.\\n\\n' +\n snippet,\n },\n { role: 'user', content: request },\n ];\n\n let plan: QueryPlan;\n try {\n const generated = await ctx.ai.generateObject(planMessages, QueryPlanSchema, {\n schemaName: 'ObjectQLQueryPlan',\n schemaDescription: 'A single ObjectQL find() query to answer the user request.',\n });\n plan = generated.object;\n } catch (err) {\n return JSON.stringify({\n error: `Failed to plan query: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 3. Validate the plan against the retrieved schema\n const matchedObject = hits.find(h => h.object.name === plan.objectName)?.object\n ?? hits[0].object;\n if (matchedObject.name !== plan.objectName) {\n return JSON.stringify({\n error:\n `Planned object \"${plan.objectName}\" is not in the retrieved schema. ` +\n `Available: ${hits.map(h => h.object.name).join(', ')}`,\n });\n }\n\n // 4. Execution\n const limit = Math.min(plan.limit ?? 20, maxLimit);\n let where: Record<string, unknown> | undefined;\n if (plan.whereJson) {\n try {\n const parsed = JSON.parse(plan.whereJson);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n where = parsed as Record<string, unknown>;\n } else {\n return JSON.stringify({\n plan,\n error: `whereJson must encode a JSON object, got: ${plan.whereJson}`,\n });\n }\n } catch (err) {\n return JSON.stringify({\n plan,\n error: `whereJson is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n try {\n const records = await ctx.dataEngine.find(plan.objectName, {\n where,\n fields: plan.fields ?? undefined,\n orderBy: plan.orderBy ?? undefined,\n limit,\n context: buildAiEngineContext(execCtx),\n });\n return JSON.stringify({\n plan: { ...plan, where },\n count: records.length,\n records,\n });\n } catch (err) {\n return JSON.stringify({\n plan,\n error: `Query execution failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n };\n}\n\n/**\n * Register the `query_data` tool on the given {@link ToolRegistry}.\n *\n * Typically called from {@link AIServicePlugin.start} once the AI, metadata,\n * and data services are all available.\n */\nexport function registerQueryDataTool(\n registry: ToolRegistry,\n context: QueryDataToolContext,\n): void {\n registry.register(QUERY_DATA_TOOL, createQueryDataHandler(context));\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IMetadataService } from '@objectstack/spec/contracts';\n\n/**\n * SchemaRetriever — Keyword-based metadata retrieval for AI prompts.\n *\n * Given a free-text query (typically the user's last message), surfaces the\n * most relevant `object` definitions and renders a compact schema snippet\n * suitable for injection into the system prompt.\n *\n * v1 strategy is intentionally simple:\n * - Tokenise the query into lower-case alphanumeric terms\n * - Score each registered object by counting term hits against its name,\n * label, field names, and field labels\n * - Return the top `limit` matches above the score threshold\n *\n * This does *not* use embeddings — for v1 the user-defined object catalogue\n * is small enough (< 1000 objects in practice) that a single linear scan\n * over already-cached metadata is faster than a vector round-trip and\n * eliminates the need for a vector store.\n *\n * Future versions can swap in {@link IAIService.embed} backed retrieval\n * behind the same `retrieve()` shape.\n *\n * @example\n * ```ts\n * const retriever = new SchemaRetriever(metadataService);\n * const hits = await retriever.retrieve('how many open tasks are due this week?');\n * const snippet = SchemaRetriever.renderSnippet(hits);\n * // snippet:\n * // ## Schema context (auto-injected)\n * // ### task — Project Task\n * // - id: text\n * // - title: text\n * // - status: select(open|in_progress|done)\n * // - due_date: date\n * ```\n */\nexport class SchemaRetriever {\n private readonly metadata: IMetadataService;\n private readonly options: Required<SchemaRetrieverOptions>;\n\n constructor(metadata: IMetadataService, options: SchemaRetrieverOptions = {}) {\n this.metadata = metadata;\n this.options = {\n limit: options.limit ?? 3,\n minScore: options.minScore ?? 1,\n maxFieldsPerObject: options.maxFieldsPerObject ?? 12,\n };\n }\n\n /**\n * Find object definitions whose name/label/fields match terms in the query.\n *\n * Returns matches sorted by score (descending) capped at `limit`. When\n * the query yields no matches, returns an empty array — callers may\n * fall back to a generic \"describe what data exists\" tool call.\n */\n async retrieve(query: string): Promise<SchemaHit[]> {\n const terms = tokenise(query);\n if (terms.length === 0) return [];\n\n const objects = await this.metadata.listObjects();\n const hits: SchemaHit[] = [];\n\n for (const raw of objects) {\n const obj = raw as ObjectShape;\n if (!obj?.name) continue;\n const score = scoreObject(obj, terms);\n if (score >= this.options.minScore) {\n hits.push({ object: obj, score });\n }\n }\n\n hits.sort((a, b) => b.score - a.score);\n return hits.slice(0, this.options.limit);\n }\n\n /**\n * Render hits as a compact Markdown schema snippet.\n *\n * Designed to be appended to the system message — every line carries\n * exactly the information a model needs to choose object/field names\n * for query construction.\n */\n static renderSnippet(hits: SchemaHit[], maxFieldsPerObject = 12): string {\n if (hits.length === 0) return '';\n const lines: string[] = ['## Schema context (auto-injected)'];\n for (const hit of hits) {\n const obj = hit.object;\n // Emit `### name — Label (Plural)` so downstream consumers (system\n // prompt for the LLM, MemoryAdapter heuristic) can score by either\n // the machine name, the singular label, or the plural label. Real\n // users typically say \"show me my tasks\", not \"list todo_task\".\n const parts: string[] = [];\n if (obj.label) parts.push(obj.label);\n if (obj.pluralLabel && obj.pluralLabel !== obj.label) parts.push(`(${obj.pluralLabel})`);\n const header = parts.length > 0 ? ` — ${parts.join(' ')}` : '';\n lines.push(`### ${obj.name}${header}`);\n const fields = Object.entries(obj.fields ?? {}).slice(0, maxFieldsPerObject);\n for (const [name, field] of fields) {\n lines.push(` - ${name}: ${describeField(field)}`);\n }\n const total = Object.keys(obj.fields ?? {}).length;\n if (total > fields.length) {\n lines.push(` - …${total - fields.length} more field(s)`);\n }\n }\n return lines.join('\\n');\n }\n}\n\n/** A scored retrieval result. */\nexport interface SchemaHit {\n object: ObjectShape;\n score: number;\n}\n\n/** Options for {@link SchemaRetriever}. */\nexport interface SchemaRetrieverOptions {\n /** Maximum number of objects to return (default: 3). */\n limit?: number;\n /** Minimum score required to include an object (default: 1). */\n minScore?: number;\n /** Maximum fields rendered per object in the snippet (default: 12). */\n maxFieldsPerObject?: number;\n}\n\n/** Minimal shape of an object definition we care about. */\nexport interface ObjectShape {\n name: string;\n label?: string;\n pluralLabel?: string;\n description?: string;\n fields?: Record<string, FieldShape>;\n}\n\n/** Minimal shape of a field definition. */\nexport interface FieldShape {\n type?: string;\n label?: string;\n options?: unknown;\n reference?: string;\n}\n\n// ── internal helpers ──────────────────────────────────────────────\n\n/** Lower-case alphanumeric tokens of length ≥ 2 (English stop-words excluded). */\nfunction tokenise(query: string): string[] {\n // Split on any non-alphanumeric (including underscores) so `todo_task`\n // tokenises to ['todo', 'task'] and matches snake_case object names.\n const raw = query.toLowerCase().match(/[a-z0-9]+/g) ?? [];\n return raw.filter(t => t.length >= 2 && !STOPWORDS.has(t));\n}\n\nconst STOPWORDS = new Set([\n 'the', 'and', 'for', 'with', 'from', 'are', 'has', 'have', 'had', 'was', 'were',\n 'this', 'that', 'these', 'those', 'all', 'any', 'how', 'what', 'when', 'where',\n 'who', 'why', 'which', 'show', 'list', 'find', 'get', 'count', 'of', 'in', 'on',\n 'at', 'to', 'as', 'by', 'is', 'it', 'an', 'or', 'be', 'me',\n]);\n\n/**\n * Score an object by term hits.\n *\n * Weights: name match = 3, label match = 2, description match = 1,\n * field name match = 2, field label match = 1. A term may contribute at\n * most once per field source.\n */\nfunction scoreObject(obj: ObjectShape, terms: string[]): number {\n let score = 0;\n const nameTokens = splitSnake(obj.name);\n const labelTokens = obj.label ? tokenise(obj.label) : [];\n const pluralTokens = obj.pluralLabel ? tokenise(obj.pluralLabel) : [];\n const descTokens = obj.description ? tokenise(obj.description) : [];\n\n for (const term of terms) {\n if (nameTokens.includes(term)) score += 3;\n else if (labelTokens.includes(term) || pluralTokens.includes(term)) score += 2;\n else if (descTokens.includes(term)) score += 1;\n }\n\n for (const [fieldName, field] of Object.entries(obj.fields ?? {})) {\n const fnTokens = splitSnake(fieldName);\n const flTokens = field.label ? tokenise(field.label) : [];\n for (const term of terms) {\n if (fnTokens.includes(term)) score += 2;\n else if (flTokens.includes(term)) score += 1;\n }\n }\n\n return score;\n}\n\n/** Split snake_case identifier into lower-case word tokens. */\nfunction splitSnake(name: string): string[] {\n return name.toLowerCase().split('_').filter(Boolean);\n}\n\n/** Compact human-readable description of a field's type. */\nfunction describeField(field: FieldShape): string {\n const t = field.type ?? 'unknown';\n if (t === 'lookup' && field.reference) return `lookup → ${field.reference}`;\n if (t === 'select' && Array.isArray(field.options)) {\n const values = field.options\n .map((o: unknown) =>\n typeof o === 'string' ? o : (o as { value?: string }).value,\n )\n .filter(Boolean)\n .slice(0, 6);\n return `select(${values.join('|')})`;\n }\n return t;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Actions-as-Tools — turn declarative {@link Action} metadata into\n * AI-callable tools so an agent can not only **read** the user's data\n * (via `query_data` / `data_explorer`) but also **act** on it.\n *\n * Phase 1 scope (this module):\n * - Only `type: 'script'` actions are auto-exposed. Their handler is\n * resolved through {@link IDataEngine.executeAction} (the same\n * dispatcher used by Studio's \"row toolbar\" buttons), so the LLM\n * ends up calling exactly the same business logic the UI does.\n * - Skip any action that is dangerous (`confirmText`, `variant: 'danger'`,\n * `mode: 'delete'`) — these require Phase 2 HITL plumbing.\n * - Skip any action whose owner opted out via `aiExposed: false` (the\n * hint is read from the action record but not formalised in the Zod\n * schema yet; spec change is backwards-compatible additive).\n *\n * The tool's JSON Schema is materialised from `action.params[]`,\n * resolving field-backed params (`{ field: 'priority' }`) against the\n * owning object so the LLM sees the same type/options/required\n * constraints the modal dialog would render.\n */\n\nimport type {\n AIToolDefinition,\n IAutomationService,\n IDataEngine,\n IMetadataService,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport type { Action, ActionParam } from '@objectstack/spec/ui';\nimport type { ToolHandler, ToolRegistry, ToolExecutionContext } from './tool-registry.js';\n\n/** Minimal field shape we care about when resolving param types. */\ninterface FieldDef {\n type?: string;\n label?: string;\n required?: boolean;\n options?: Array<{ value: string; label?: unknown } | string>;\n description?: string;\n}\n\n/** Minimal object shape — same as what {@link SchemaRetriever} consumes. */\ninterface ObjectDef {\n name: string;\n label?: string;\n pluralLabel?: string;\n fields?: Record<string, FieldDef>;\n actions?: Action[];\n}\n\n/**\n * Dependencies needed to invoke an Action from the AI tool runtime.\n *\n * The `metadata` service is used at registration time to resolve param\n * field types; the `dataEngine` is used at call time to (a) load the\n * subject record when a `recordIdParam` is configured and (b) dispatch\n * to the registered handler via `executeAction`.\n *\n * `automation` enables `type:'flow'` actions to dispatch into the\n * automation service's flow runner. When omitted, flow actions are\n * skipped at registration time with a clear reason.\n *\n * `apiClient` (or `apiBaseUrl`) enables `type:'api'` actions to perform\n * an HTTP call to the action's `target` URL. The default client uses\n * the global `fetch` and prepends `apiBaseUrl` to relative `target`s.\n * Supply a custom client when you need bespoke auth, in-process\n * routing, or stubbing in tests.\n *\n * `principal` lets callers attribute AI-initiated mutations to a known\n * user id; it defaults to a synthetic `'ai_agent'` user so traces /\n * audit always have *some* actor.\n */\nexport interface ActionToolsContext {\n metadata: IMetadataService;\n dataEngine: IDataEngine;\n /** Automation service for `type:'flow'` action dispatch. Optional. */\n automation?: IAutomationService;\n /** Custom API client for `type:'api'` actions. Defaults to a fetch-based client. */\n apiClient?: ApiActionClient;\n /** Base URL prepended to relative `target` paths for `type:'api'` actions. */\n apiBaseUrl?: string;\n /** Extra HTTP headers (e.g. auth bearer) applied to every `type:'api'` call. */\n apiHeaders?: Record<string, string>;\n /** Synthetic user attribution for AI-initiated calls. */\n principal?: { id: string; name?: string };\n /** Tool-name prefix (default: `action_`). Keeps namespace separate from data tools. */\n toolPrefix?: string;\n /**\n * AI service used to enqueue HITL approvals for dangerous actions.\n * When supplied together with `enableActionApproval: true`, actions\n * that would otherwise be skipped on safety grounds (`confirmText`,\n * `mode:'delete'`, `variant:'danger'`) are registered as tools whose\n * handler proposes a pending action and returns\n * `{ status: 'pending_approval' }` instead of executing.\n */\n aiService?: {\n proposePendingAction?: (input: {\n objectName: string;\n actionName: string;\n toolName: string;\n toolInput: Record<string, unknown>;\n conversationId?: string;\n messageId?: string;\n proposedBy?: string;\n }) => Promise<{ id: string }>;\n registerPendingActionDispatcher?: (\n toolName: string,\n dispatch: (input: Record<string, unknown>) => Promise<unknown>,\n ) => void;\n };\n /**\n * Opt into the HITL approval queue for dangerous actions. Default\n * is `false` (safer: dangerous actions stay invisible to the LLM\n * until an operator explicitly enables approval routing).\n */\n enableActionApproval?: boolean;\n}\n\n/**\n * Minimal HTTP client shape used by `type:'api'` action dispatch.\n *\n * Implementations are expected to return a JSON-deserialised body (or\n * `null` for empty responses) on 2xx, and throw on non-2xx so the tool\n * surfaces the failure to the LLM as a tool error.\n */\nexport interface ApiActionClient {\n request(input: {\n url: string;\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n body?: Record<string, unknown>;\n headers?: Record<string, string>;\n }): Promise<unknown>;\n}\n\n/** Result returned to the LLM after invoking an action. */\ninterface ActionInvocationResult {\n ok: boolean;\n action: string;\n objectName?: string;\n recordId?: string;\n message?: string;\n result?: unknown;\n error?: string;\n}\n\n// ── Skip-list predicates ────────────────────────────────────────────\n\n/**\n * Decide whether an action should be auto-exposed as a tool.\n *\n * Returns `null` when exposed, or a string reason when skipped.\n * Exported for tests and Studio \"AI exposure\" diagnostics.\n *\n * Supported types as of Phase 2: `script`, `api`, `flow`. Studio-only\n * UI types (`url`, `modal`, `form`) remain skipped — they have no\n * headless invocation path.\n */\n/**\n * True when an action is \"dangerous\" and should be routed through the\n * HITL approval queue (rather than dispatched directly). Exported so\n * Studio's AI-exposure surface can highlight which actions require\n * approval.\n */\nexport function actionRequiresApproval(action: Action): boolean {\n return Boolean(\n action.confirmText || action.mode === 'delete' || action.variant === 'danger',\n );\n}\n\nexport function actionSkipReason(\n action: Action,\n ctx?: {\n automation?: IAutomationService;\n apiClient?: ApiActionClient;\n apiBaseUrl?: string;\n enableActionApproval?: boolean;\n aiService?: ActionToolsContext['aiService'];\n },\n): string | null {\n if (action.aiExposed === false) {\n return 'opted-out via aiExposed:false';\n }\n // Skip Studio-only types (no headless invocation surface).\n if (action.type === 'url' || action.type === 'modal' || action.type === 'form') {\n return `type='${action.type}' is UI-only`;\n }\n if (action.type !== 'script' && action.type !== 'api' && action.type !== 'flow') {\n return `type='${action.type}' not supported`;\n }\n if (action.type === 'script' && !action.target && !action.body) {\n return 'no target or body';\n }\n if ((action.type === 'api' || action.type === 'flow') && !action.target) {\n return `type='${action.type}' requires a target`;\n }\n // Wiring availability checks — only meaningful when ctx is supplied.\n if (ctx) {\n if (action.type === 'flow' && !ctx.automation) {\n return 'no automation service available';\n }\n if (action.type === 'api' && !ctx.apiClient && !ctx.apiBaseUrl) {\n return 'no apiClient or apiBaseUrl configured';\n }\n }\n // Safety: dangerous actions normally require explicit human approval.\n // When the caller has opted in to the HITL queue (and wired aiService),\n // we *register* them and route to the queue instead of skipping.\n if (actionRequiresApproval(action)) {\n const approvalReady =\n ctx?.enableActionApproval === true && Boolean(ctx?.aiService?.proposePendingAction);\n if (!approvalReady) {\n if (action.confirmText) return 'requires confirmation (confirmText set)';\n if (action.mode === 'delete') return \"mode='delete' — destructive\";\n if (action.variant === 'danger') return \"variant='danger' — destructive\";\n }\n }\n return null;\n}\n\n// ── Param → JSON Schema ─────────────────────────────────────────────\n\n/**\n * Map an ObjectStack field type to a JSON-Schema primitive type.\n *\n * Intentionally conservative — anything we don't recognise becomes\n * `string` so the LLM can still pass *something*. Handlers should\n * re-validate via Zod / runtime checks anyway.\n */\nfunction fieldTypeToJsonType(t: string | undefined): 'string' | 'number' | 'boolean' | 'array' {\n switch (t) {\n case 'number':\n case 'currency':\n case 'percent':\n case 'rating':\n case 'slider':\n case 'autonumber':\n return 'number';\n case 'boolean':\n case 'toggle':\n return 'boolean';\n case 'multiselect':\n case 'checkboxes':\n case 'tags':\n return 'array';\n default:\n return 'string';\n }\n}\n\n/**\n * Resolve a single {@link ActionParam} into a `(name, jsonSchema, required)`\n * tuple by consulting the owning object's field definition when the param\n * uses field-backing.\n */\nfunction resolveParam(\n param: ActionParam,\n ownerObject: ObjectDef | undefined,\n allObjects: Map<string, ObjectDef>,\n): { name: string; schema: Record<string, unknown>; required: boolean } | null {\n const fieldRef = param.field;\n const owner =\n param.objectOverride && allObjects.get(param.objectOverride)\n ? allObjects.get(param.objectOverride)\n : ownerObject;\n const field = fieldRef ? owner?.fields?.[fieldRef] : undefined;\n\n const name = param.name ?? fieldRef;\n if (!name) return null;\n\n const type = param.type ?? field?.type;\n const jsonType = fieldTypeToJsonType(type);\n const schema: Record<string, unknown> = { type: jsonType };\n\n const label = typeof param.label === 'string' ? param.label : field?.label;\n const help = param.helpText ?? field?.description;\n const description = [label, help].filter(Boolean).join(' — ') || undefined;\n if (description) schema.description = description;\n\n // Enum sourcing — explicit override wins, otherwise field options\n const optionSource = param.options ?? field?.options;\n if (Array.isArray(optionSource) && optionSource.length > 0) {\n const values = optionSource\n .map(o => (typeof o === 'string' ? o : (o as { value?: string }).value))\n .filter((v): v is string => typeof v === 'string');\n if (values.length > 0) {\n schema.enum = jsonType === 'array' ? undefined : values;\n if (jsonType === 'array') {\n schema.items = { type: 'string', enum: values };\n }\n }\n } else if (jsonType === 'array') {\n schema.items = { type: 'string' };\n }\n\n if (param.defaultValue !== undefined) {\n schema.default = param.defaultValue;\n }\n\n const required = Boolean(param.required ?? field?.required ?? false);\n return { name, schema, required };\n}\n\n/**\n * Build the JSON Schema body for an action's `parameters` field.\n *\n * In addition to user-declared params, we always inject a `recordId`\n * argument when the action is bound to an object — the LLM needs *some*\n * way to say \"complete _this_ task\". The argument is optional for\n * actions that work without a record (`list_toolbar` only) and required\n * when the action declares `recordIdParam`.\n */\nfunction buildParametersSchema(\n action: Action,\n ownerObject: ObjectDef | undefined,\n allObjects: Map<string, ObjectDef>,\n): AIToolDefinition['parameters'] {\n const properties: Record<string, Record<string, unknown>> = {};\n const required: string[] = [];\n\n // Inject recordId for object-bound, row-context actions\n const isRowContext =\n Array.isArray(action.locations) &&\n action.locations.some(l => l === 'list_item' || l === 'record_header' || l === 'record_more' || l === 'record_related');\n if (action.objectName && isRowContext) {\n properties.recordId = {\n type: 'string',\n description: `The ${action.objectName} record id to act on.`,\n };\n // Mark required if action explicitly references a row field for id seeding\n if (action.recordIdParam || action.recordIdField) {\n required.push('recordId');\n }\n }\n\n for (const param of action.params ?? []) {\n const resolved = resolveParam(param, ownerObject, allObjects);\n if (!resolved) continue;\n properties[resolved.name] = resolved.schema;\n if (resolved.required) required.push(resolved.name);\n }\n\n return {\n type: 'object',\n properties,\n ...(required.length > 0 ? { required } : {}),\n additionalProperties: false,\n };\n}\n\n// ── Tool name + description ─────────────────────────────────────────\n\n/** Compute the AI tool name for a given action (prefixed for namespacing). */\nexport function actionToolName(action: Action, prefix = 'action_'): string {\n return `${prefix}${action.name}`;\n}\n\nfunction describeAction(action: Action, ownerObject: ObjectDef | undefined): string {\n const label =\n typeof action.label === 'string'\n ? action.label\n : action.name.replace(/_/g, ' ');\n const target = action.objectName ?? ownerObject?.name;\n const targetLabel = ownerObject?.label ?? target;\n const parts: string[] = [];\n parts.push(`${label}${targetLabel ? ` — operates on ${targetLabel}` : ''}.`);\n if (action.successMessage && typeof action.successMessage === 'string') {\n parts.push(`On success: ${action.successMessage}`);\n }\n if (action.mode) parts.push(`Mode: ${action.mode}.`);\n parts.push(\n 'Use this when the user asks to perform this operation in natural language.',\n );\n return parts.join(' ');\n}\n\n// ── Builders ────────────────────────────────────────────────────────\n\n/**\n * Convert a single {@link Action} into a complete {@link AIToolDefinition}.\n *\n * Returns `null` when the action is filtered out by {@link actionSkipReason}.\n */\nexport function actionToToolDefinition(\n action: Action,\n ownerObject: ObjectDef | undefined,\n allObjects: Map<string, ObjectDef>,\n toolPrefix = 'action_',\n): AIToolDefinition | null {\n // NOTE: skip eligibility is decided by the caller (registerActionsAsTools)\n // with full context (apiClient, automation, HITL approval wiring). This\n // function only checks the *structural* invariants that make a\n // definition impossible to build.\n if (action.aiExposed === false) return null;\n if (action.type === 'url' || action.type === 'modal' || action.type === 'form') return null;\n return {\n name: actionToolName(action, toolPrefix),\n description: describeAction(action, ownerObject),\n parameters: buildParametersSchema(action, ownerObject, allObjects),\n };\n}\n\n// ── Handler / dispatch ─────────────────────────────────────────────\n\n/**\n * Adapter that wraps {@link IDataEngine} into the shape user-authored\n * action handlers expect (see `examples/app-todo/src/actions/task.handlers.ts`).\n *\n * Handlers in the wild use a pseudo-ORM `engine.update(obj, id, data)`\n * convention, while {@link IDataEngine.update} takes `(obj, data, opts)`\n * with a `where`-style options bag. We adapt at the boundary so existing\n * Studio-side handlers run unchanged.\n */\nfunction buildHandlerEngineAdapter(engine: IDataEngine): {\n update: (object: string, id: string, data: Record<string, unknown>) => Promise<unknown>;\n insert: (object: string, data: Record<string, unknown>) => Promise<unknown>;\n find: (object: string, where: Record<string, unknown>) => Promise<unknown[]>;\n delete: (object: string, ids: string[]) => Promise<unknown>;\n} {\n return {\n update: (object, id, data) =>\n engine.update(object, { ...data, id }, { where: { id } }),\n insert: (object, data) => engine.insert(object, data),\n find: (object, where) => engine.find(object, { where }),\n delete: async (object, ids) => {\n if (!Array.isArray(ids) || ids.length === 0) return 0;\n // Loop scalar deletes — engine.delete prioritises a scalar `id`\n // extracted from `where.id` over the `multi:true` branch, so passing\n // `{ where: { id: { $in: [...] } } }` breaks at the driver layer.\n let count = 0;\n for (const id of ids) {\n await engine.delete(object, { where: { id } });\n count++;\n }\n return count;\n },\n };\n}\n\n/**\n * Shared entry-point: load record (when row-context), assemble user\n * params, then delegate to the type-specific executor.\n */\nfunction createActionToolHandler(\n action: Action,\n ctx: ActionToolsContext,\n): ToolHandler {\n const fallbackPrincipal = ctx.principal ?? { id: 'ai_agent', name: 'AI Assistant' };\n const requiresRecord =\n Array.isArray(action.locations) &&\n action.locations.some(\n l => l === 'list_item' || l === 'record_header' || l === 'record_more' || l === 'record_related',\n );\n\n return async (args, execCtx) => {\n // Per-request execution context wins over the static principal so\n // every audit/dispatch entry attributes the work to the real user\n // when one is known. Falls back to the registration-time principal\n // (or the synthetic `ai_agent`) for unauthenticated callers.\n const principal = execCtx?.actor\n ? { id: execCtx.actor.id, name: execCtx.actor.name }\n : fallbackPrincipal;\n const engineCtx = buildActionEngineContext(execCtx);\n const objectName = action.objectName;\n const target = action.target;\n const result: ActionInvocationResult = {\n ok: false,\n action: action.name,\n objectName,\n };\n\n if (!objectName) {\n result.error = 'Action has no objectName; cannot dispatch.';\n return JSON.stringify(result);\n }\n if (!target && action.type !== 'script') {\n result.error = 'Action has no target.';\n return JSON.stringify(result);\n }\n\n const recordId =\n typeof args.recordId === 'string' && args.recordId.length > 0\n ? args.recordId\n : undefined;\n\n let record: Record<string, unknown> | undefined;\n if (requiresRecord) {\n if (!recordId) {\n result.error =\n 'recordId is required for this action — supply the id of the ' +\n `${objectName} record to act on (use query_data first if you don't have it).`;\n return JSON.stringify(result);\n }\n try {\n // RLS engages here too — if the actor can't see the record,\n // the agent gets a \"not found\" error instead of leaking data.\n const found = await ctx.dataEngine.find(objectName, {\n where: { id: recordId },\n limit: 1,\n context: engineCtx,\n });\n record = (found as Array<Record<string, unknown>>)[0];\n if (!record) {\n result.error = `Record ${recordId} not found in ${objectName}.`;\n return JSON.stringify(result);\n }\n result.recordId = recordId;\n } catch (err) {\n result.error = `Failed to load record: ${err instanceof Error ? err.message : String(err)}`;\n return JSON.stringify(result);\n }\n }\n\n // Strip recordId from params before forwarding so handlers receive only\n // user-collected fields (mirroring the Studio modal-submit shape).\n const { recordId: _omit, ...userParams } = args as Record<string, unknown>;\n\n // ── HITL routing ──────────────────────────────────────────────\n // When the action is dangerous AND approval is wired, persist a\n // pending request and return the \"pending\" envelope instead of\n // dispatching. The dispatcher itself was pre-registered with\n // aiService.registerPendingActionDispatcher() at registration time\n // so approval re-runs the exact same code path.\n if (\n ctx.enableActionApproval &&\n actionRequiresApproval(action) &&\n ctx.aiService?.proposePendingAction\n ) {\n try {\n const toolName = `${ctx.toolPrefix ?? 'action_'}${action.name}`;\n const { id } = await ctx.aiService.proposePendingAction({\n objectName: objectName!,\n actionName: action.name,\n toolName,\n toolInput: args as Record<string, unknown>,\n conversationId: execCtx?.conversationId,\n messageId: execCtx?.messageId,\n proposedBy: principal.id,\n });\n const pending: ActionInvocationResult & {\n status?: string;\n pendingActionId?: string;\n } = {\n ok: true,\n action: action.name,\n objectName,\n recordId,\n status: 'pending_approval',\n pendingActionId: id,\n message:\n `Action '${action.name}' is destructive and requires human approval. ` +\n `Proposal queued as ${id}. ` +\n `An operator must approve via Studio's pending-actions inbox before it runs. ` +\n `Do NOT call this tool again for the same intent — wait for the operator.`,\n };\n return JSON.stringify(pending);\n } catch (err) {\n result.error = `Failed to enqueue approval: ${err instanceof Error ? err.message : String(err)}`;\n return JSON.stringify(result);\n }\n }\n\n try {\n let out: unknown;\n if (action.type === 'api') {\n out = await dispatchApiAction(action, ctx, userParams, record, recordId);\n } else if (action.type === 'flow') {\n out = await dispatchFlowAction(action, ctx, userParams, record, principal);\n } else {\n // 'script' (default) — existing behaviour.\n out = await dispatchScriptAction(action, ctx, userParams, record, principal);\n }\n result.ok = true;\n result.result = out ?? null;\n const successMsg =\n typeof action.successMessage === 'string' ? action.successMessage : undefined;\n result.message = successMsg ?? `Action '${action.name}' executed successfully.`;\n return JSON.stringify(result);\n } catch (err) {\n result.error = err instanceof Error ? err.message : String(err);\n return JSON.stringify(result);\n }\n };\n}\n\n/**\n * Translate the AI-side {@link ToolExecutionContext} into an ObjectQL\n * {@link ExecutionContext} for record lookups inside action handlers.\n * Mirrors `data-tools.ts#buildEngineContext` — kept local so this file\n * has no inter-tool dependency.\n */\nfunction buildActionEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\n}\n\nasync function dispatchScriptAction(\n action: Action,\n ctx: ActionToolsContext,\n params: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n principal: { id: string; name?: string },\n): Promise<unknown> {\n const engineAdapter = buildHandlerEngineAdapter(ctx.dataEngine);\n const handlerCtx = { record, user: principal, engine: engineAdapter, params };\n return await (ctx.dataEngine as IDataEngine & {\n executeAction?: (o: string, a: string, c: unknown) => Promise<unknown>;\n }).executeAction?.(action.objectName!, action.target!, handlerCtx);\n}\n\n/**\n * Compose the HTTP body for a `type:'api'` action.\n *\n * Order of merge (last-wins):\n * 1. user-collected params (wrapped if `bodyShape.wrap` is set)\n * 2. recordId — placed flat at `recordIdParam` (using `recordIdField`\n * to pick the value off the record, defaulting to `id`)\n * 3. `bodyExtra` constants (always win)\n */\nexport function buildApiRequestBody(\n action: Action,\n args: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n recordId: string | undefined,\n): Record<string, unknown> {\n const shape = action.bodyShape;\n const wrapKey =\n shape && typeof shape === 'object' && 'wrap' in shape && typeof shape.wrap === 'string'\n ? shape.wrap\n : undefined;\n const body: Record<string, unknown> = wrapKey ? { [wrapKey]: { ...args } } : { ...args };\n\n if (action.recordIdParam) {\n const idField = action.recordIdField ?? 'id';\n const idValue = record ? record[idField] : recordId;\n if (idValue !== undefined) body[action.recordIdParam] = idValue;\n }\n\n if (action.bodyExtra && typeof action.bodyExtra === 'object') {\n Object.assign(body, action.bodyExtra as Record<string, unknown>);\n }\n return body;\n}\n\nasync function dispatchApiAction(\n action: Action,\n ctx: ActionToolsContext,\n params: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n recordId: string | undefined,\n): Promise<unknown> {\n const client =\n ctx.apiClient ??\n (ctx.apiBaseUrl\n ? createFetchApiClient({ baseUrl: ctx.apiBaseUrl, headers: ctx.apiHeaders })\n : undefined);\n if (!client) {\n throw new Error('No apiClient configured for type:\"api\" action dispatch.');\n }\n const method = (action.method ?? 'POST') as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n const body = buildApiRequestBody(action, params, record, recordId);\n return await client.request({\n url: action.target!,\n method,\n body: method === 'GET' || method === 'DELETE' ? undefined : body,\n headers: ctx.apiHeaders,\n });\n}\n\nasync function dispatchFlowAction(\n action: Action,\n ctx: ActionToolsContext,\n params: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n principal: { id: string; name?: string },\n): Promise<unknown> {\n if (!ctx.automation) {\n throw new Error('No automation service available for type:\"flow\" action dispatch.');\n }\n const result = await ctx.automation.execute(action.target!, {\n triggerData: { record, params, user: principal, action: action.name },\n } as Parameters<IAutomationService['execute']>[1]);\n if (result && typeof result === 'object' && 'success' in result && result.success === false) {\n throw new Error(\n `Flow '${action.target}' failed: ${(result as { error?: string }).error ?? 'unknown error'}`,\n );\n }\n return result;\n}\n\n/**\n * Default fetch-based {@link ApiActionClient}. Resolves relative `url`s\n * against `baseUrl`, merges static `headers`, throws on non-2xx, returns\n * the parsed JSON body (or `null` if empty).\n */\nexport function createFetchApiClient(options: {\n baseUrl?: string;\n headers?: Record<string, string>;\n fetch?: typeof fetch;\n}): ApiActionClient {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new Error('createFetchApiClient: no global fetch available; pass options.fetch.');\n }\n return {\n async request({ url, method, body, headers }) {\n const absolute = /^https?:\\/\\//.test(url) ? url : `${(options.baseUrl ?? '').replace(/\\/$/, '')}${url.startsWith('/') ? '' : '/'}${url}`;\n const res = await fetchImpl(absolute, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...(options.headers ?? {}),\n ...(headers ?? {}),\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n const text = await res.text();\n const parsed = text ? safeJsonParse(text) : null;\n if (!res.ok) {\n const msg =\n parsed && typeof parsed === 'object' && 'error' in parsed\n ? (parsed as { error: unknown }).error\n : text;\n throw new Error(`${method} ${absolute} → ${res.status}: ${typeof msg === 'string' ? msg : JSON.stringify(msg)}`);\n }\n return parsed;\n },\n };\n}\n\nfunction safeJsonParse(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return s;\n }\n}\n\n// ── Registration ──────────────────────────────────────────────────\n\n/**\n * Walk every registered object in the {@link IMetadataService}, pick out\n * each object's actions, and register the ones that pass {@link actionSkipReason}\n * as AI tools.\n *\n * Returns the list of registered tool names and a parallel list of\n * `{ action, reason }` for actions that were intentionally skipped —\n * useful for Studio's \"AI exposure\" diagnostics surface.\n */\nexport async function registerActionsAsTools(\n registry: ToolRegistry,\n context: ActionToolsContext,\n): Promise<{\n registered: string[];\n skipped: Array<{ action: string; reason: string }>;\n}> {\n const objects = (await context.metadata.listObjects()) as ObjectDef[];\n const objMap = new Map<string, ObjectDef>(\n objects.filter((o): o is ObjectDef => Boolean(o?.name)).map(o => [o.name, o]),\n );\n\n const registered: string[] = [];\n const skipped: Array<{ action: string; reason: string }> = [];\n const prefix = context.toolPrefix ?? 'action_';\n\n for (const obj of objects) {\n if (!obj?.actions || !Array.isArray(obj.actions)) continue;\n for (const action of obj.actions) {\n if (!action || typeof action.name !== 'string') continue;\n // Backfill objectName if it was elided (defineStack does this normally,\n // but be defensive when metadata comes from external sources).\n const normalized: Action = {\n ...action,\n objectName: action.objectName ?? obj.name,\n };\n\n const reason = actionSkipReason(normalized, {\n automation: context.automation,\n apiClient: context.apiClient,\n apiBaseUrl: context.apiBaseUrl,\n enableActionApproval: context.enableActionApproval,\n aiService: context.aiService,\n });\n if (reason !== null) {\n skipped.push({ action: normalized.name, reason });\n continue;\n }\n\n const definition = actionToToolDefinition(normalized, obj, objMap, prefix);\n if (!definition) continue;\n\n // Avoid colliding with already-registered tools (e.g. metadata tools).\n if (registry.has(definition.name)) {\n skipped.push({ action: normalized.name, reason: 'tool name already registered' });\n continue;\n }\n\n const handler = createActionToolHandler(normalized, context);\n registry.register(definition, handler);\n registered.push(definition.name);\n\n // Pre-register the *bypass-approval* dispatcher under the same tool\n // name so AIService.approvePendingAction can re-run the action by\n // looking up the dispatcher and invoking it with the original input.\n if (\n context.enableActionApproval &&\n actionRequiresApproval(normalized) &&\n context.aiService?.registerPendingActionDispatcher\n ) {\n // Build a parallel context with approval *disabled* so the handler\n // executes directly instead of re-queuing.\n const bypassCtx: ActionToolsContext = {\n ...context,\n enableActionApproval: false,\n };\n const directHandler = createActionToolHandler(normalized, bypassCtx);\n context.aiService.registerPendingActionDispatcher(\n definition.name,\n async (input) => {\n const raw = await directHandler(input);\n // Handlers return a JSON string envelope; parse for the\n // approval pathway so the row's `result` is structured.\n let parsed: unknown = raw;\n try {\n parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;\n } catch {\n parsed = raw;\n }\n // Surface handler-level failures as exceptions so the\n // approval row flips to `failed` (not silently `executed`).\n if (\n parsed &&\n typeof parsed === 'object' &&\n 'ok' in parsed &&\n (parsed as { ok?: unknown }).ok === false\n ) {\n const errMsg =\n (parsed as { error?: unknown }).error != null\n ? String((parsed as { error?: unknown }).error)\n : 'action handler reported failure';\n throw new Error(errMsg);\n }\n return parsed;\n },\n );\n }\n }\n }\n\n return { registered, skipped };\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, Skill } from '@objectstack/spec/ai';\nimport { AgentSchema } from '@objectstack/spec/ai';\nimport { SkillRegistry, type SkillContext } from './skill-registry.js';\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 *\n * Extends {@link SkillContext} so the same context object can drive\n * skill activation in the {@link SkillRegistry}.\n */\nexport interface AgentChatContext extends SkillContext {\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 * + active skill instructions.\n * 3. Derive {@link AIRequestOptions} from agent `model`, `tools`, and\n * resolved skills.\n * 4. Map agent tool references to concrete {@link AIToolDefinition}s\n * registered in the {@link ToolRegistry}.\n *\n * When constructed with a {@link SkillRegistry} the runtime supports\n * the Agent → Skill → Tool composition model. When the registry is\n * omitted (legacy / test mode) only the agent's inline `tools[]` are\n * used.\n */\nexport class AgentRuntime {\n constructor(\n private readonly metadataService: IMetadataService,\n private readonly skillRegistry?: SkillRegistry,\n ) {}\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 * The composed prompt has up to three sections:\n * 1. The agent's base `instructions` (its persona / prime directives).\n * 2. UI context hints from {@link AgentChatContext} (current object,\n * record, view) so the agent can tailor responses without extra\n * tool calls.\n * 3. An \"Active Skills\" block describing the capabilities currently\n * available — only populated when `activeSkills` is provided.\n */\n buildSystemMessages(\n agent: Agent,\n context?: AgentChatContext,\n activeSkills?: readonly Skill[],\n ): 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.appName) ctx.push(`Current app: ${context.appName}`);\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 // Active skill bundle\n if (activeSkills && activeSkills.length > 0 && this.skillRegistry) {\n const block = this.skillRegistry.composeInstructionsBlock(activeSkills);\n if (block) parts.push(block);\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 * Tools belonging to `activeSkills` are also resolved and merged into\n * the final tool list (deduplicated by name).\n *\n * Any unresolved references (tools the agent or skill declares but\n * that are not registered) are silently skipped — this is intentional\n * so that agents/skills 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 * @param activeSkills - Skills resolved from agent.skills[] + context filtering\n * @returns Request options with model config and resolved tool definitions\n */\n buildRequestOptions(\n agent: Agent,\n availableTools: readonly AIToolDefinition[],\n activeSkills?: readonly Skill[],\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 const toolMap = new Map(availableTools.map((t) => [t.name, t]));\n const seen = new Set<string>();\n const resolved: AIToolDefinition[] = [];\n\n if (agent.tools && agent.tools.length > 0) {\n for (const ref of agent.tools) {\n if (seen.has(ref.name)) continue;\n const def = toolMap.get(ref.name);\n if (def) {\n resolved.push(def);\n seen.add(ref.name);\n }\n }\n }\n\n // Merge skill tools (deduplicated)\n if (activeSkills && activeSkills.length > 0 && this.skillRegistry) {\n const skillTools = this.skillRegistry.flattenToTools(activeSkills, availableTools);\n for (const def of skillTools) {\n if (seen.has(def.name)) continue;\n resolved.push(def);\n seen.add(def.name);\n }\n }\n\n if (resolved.length > 0) {\n options.tools = resolved;\n options.toolChoice = 'auto';\n }\n\n return options;\n }\n\n // ── Skill resolution helpers ─────────────────────────────────\n\n /**\n * Resolve the set of skills active for a given agent in a given\n * context. Combines:\n *\n * 1. The agent's declared `skills[]` whitelist (if any).\n * 2. Filtering by `triggerConditions` against the runtime context.\n *\n * When the agent declares no skills, returns the empty list (i.e.\n * the agent only uses its inline `tools[]`).\n *\n * Returns an empty array if no SkillRegistry was provided to the\n * runtime (legacy mode).\n */\n async resolveActiveSkills(agent: Agent, context?: AgentChatContext): Promise<Skill[]> {\n if (!this.skillRegistry) return [];\n if (!agent.skills || agent.skills.length === 0) return [];\n return this.skillRegistry.listActiveSkills(context ?? {}, agent.skills);\n }\n\n /**\n * Pick a default agent for the given context, used by the ambient\n * chat endpoint when the client doesn't specify an `agentName`.\n *\n * Resolution order:\n * 1. The `defaultAgent` of the app named by `context.appName`.\n * 2. The first active agent in the registry (deterministic fallback).\n * 3. `undefined` if no agents are registered.\n */\n async resolveDefaultAgent(context?: AgentChatContext): Promise<Agent | undefined> {\n if (context?.appName) {\n const rawApp = await this.metadataService.get('app', context.appName).catch(() => undefined);\n const defaultAgentName = (rawApp as { defaultAgent?: string } | undefined)?.defaultAgent;\n if (defaultAgentName) {\n const agent = await this.loadAgent(defaultAgentName);\n if (agent && agent.active !== false) return agent;\n }\n }\n\n // Fallback: first active agent in declaration order.\n const summaries = await this.listAgents();\n if (summaries.length === 0) return undefined;\n return this.loadAgent(summaries[0].name);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { AIToolDefinition, IMetadataService } from '@objectstack/spec/contracts';\nimport type { Skill, SkillTriggerCondition } from '@objectstack/spec/ai';\nimport { SkillSchema } from '@objectstack/spec/ai';\n\n/**\n * Runtime context passed when chatting with the ambient assistant.\n *\n * Mirrors the metadata fields used by `Skill.triggerConditions` so that\n * skills can be activated declaratively based on what the user is doing.\n *\n * UI clients populate this from the current route / selected record.\n */\nexport interface SkillContext {\n /** Application the user is currently inside (e.g. \"crm\"). */\n appName?: string;\n /** Object the user is viewing (e.g. \"lead\"). */\n objectName?: string;\n /** Currently selected record ID. */\n recordId?: string;\n /** Current view name. */\n viewName?: string;\n /** Channel/medium of the conversation (e.g. \"web\", \"slack\", \"email\"). */\n channel?: string;\n /** User's role (used by `triggerConditions` with `field=userRole`). */\n userRole?: string;\n /** Free-form additional context fields evaluated against `triggerConditions`. */\n [extraField: string]: unknown;\n}\n\n/**\n * Summary of an active skill suitable for slash-command palettes\n * and `GET /api/v1/ai/skills` responses.\n */\nexport interface SkillSummary {\n name: string;\n label: string;\n description?: string;\n triggerPhrases?: string[];\n toolCount: number;\n}\n\n/**\n * SkillRegistry — Loads and resolves AI Skill metadata.\n *\n * Responsibilities:\n * 1. Load & validate skill definitions from {@link IMetadataService}.\n * 2. Filter by runtime context using `triggerConditions`.\n * 3. Flatten skill `tools[]` references to concrete {@link AIToolDefinition}s.\n * 4. Compose skill `instructions` for system-prompt injection.\n *\n * The registry is stateless; every call re-reads from the metadata\n * service so changes published at runtime become immediately visible.\n *\n * @example\n * ```ts\n * const registry = new SkillRegistry(metadataService);\n * const active = await registry.listActiveSkills({ appName: 'crm', objectName: 'lead' });\n * const tools = registry.flattenToTools(active, allTools);\n * ```\n */\nexport class SkillRegistry {\n constructor(private readonly metadataService: IMetadataService) {}\n\n // ── Loading ────────────────────────────────────────────────────\n\n /**\n * Load and validate a single skill definition by name.\n *\n * Returns `undefined` when the skill is missing or fails Zod\n * validation (so callers don't accidentally feed malformed metadata\n * to the LLM).\n */\n async loadSkill(skillName: string): Promise<Skill | undefined> {\n const raw = await this.metadataService.get('skill', skillName);\n if (!raw) return undefined;\n\n const result = SkillSchema.safeParse(raw);\n if (!result.success) return undefined;\n return result.data;\n }\n\n /**\n * Load all skill definitions, dropping any that fail validation\n * or are explicitly inactive.\n */\n async listSkills(): Promise<Skill[]> {\n const raw = await this.metadataService.list('skill');\n const skills: Skill[] = [];\n for (const item of raw) {\n const result = SkillSchema.safeParse(item);\n if (result.success && result.data.active !== false) {\n skills.push(result.data);\n }\n }\n return skills;\n }\n\n /**\n * Load only the skills referenced by `skillNames`, preserving\n * declaration order. Missing or invalid skill names are silently\n * dropped (logged at the route layer if needed) so an Agent can be\n * defined before all its skills are persisted.\n */\n async loadSkills(skillNames: readonly string[]): Promise<Skill[]> {\n const skills: Skill[] = [];\n for (const name of skillNames) {\n const skill = await this.loadSkill(name);\n if (skill && skill.active !== false) {\n skills.push(skill);\n }\n }\n return skills;\n }\n\n // ── Context filtering ──────────────────────────────────────────\n\n /**\n * Return skills whose `triggerConditions` are satisfied by the\n * given context. Skills without any conditions are always considered\n * active and returned in their declaration order.\n *\n * If `restrictTo` is provided, the result is intersected with that\n * allow-list (typically the agent's `skills[]` field) so an agent\n * never sees skills outside its declared scope.\n */\n async listActiveSkills(\n context: SkillContext = {},\n restrictTo?: readonly string[],\n ): Promise<Skill[]> {\n const allowList = restrictTo ? new Set(restrictTo) : undefined;\n const all = await this.listSkills();\n return all.filter((skill) => {\n if (allowList && !allowList.has(skill.name)) return false;\n return this.matchesContext(skill, context);\n });\n }\n\n /**\n * Evaluate a skill's `triggerConditions` against the given context.\n *\n * Semantics:\n * - No conditions defined → always matches.\n * - All conditions must pass (logical AND).\n * - Operators: `eq`, `neq`, `in`, `not_in`, `contains`.\n * - `contains` does substring matching for strings and `Array.includes`\n * for arrays.\n * - Missing context fields fail unless the operator is `neq` /\n * `not_in` (treating \"absent\" as \"not equal to anything\").\n */\n matchesContext(skill: Skill, context: SkillContext): boolean {\n const conditions = skill.triggerConditions;\n if (!conditions || conditions.length === 0) return true;\n return conditions.every((cond) => this.evaluateCondition(cond, context));\n }\n\n private evaluateCondition(cond: SkillTriggerCondition, context: SkillContext): boolean {\n const fieldValue = context[cond.field];\n const expected = cond.value;\n\n switch (cond.operator) {\n case 'eq':\n return fieldValue === expected;\n case 'neq':\n return fieldValue !== expected;\n case 'in': {\n const list = Array.isArray(expected) ? expected : [expected];\n return list.includes(fieldValue as string);\n }\n case 'not_in': {\n const list = Array.isArray(expected) ? expected : [expected];\n return !list.includes(fieldValue as string);\n }\n case 'contains': {\n if (typeof fieldValue === 'string' && typeof expected === 'string') {\n return fieldValue.includes(expected);\n }\n if (Array.isArray(fieldValue)) {\n return Array.isArray(expected)\n ? expected.every((v) => fieldValue.includes(v))\n : fieldValue.includes(expected as string);\n }\n return false;\n }\n default:\n return false;\n }\n }\n\n // ── Tool resolution ───────────────────────────────────────────\n\n /**\n * Flatten a list of skills to a deduplicated array of concrete tool\n * definitions, preserving the order skills declared their tools.\n *\n * Tools that are declared by a skill but missing from the available\n * tool registry are silently dropped — this is intentional so a skill\n * can be authored before all its underlying tools are registered.\n */\n flattenToTools(skills: readonly Skill[], availableTools: readonly AIToolDefinition[]): AIToolDefinition[] {\n const toolMap = new Map(availableTools.map((t) => [t.name, t]));\n const seen = new Set<string>();\n const resolved: AIToolDefinition[] = [];\n for (const skill of skills) {\n for (const toolName of skill.tools) {\n // Support trailing-wildcard patterns like `action_*` so a skill\n // can subscribe to a *family* of dynamically registered tools\n // (built-in `actions_executor` uses this for the `action_<name>`\n // tools materialised from each object's declarative Action list).\n if (toolName.endsWith('*')) {\n const prefix = toolName.slice(0, -1);\n for (const def of availableTools) {\n if (!def.name.startsWith(prefix)) continue;\n if (seen.has(def.name)) continue;\n resolved.push(def);\n seen.add(def.name);\n }\n continue;\n }\n if (seen.has(toolName)) continue;\n const def = toolMap.get(toolName);\n if (def) {\n resolved.push(def);\n seen.add(toolName);\n }\n }\n }\n return resolved;\n }\n\n // ── System-prompt composition ─────────────────────────────────\n\n /**\n * Build the \"Active Skills\" block to append to an agent's system\n * prompt. The block lists each skill's label + instructions so the\n * LLM knows which capabilities are available and how to invoke them.\n *\n * Returns an empty string when there are no skills, so the caller\n * can safely concatenate without producing dangling whitespace.\n */\n composeInstructionsBlock(skills: readonly Skill[]): string {\n if (skills.length === 0) return '';\n\n const lines: string[] = ['', '--- Active Skills ---'];\n for (const skill of skills) {\n lines.push(`\\n### ${skill.label} (${skill.name})`);\n if (skill.description) lines.push(skill.description);\n if (skill.instructions) lines.push(skill.instructions);\n if (skill.tools.length > 0) {\n lines.push(`Tools: ${skill.tools.join(', ')}`);\n }\n }\n return lines.join('\\n');\n }\n\n /**\n * Project a skill to a wire-friendly summary suitable for the\n * `/api/v1/ai/skills` endpoint and slash-command palettes.\n */\n toSummary(skill: Skill): SkillSummary {\n return {\n name: skill.name,\n label: skill.label,\n description: skill.description,\n triggerPhrases: skill.triggerPhrases,\n toolCount: skill.tools.length,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Agent } from '@objectstack/spec/ai';\n\n/**\n * Built-in `data_chat` agent — a thin **persona** record.\n *\n * Following the platform's metadata-driven philosophy, this agent no\n * longer hardcodes the tools it can call. The capability bundle lives\n * on the `data_explorer` *skill* (see `../skills/data-explorer-skill.ts`).\n * The agent record is now just:\n * - identity (name / label / role)\n * - persona (system prompt)\n * - model + safety config\n * - skills attached → `skills: ['data_explorer']`\n *\n * To grant data-exploration powers to a different agent, just add\n * `data_explorer` to its `skills[]`. To revoke globally, set the\n * skill's `active: false` in metadata.\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\nAlways answer in the same language the user is using. Detailed tool-usage guidance is supplied by the skills attached to this agent.`,\n\n model: {\n provider: 'openai',\n model: 'gpt-4',\n temperature: 0.3,\n maxTokens: 4096,\n },\n\n // Capability bundle lives on the skill; the agent only references it.\n // `data_explorer` = read side, `actions_executor` = write side.\n skills: ['data_explorer', 'actions_executor'],\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\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Agent } from '@objectstack/spec/ai';\n\n/**\n * Built-in `metadata_assistant` agent — a thin **persona** record.\n *\n * Capability bundle is no longer hardcoded here; it lives on the\n * `metadata_authoring` *skill* (see\n * `../skills/metadata-authoring-skill.ts`). Studio's Universal\n * Assistant pins this agent via `?agent=metadata_assistant` because\n * Studio is a metadata-authoring host.\n *\n * To extend this agent (e.g. give it data-exploration too), just add\n * the skill name: `skills: ['metadata_authoring', 'data_explorer']`.\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\nAlways answer in the same language the user is using. If the user's request is ambiguous, ask clarifying questions before proceeding. Detailed tool-usage guidance is supplied by the skills attached to this agent.`,\n\n model: {\n provider: 'openai',\n model: 'gpt-4',\n temperature: 0.2,\n maxTokens: 4096,\n },\n\n // Capability bundle lives on the skill; the agent only references it.\n skills: ['metadata_authoring'],\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\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Skill } from '@objectstack/spec/ai';\n\n/**\n * Built-in `data_explorer` skill — the read-only data-Q&A capability\n * bundle that the `data_chat` agent (and any other agent that wants\n * data-exploration powers) attaches to its `skills[]`.\n *\n * Following the platform's metadata-driven philosophy, the agent\n * itself no longer hardcodes which tools it can call; instead it\n * names this skill and the SkillRegistry resolves the tool list at\n * request time. Disabling this skill via the metadata service\n * disables data exploration for every agent that references it,\n * without code changes.\n */\nexport const DATA_EXPLORER_SKILL: Skill = {\n name: 'data_explorer',\n label: 'Data Explorer',\n description: 'Read-only Q&A over the user\\'s business data — schema discovery, filtered queries, lookups, and aggregations.',\n instructions: `You can explore the user's business data through these tools.\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 tools: [\n 'query_data',\n 'list_objects',\n 'describe_object',\n 'query_records',\n 'get_record',\n 'aggregate_data',\n ],\n triggerPhrases: [\n 'show me',\n 'list',\n 'how many',\n 'count',\n 'find records',\n 'query',\n 'aggregate',\n 'sum',\n 'average',\n ],\n active: true,\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Skill } from '@objectstack/spec/ai';\n\n/**\n * Built-in `metadata_authoring` skill — the write-side schema-design\n * capability bundle attached to the `metadata_assistant` agent (and\n * any other agent that should be allowed to mutate schema).\n *\n * Splitting this off from the agent record lets us:\n * - Reuse the same authoring tools across multiple agent personas\n * (e.g. an \"ops bot\" that ALSO can author).\n * - Disable authoring globally by setting `active: false` on the\n * skill metadata, without redeploying the agent.\n * - Layer permissions via `Skill.permissions` independent of the\n * agent's permissions.\n */\nexport const METADATA_AUTHORING_SKILL: Skill = {\n name: 'metadata_authoring',\n label: 'Metadata Authoring',\n description: 'Create and modify ObjectStack metadata — objects, fields, schema changes through natural language.',\n instructions: `You are an expert metadata architect. When the user asks you to design or change a data model, use these tools.\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_objects to check if a similar one already exists.\n2. Before modifying or deleting fields, use describe_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 tools: [\n 'create_object',\n 'add_field',\n 'modify_field',\n 'delete_field',\n 'list_objects',\n 'describe_object',\n ],\n triggerPhrases: [\n 'create object',\n 'create table',\n 'add field',\n 'add column',\n 'modify field',\n 'change field',\n 'delete field',\n 'drop field',\n 'design schema',\n 'new entity',\n ],\n active: true,\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Skill } from '@objectstack/spec/ai';\n\n/**\n * Built-in `actions_executor` skill — the write-side counterpart to\n * `data_explorer`.\n *\n * Where `data_explorer` lets an agent **answer** questions about the\n * user's data, `actions_executor` lets the same agent **perform**\n * business operations: complete tasks, start workflows, send invites,\n * etc. The concrete tools are not enumerated here — they're materialised\n * at runtime from every `Action` declared on every object the metadata\n * service knows about (see `registerActionsAsTools` in\n * `tools/action-tools.ts`). The skill records the *intent* (\"agent may\n * invoke business actions\"); the registry expands it into actual tools\n * after metadata is loaded.\n *\n * The `tools` array is intentionally empty — Phase 1 lets the\n * skill-registry resolver fall through to the global tool list when an\n * agent's skill bundle would otherwise filter out the dynamically\n * registered `action_*` tools. Skills that want to restrict the set\n * should be authored project-side with the specific `action_<name>`\n * tools they want to expose.\n */\nexport const ACTIONS_EXECUTOR_SKILL: Skill = {\n name: 'actions_executor',\n label: 'Action Executor',\n description:\n \"Perform business operations on the user's data — invoke actions like \" +\n \"'mark as complete', 'start task', 'clone record' through natural language.\",\n instructions: `You can perform business operations by invoking the user's registered actions.\n\nCapabilities:\n- Each tool whose name starts with \\`action_\\` is a business operation declared on an object.\n- Read the tool description carefully — it tells you what the action does and what record types it applies to.\n- Most actions need a \\`recordId\\` argument. If you don't already have one from a prior \\`query_data\\` call, run \\`query_data\\` first to find the right record, then invoke the action with its id.\n\nGuidelines:\n1. Confirm intent — when the user says \"complete it\" / \"start that one\", make sure you know *which* record they mean. Ask if ambiguous.\n2. Use \\`query_data\\` to look up records by natural-language description (\"the design review task\", \"tickets assigned to me\").\n3. After invoking an action, the tool returns \\`{ ok, message, result }\\`. Summarise success in plain language; surface errors verbatim.\n4. Never invent recordIds. If \\`query_data\\` didn't return one, tell the user instead of guessing.\n5. Action tools are pre-filtered for safety — destructive operations (\\`mode: 'delete'\\`, \\`variant: 'danger'\\`, anything with \\`confirmText\\`) are *not* exposed here and require explicit user confirmation in the UI.\n6. Always answer in the same language the user is using.`,\n // Dynamically materialised: the runtime registers one tool per Action,\n // and the skill subscribes to the whole family via the `action_*`\n // glob (resolved by SkillRegistry.flattenToTools).\n tools: ['action_*'],\n triggerPhrases: [\n 'complete',\n 'mark as',\n 'start',\n 'finish',\n 'clone',\n 'duplicate',\n 'do it',\n 'run',\n 'invoke',\n 'execute',\n ],\n active: true,\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 AIObjectResult,\n GenerateObjectOptions,\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 type { z } from 'zod';\nimport { generateText, streamText, generateObject, 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 try {\n for await (const part of result.fullStream) {\n yield part as TextStreamPart<ToolSet>;\n }\n } catch (err) {\n // Convert provider errors into a typed `error` part so the encoder can\n // surface them to the client instead of leaving the SSE stream open.\n yield {\n type: 'error',\n error: err instanceof Error ? err : new Error(String(err)),\n } as unknown 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 generateObject<T>(\n messages: ModelMessage[],\n schema: z.ZodType<T>,\n options?: GenerateObjectOptions,\n ): Promise<AIObjectResult<T>> {\n const { schemaName, schemaDescription, ...rest } = options ?? {};\n const result = await generateObject({\n model: this.model,\n messages,\n schema,\n schemaName,\n schemaDescription,\n ...buildVercelOptions(rest),\n });\n\n return {\n object: result.object as T,\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 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 * as AI from '@objectstack/spec/ai';\n\n/**\n * ModelRegistry — In-memory runtime registry for AI models.\n *\n * Provides:\n * - Model lookup by id\n * - Default model resolution\n * - Token-based cost estimation\n *\n * Populated from `objectstack.config.ts` at boot. Pure in-memory by design —\n * suitable for serverless / edge runtimes. Persistent registries should be\n * implemented as a wrapper that hydrates this registry at start time.\n *\n * @example\n * ```ts\n * const registry = new ModelRegistry({\n * models: [{\n * id: 'gpt-4o',\n * name: 'GPT-4o',\n * version: '2024-08-06',\n * provider: 'openai',\n * capabilities: { textGeneration: true, functionCalling: true },\n * limits: { maxTokens: 128000, contextWindow: 128000 },\n * pricing: { inputCostPer1kTokens: 0.0025, outputCostPer1kTokens: 0.01 },\n * }],\n * defaultModelId: 'gpt-4o',\n * });\n * const cost = registry.estimateCost('gpt-4o', { promptTokens: 1000, completionTokens: 500 });\n * ```\n */\nexport class ModelRegistry {\n private readonly models = new Map<string, AI.ModelConfig>();\n private defaultModelId?: string;\n\n constructor(config: ModelRegistryConfig = {}) {\n for (const model of config.models ?? []) {\n this.models.set(model.id, model);\n }\n this.defaultModelId = config.defaultModelId;\n }\n\n /** Register or replace a model. */\n register(model: AI.ModelConfig): void {\n this.models.set(model.id, model);\n }\n\n /** Look up a model by id. */\n get(id: string): AI.ModelConfig | undefined {\n return this.models.get(id);\n }\n\n /** Look up a model by id, throwing if missing. */\n getOrThrow(id: string): AI.ModelConfig {\n const model = this.models.get(id);\n if (!model) {\n throw new Error(\n `[ModelRegistry] Unknown model \"${id}\". Registered: ${\n [...this.models.keys()].join(', ') || '(none)'\n }`,\n );\n }\n return model;\n }\n\n /** Resolve the default model (explicit > first registered > undefined). */\n getDefault(): AI.ModelConfig | undefined {\n if (this.defaultModelId) {\n return this.models.get(this.defaultModelId);\n }\n return this.models.values().next().value;\n }\n\n /** Set the default model id (must already be registered). */\n setDefault(id: string): void {\n this.getOrThrow(id);\n this.defaultModelId = id;\n }\n\n /** All registered models. */\n list(): AI.ModelConfig[] {\n return [...this.models.values()];\n }\n\n /** Number of registered models. */\n get size(): number {\n return this.models.size;\n }\n\n /**\n * Estimate cost in the model's currency (defaults to USD).\n *\n * Returns `undefined` when the model is unknown or has no pricing data.\n * Costs are computed as `(tokens / 1000) * pricePer1kTokens` for input and\n * output independently, then summed.\n */\n estimateCost(modelId: string, usage: TokenUsage): CostEstimate | undefined {\n const model = this.models.get(modelId);\n if (!model?.pricing) return undefined;\n return computeCost(model.pricing, usage);\n }\n}\n\n/** Token usage shape (mirrors `AIResult['usage']`). */\nexport interface TokenUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens?: number;\n}\n\n/** Cost estimate returned by {@link ModelRegistry.estimateCost}. */\nexport interface CostEstimate {\n /** Cost attributable to prompt/input tokens. */\n inputCost: number;\n /** Cost attributable to completion/output tokens. */\n outputCost: number;\n /** `inputCost + outputCost`. */\n totalCost: number;\n /** ISO 4217 currency code. */\n currency: string;\n}\n\n/** Configuration for {@link ModelRegistry}. */\nexport interface ModelRegistryConfig {\n /** Models to register at construction. */\n models?: AI.ModelConfig[];\n /** Default model id (must appear in `models`). */\n defaultModelId?: string;\n}\n\n/**\n * Compute cost from pricing + usage. Exported for direct use when a registry\n * is not in scope (e.g. tests or one-off calculations).\n */\nexport function computeCost(pricing: AI.ModelPricing, usage: TokenUsage): CostEstimate {\n const inputCost =\n pricing.inputCostPer1kTokens != null\n ? (usage.promptTokens / 1000) * pricing.inputCostPer1kTokens\n : 0;\n const outputCost =\n pricing.outputCostPer1kTokens != null\n ? (usage.completionTokens / 1000) * pricing.outputCostPer1kTokens\n : 0;\n return {\n inputCost,\n outputCost,\n totalCost: inputCost + outputCost,\n currency: pricing.currency ?? 'USD',\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIToolDefinition,\n IKnowledgeService,\n KnowledgeSearchOptions,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport type {\n ToolHandler,\n ToolExecutionContext,\n ToolRegistry,\n} from './tool-registry.js';\n\n/**\n * Services required by the knowledge tool family.\n */\nexport interface KnowledgeToolContext {\n /** Orchestrator that resolves adapters and applies permission filtering. */\n knowledgeService: IKnowledgeService;\n}\n\n/**\n * Default cap on `topK` when callers omit it or supply something silly.\n * Adapters and the orchestrator may cap further.\n */\nconst DEFAULT_TOP_K = 5;\nconst MAX_TOP_K = 20;\n\n/**\n * Translate a {@link ToolExecutionContext} into the\n * {@link ExecutionContext} that `IKnowledgeService.search` expects.\n *\n * Mirrors the convention used by the data tools: when the AI tool call\n * carries an authenticated actor, RLS is enforced; otherwise we fall\n * back to a system context so legacy / internal callers continue to\n * work unchanged.\n */\nfunction buildEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\n}\n\nexport const SEARCH_KNOWLEDGE_TOOL: AIToolDefinition = {\n name: 'search_knowledge',\n description:\n 'Search registered knowledge sources (object snapshots, uploaded files, ' +\n 'external URLs) and return the most relevant excerpts. ' +\n 'Use this when the user asks a question whose answer is in documents, ' +\n 'policies, or reference material the LLM does not natively know. ' +\n 'Results are already permission-filtered for the current user.',\n parameters: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Free-text question or keywords to search for.',\n },\n sourceIds: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional list of source ids to restrict the search to. ' +\n 'When omitted, every source the caller can see is queried.',\n },\n topK: {\n type: 'number',\n description: `Maximum hits to return (default ${DEFAULT_TOP_K}, max ${MAX_TOP_K}).`,\n },\n filter: {\n type: 'object',\n description:\n 'Optional adapter-specific metadata filter (e.g. {\"topic\":\"refunds\"}).',\n },\n },\n required: ['query'],\n },\n};\n\nfunction createSearchKnowledgeHandler(context: KnowledgeToolContext): ToolHandler {\n return async (args, ctx) => {\n const query = typeof args.query === 'string' ? args.query.trim() : '';\n if (!query) {\n return JSON.stringify({ error: 'search_knowledge: `query` is required.' });\n }\n\n const sourceIds = Array.isArray(args.sourceIds)\n ? args.sourceIds.filter((x): x is string => typeof x === 'string')\n : undefined;\n const topKRaw = typeof args.topK === 'number' ? args.topK : DEFAULT_TOP_K;\n const topK = Math.max(1, Math.min(MAX_TOP_K, Math.floor(topKRaw)));\n const filter =\n args.filter && typeof args.filter === 'object' && !Array.isArray(args.filter)\n ? (args.filter as Record<string, unknown>)\n : undefined;\n\n const opts: KnowledgeSearchOptions = {\n topK,\n executionContext: buildEngineContext(ctx),\n };\n if (sourceIds && sourceIds.length > 0) opts.sourceIds = sourceIds;\n if (filter) opts.filter = filter;\n\n try {\n const hits = await context.knowledgeService.search(query, opts);\n return JSON.stringify({\n query,\n count: hits.length,\n hits: hits.map((h) => ({\n documentId: h.documentId,\n chunkId: h.chunkId,\n sourceId: h.sourceId,\n sourceRecordId: h.sourceRecordId,\n score: Number(h.score?.toFixed?.(4) ?? h.score ?? 0),\n title: h.title,\n snippet: h.snippet,\n metadata: h.metadata,\n })),\n });\n } catch (err) {\n return JSON.stringify({\n error: `search_knowledge failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n };\n}\n\n/**\n * Register knowledge-related tools on the AI tool registry.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const knowledgeService = ctx.getService<IKnowledgeService>('knowledge');\n * registerKnowledgeTools(aiService.toolRegistry, { knowledgeService });\n * });\n * ```\n */\nexport function registerKnowledgeTools(\n registry: ToolRegistry,\n context: KnowledgeToolContext,\n): void {\n registry.register(SEARCH_KNOWLEDGE_TOOL, createSearchKnowledgeHandler(context));\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * list_packages — AI Tool Metadata\n *\n * Lists all installed packages in the ObjectStack instance.\n * Useful for understanding what packages are available before creating metadata.\n */\nexport const listPackagesTool = defineTool({\n name: 'list_packages',\n label: 'List Packages',\n description:\n 'Lists all installed packages in the system. Use this to see what packages are available ' +\n 'before creating or modifying metadata. Packages are the containers that hold metadata.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n status: {\n type: 'string',\n description: 'Filter by package status',\n enum: ['installed', 'disabled', 'installing', 'upgrading', 'uninstalling', 'error'],\n },\n enabled: {\n type: 'boolean',\n description: 'Filter by enabled state (true = only enabled, false = only disabled)',\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 * get_package — AI Tool Metadata\n *\n * Gets detailed information about a specific package.\n */\nexport const getPackageTool = defineTool({\n name: 'get_package',\n label: 'Get Package',\n description:\n 'Gets detailed information about a specific installed package, including its manifest, ' +\n 'metadata, and installation status.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n packageId: {\n type: 'string',\n description: 'Package identifier (reverse domain notation, e.g., com.acme.crm)',\n },\n },\n required: ['packageId'],\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 * create_package — AI Tool Metadata\n *\n * Creates a new package for organizing metadata.\n * All metadata (objects, views, flows, etc.) should belong to a package.\n */\nexport const createPackageTool = defineTool({\n name: 'create_package',\n label: 'Create Package',\n description:\n 'Creates a new package (metadata container) with the specified manifest. ' +\n 'All metadata in ObjectStack should belong to a package. Use this when starting new development ' +\n 'or when the user wants to organize their metadata into a new module.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Package identifier in reverse domain notation (e.g., com.acme.crm, org.mycompany.sales)',\n },\n name: {\n type: 'string',\n description: 'Human-readable package name (e.g., \"CRM Application\", \"Sales Module\")',\n },\n version: {\n type: 'string',\n description: 'Semantic version (e.g., \"1.0.0\")',\n default: '1.0.0',\n },\n description: {\n type: 'string',\n description: 'Brief description of what this package provides',\n },\n namespace: {\n type: 'string',\n description: 'Namespace prefix for metadata (snake_case, e.g., crm, sales). If not provided, derived from package ID.',\n },\n type: {\n type: 'string',\n description: 'Package type',\n enum: ['application', 'plugin', 'library', 'template'],\n default: 'application',\n },\n },\n required: ['id', 'name'],\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 * get_active_package — AI Tool Metadata\n *\n * Gets the currently active package in the conversation context.\n */\nexport const getActivePackageTool = defineTool({\n name: 'get_active_package',\n label: 'Get Active Package',\n description:\n 'Gets the currently active package in this conversation. The active package determines ' +\n 'where new metadata will be created. Returns null if no package is set.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {},\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 * set_active_package — AI Tool Metadata\n *\n * Sets the active package for the current conversation.\n * All metadata operations will use this package context.\n */\nexport const setActivePackageTool = defineTool({\n name: 'set_active_package',\n label: 'Set Active Package',\n description:\n 'Sets the active package for this conversation. All subsequent metadata creation operations ' +\n '(objects, views, flows, etc.) will be associated with this package unless explicitly overridden.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n packageId: {\n type: 'string',\n description: 'Package identifier to set as active (e.g., com.acme.crm)',\n },\n },\n required: ['packageId'],\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Tool } from '@objectstack/spec/ai';\nimport type { InstalledPackage } from '@objectstack/spec/kernel';\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 { listPackagesTool } from './list-packages.tool.js';\nexport { getPackageTool } from './get-package.tool.js';\nexport { createPackageTool } from './create-package.tool.js';\nexport { getActivePackageTool } from './get-active-package.tool.js';\nexport { setActivePackageTool } from './set-active-package.tool.js';\n\nimport { listPackagesTool } from './list-packages.tool.js';\nimport { getPackageTool } from './get-package.tool.js';\nimport { createPackageTool } from './create-package.tool.js';\nimport { getActivePackageTool } from './get-active-package.tool.js';\nimport { setActivePackageTool } from './set-active-package.tool.js';\n\n/** All built-in package management tool definitions (Tool metadata). */\nexport const PACKAGE_TOOL_DEFINITIONS: Tool[] = [\n listPackagesTool,\n getPackageTool,\n createPackageTool,\n getActivePackageTool,\n setActivePackageTool,\n];\n\n// ---------------------------------------------------------------------------\n// Package Registry Interface (minimal contract for package operations)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal package registry interface for tool operations.\n * The actual implementation may be a full PackageRegistry service.\n */\nexport interface IPackageRegistry {\n /** List all installed packages */\n list(filter?: { status?: string; enabled?: boolean }): Promise<InstalledPackage[]>;\n\n /** Get a specific package by ID */\n get(packageId: string): Promise<InstalledPackage | undefined>;\n\n /** Install a new package */\n install(manifest: Record<string, unknown>): Promise<InstalledPackage>;\n\n /** Check if a package exists */\n exists(packageId: string): Promise<boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// Conversation Service Interface (for tracking active package)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal conversation service interface for context management.\n */\nexport interface IConversationService {\n /** Get conversation metadata */\n getMetadata?(conversationId: string): Promise<Record<string, unknown> | undefined>;\n\n /** Update conversation metadata */\n updateMetadata?(conversationId: string, metadata: Record<string, unknown>): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Context — injected once at registration time\n// ---------------------------------------------------------------------------\n\n/**\n * Services required by the package 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 PackageToolContext {\n /** Package registry for package CRUD operations */\n packageRegistry: IPackageRegistry;\n\n /** Conversation service for tracking active package context (optional) */\n conversationService?: IConversationService;\n\n /** Current conversation ID (if in a conversation context) */\n conversationId?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Shared validation helpers\n// ---------------------------------------------------------------------------\n\n/** Reverse domain notation pattern (e.g. com.acme.crm). */\nconst REVERSE_DOMAIN_RE = /^[a-z][a-z0-9]*(\\.[a-z][a-z0-9]*)+$/;\n\n/** snake_case identifier pattern. */\nconst SNAKE_CASE_RE = /^[a-z_][a-z0-9_]*$/;\n\n/** Semantic version pattern. */\nconst SEMVER_RE = /^\\d+\\.\\d+\\.\\d+(-[a-z0-9]+(\\.[a-z0-9]+)*)?$/;\n\n/**\n * Validate that a value matches reverse domain notation.\n */\nfunction isReverseDomain(value: string): boolean {\n return REVERSE_DOMAIN_RE.test(value);\n}\n\n/**\n * Validate that a value matches snake_case.\n */\nfunction isSnakeCase(value: string): boolean {\n return SNAKE_CASE_RE.test(value);\n}\n\n/**\n * Validate semantic version.\n */\nfunction isSemVer(value: string): boolean {\n return SEMVER_RE.test(value);\n}\n\n/**\n * Derive namespace from package ID.\n * Example: \"com.acme.crm\" -> \"crm\"\n */\nfunction deriveNamespace(packageId: string): string {\n const parts = packageId.split('.');\n return parts[parts.length - 1];\n}\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createListPackagesHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { status, enabled } = (args ?? {}) as {\n status?: string;\n enabled?: boolean;\n };\n\n const filter: { status?: string; enabled?: boolean } = {};\n if (status) filter.status = status;\n if (enabled !== undefined) filter.enabled = enabled;\n\n const packages = await ctx.packageRegistry.list(filter);\n\n const result = packages.map(pkg => ({\n id: pkg.manifest.id,\n name: pkg.manifest.name,\n version: pkg.manifest.version,\n type: pkg.manifest.type,\n status: pkg.status,\n enabled: pkg.enabled,\n installedAt: pkg.installedAt,\n description: pkg.manifest.description,\n }));\n\n return JSON.stringify({\n packages: result,\n total: result.length,\n });\n };\n}\n\nfunction createGetPackageHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { packageId } = args as { packageId: string };\n\n if (!packageId) {\n return JSON.stringify({ error: 'packageId is required' });\n }\n\n const pkg = await ctx.packageRegistry.get(packageId);\n\n if (!pkg) {\n return JSON.stringify({ error: `Package \"${packageId}\" not found` });\n }\n\n return JSON.stringify({\n id: pkg.manifest.id,\n name: pkg.manifest.name,\n version: pkg.manifest.version,\n type: pkg.manifest.type,\n status: pkg.status,\n enabled: pkg.enabled,\n installedAt: pkg.installedAt,\n updatedAt: pkg.updatedAt,\n description: pkg.manifest.description,\n namespace: pkg.manifest.namespace,\n dependencies: pkg.manifest.dependencies,\n registeredNamespaces: pkg.registeredNamespaces,\n });\n };\n}\n\nfunction createCreatePackageHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { id, name, version = '1.0.0', description, namespace, type = 'application' } = args as {\n id: string;\n name: string;\n version?: string;\n description?: string;\n namespace?: string;\n type?: string;\n };\n\n // Validate required fields\n if (!id || !name) {\n return JSON.stringify({ error: 'Both \"id\" and \"name\" are required' });\n }\n\n // Validate package ID format (reverse domain notation)\n if (!isReverseDomain(id)) {\n return JSON.stringify({\n error: `Invalid package ID \"${id}\". Must be in reverse domain notation (e.g., com.acme.crm, org.mycompany.sales)`,\n });\n }\n\n // Validate version format\n if (!isSemVer(version)) {\n return JSON.stringify({\n error: `Invalid version \"${version}\". Must be semantic version (e.g., 1.0.0, 2.1.3-beta)`,\n });\n }\n\n // Check if package already exists\n const exists = await ctx.packageRegistry.exists(id);\n if (exists) {\n return JSON.stringify({ error: `Package \"${id}\" already exists` });\n }\n\n // Derive or validate namespace\n const derivedNamespace = namespace || deriveNamespace(id);\n if (!isSnakeCase(derivedNamespace)) {\n return JSON.stringify({\n error: `Invalid namespace \"${derivedNamespace}\". Must be snake_case (e.g., crm, sales_module)`,\n });\n }\n\n // Build manifest\n const manifest: Record<string, unknown> = {\n id,\n name,\n version,\n type,\n namespace: derivedNamespace,\n ...(description ? { description } : {}),\n };\n\n // Install the package\n const installedPackage = await ctx.packageRegistry.install(manifest);\n\n // Set as active package in conversation if conversation service is available\n if (ctx.conversationService && ctx.conversationId) {\n try {\n await ctx.conversationService.updateMetadata?.(ctx.conversationId, {\n activePackageId: id,\n });\n } catch (err) {\n // Non-critical error - package was created successfully\n console.warn('Failed to set active package in conversation:', err);\n }\n }\n\n return JSON.stringify({\n packageId: installedPackage.manifest.id,\n name: installedPackage.manifest.name,\n version: installedPackage.manifest.version,\n namespace: installedPackage.manifest.namespace,\n status: installedPackage.status,\n message: `Package \"${name}\" created successfully and set as active package`,\n });\n };\n}\n\nfunction createGetActivePackageHandler(ctx: PackageToolContext): ToolHandler {\n return async () => {\n // If no conversation service, can't track active package\n if (!ctx.conversationService || !ctx.conversationId) {\n return JSON.stringify({\n activePackageId: null,\n message: 'No conversation context available to track active package',\n });\n }\n\n try {\n const metadata = await ctx.conversationService.getMetadata?.(ctx.conversationId);\n const activePackageId = metadata?.activePackageId as string | undefined;\n\n if (!activePackageId) {\n return JSON.stringify({\n activePackageId: null,\n message: 'No active package set. Use set_active_package or create a new package.',\n });\n }\n\n // Get package details\n const pkg = await ctx.packageRegistry.get(activePackageId);\n\n if (!pkg) {\n return JSON.stringify({\n activePackageId,\n error: `Active package \"${activePackageId}\" not found. It may have been uninstalled.`,\n });\n }\n\n return JSON.stringify({\n activePackageId: pkg.manifest.id,\n name: pkg.manifest.name,\n version: pkg.manifest.version,\n namespace: pkg.manifest.namespace,\n type: pkg.manifest.type,\n });\n } catch (err) {\n return JSON.stringify({\n error: `Failed to get active package: ${(err as Error).message}`,\n });\n }\n };\n}\n\nfunction createSetActivePackageHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { packageId } = args as { packageId: string };\n\n if (!packageId) {\n return JSON.stringify({ error: 'packageId is required' });\n }\n\n // Verify package exists\n const pkg = await ctx.packageRegistry.get(packageId);\n if (!pkg) {\n return JSON.stringify({ error: `Package \"${packageId}\" not found` });\n }\n\n // If no conversation service, return error\n if (!ctx.conversationService || !ctx.conversationId) {\n return JSON.stringify({\n error: 'No conversation context available. Cannot set active package.',\n });\n }\n\n try {\n await ctx.conversationService.updateMetadata?.(ctx.conversationId, {\n activePackageId: packageId,\n });\n\n return JSON.stringify({\n activePackageId: packageId,\n name: pkg.manifest.name,\n namespace: pkg.manifest.namespace,\n message: `Active package set to \"${pkg.manifest.name}\"`,\n });\n } catch (err) {\n return JSON.stringify({\n error: `Failed to set active package: ${(err as Error).message}`,\n });\n }\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public Registration Helper\n// ---------------------------------------------------------------------------\n\n/**\n * Register all built-in package management tools on the given {@link ToolRegistry}.\n *\n * Typically called from the `ai:ready` hook after the package registry is available.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const packageRegistry = ctx.getService<IPackageRegistry>('packageRegistry');\n * const conversationService = ctx.getService<IConversationService>('conversation');\n * registerPackageTools(aiService.toolRegistry, {\n * packageRegistry,\n * conversationService,\n * });\n * });\n * ```\n */\nexport function registerPackageTools(\n registry: ToolRegistry,\n context: PackageToolContext,\n): void {\n registry.register(listPackagesTool, createListPackagesHandler(context));\n registry.register(getPackageTool, createGetPackageHandler(context));\n registry.register(createPackageTool, createCreatePackageHandler(context));\n registry.register(getActivePackageTool, createGetActivePackageHandler(context));\n registry.register(setActivePackageTool, createSetActivePackageHandler(context));\n}\n"],"mappings":"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","names":["import_ai","import_ai","import_ai","import_ai","import_ai","result","import_node_crypto","import_data","import_data","import_data","import_spec","import_ai","import_ai","def","import_ai","vercelTool","DATA_TOOL_DEFINITIONS","METADATA_TOOL_DEFINITIONS","buildEngineContext","import_ai","import_ai","import_ai","import_ai","import_ai","SNAKE_CASE_RE","isSnakeCase"]}
1
+ {"version":3,"sources":["../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-objects.tool.ts","../src/tools/describe-object.tool.ts","../src/tools/metadata-tools.ts","../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/trace-recorder.ts","../src/plugin.ts","../src/stream/vercel-stream-encoder.ts","../src/routes/message-utils.ts","../src/routes/ai-routes.ts","../src/routes/agent-routes.ts","../src/routes/assistant-routes.ts","../src/routes/tool-routes.ts","../src/routes/pending-action-routes.ts","../src/conversation/objectql-conversation-service.ts","../src/objects/ai-conversation.object.ts","../src/objects/ai-message.object.ts","../src/objects/ai-trace.object.ts","../src/objects/ai-pending-action.object.ts","../src/views/ai-trace.view.ts","../src/views/ai-pending-action.view.ts","../src/tools/query-data.tool.ts","../src/schema-retriever.ts","../src/tools/action-tools.ts","../src/agent-runtime.ts","../src/skill-registry.ts","../src/agents/data-chat-agent.ts","../src/agents/metadata-assistant-agent.ts","../src/skills/data-explorer-skill.ts","../src/skills/metadata-authoring-skill.ts","../src/skills/actions-executor-skill.ts","../src/adapters/vercel-adapter.ts","../src/model-registry.ts","../src/tools/knowledge-tools.ts","../src/tools/list-packages.tool.ts","../src/tools/get-package.tool.ts","../src/tools/create-package.tool.ts","../src/tools/get-active-package.tool.ts","../src/tools/set-active-package.tool.ts","../src/tools/package-tools.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIToolDefinition,\n IDataEngine,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport type { ToolHandler, ToolExecutionContext } from './tool-registry.js';\nimport type { ToolRegistry } from './tool-registry.js';\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}\n\n/**\n * Translate a {@link ToolExecutionContext} into the ObjectQL\n * {@link ExecutionContext} that data-engine calls expect.\n *\n * When the AI tool call carries an authenticated `actor`, we forward\n * the user/roles/permissions and explicitly set `isSystem: false` so\n * row-level security and field masking kick in just like they would\n * for a normal REST request.\n *\n * When no actor is supplied (legacy callers, cron jobs, plugin-level\n * bootstraps) we send `isSystem: true` to preserve today's\n * unrestricted behaviour — closing the agent-permission gap is\n * opt-in at the call site that knows the user.\n */\nfunction buildEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\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 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 required: ['field', 'order'],\n additionalProperties: false,\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 additionalProperties: false,\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 tools definitions. */\nexport const DATA_TOOL_DEFINITIONS: AIToolDefinition[] = [\n QUERY_RECORDS_TOOL,\n GET_RECORD_TOOL,\n AGGREGATE_DATA_TOOL,\n];\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createQueryRecordsHandler(ctx: DataToolContext): ToolHandler {\n return async (args, execCtx) => {\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 context: buildEngineContext(execCtx),\n });\n\n return JSON.stringify({ count: records.length, records });\n };\n}\n\nfunction createGetRecordHandler(ctx: DataToolContext): ToolHandler {\n return async (args, execCtx) => {\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 context: buildEngineContext(execCtx),\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, execCtx) => {\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 context: buildEngineContext(execCtx),\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 the data engine is available.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const dataEngine = ctx.getService<IDataEngine>('data');\n * registerDataTools(aiService.toolRegistry, { dataEngine });\n * });\n * ```\n */\nexport function registerDataTools(\n registry: ToolRegistry,\n context: DataToolContext,\n): void {\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 packageId: {\n type: 'string',\n description: 'Package ID that will own this object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\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 packageId: {\n type: 'string',\n description: 'Package ID that owns the target object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\n },\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 packageId: {\n type: 'string',\n description: 'Package ID that owns the target object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\n },\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 packageId: {\n type: 'string',\n description: 'Package ID that owns the target object (e.g., com.acme.crm). If not provided, uses the active package from conversation context.',\n },\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_objects — AI Tool Metadata\n *\n * Lists all registered data objects (tables) with optional filtering\n * and field summaries. This is the single, unified tool for listing\n * objects — used by both data_chat and metadata_assistant agents.\n */\nexport const listObjectsTool = defineTool({\n name: 'list_objects',\n label: 'List Objects',\n description:\n 'Lists all registered data objects (tables) in the current environment. ' +\n 'Use this when the user wants to see what tables, entities, or data models are available.',\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_object — AI Tool Metadata\n *\n * Returns the full schema of a data object including all fields, types,\n * relationships, and configuration. This is the single, unified tool for\n * describing objects — used by both data_chat and metadata_assistant agents.\n */\nexport const describeObjectTool = defineTool({\n name: 'describe_object',\n label: 'Describe Object',\n description:\n 'Returns the full schema details of a data object, including all fields, types, relationships, and configuration. ' +\n 'Use this to understand the structure of a table before querying or modifying it.',\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 { listObjectsTool } from './list-objects.tool.js';\nexport { describeObjectTool } from './describe-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 { listObjectsTool } from './list-objects.tool.js';\nimport { describeObjectTool } from './describe-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 listObjectsTool,\n describeObjectTool,\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// Package Resolution Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Retrieves the active package ID from the conversation context.\n * Returns null if no conversation service is available or no active package is set.\n */\nasync function getActivePackageId(ctx: MetadataToolContext): Promise<string | null> {\n if (!ctx.conversationService?.getMetadata || !ctx.conversationId) {\n return null;\n }\n\n const metadata = await ctx.conversationService.getMetadata(ctx.conversationId);\n return (metadata?.activePackageId as string) ?? null;\n}\n\n/**\n * Resolves the package ID to use for a metadata operation.\n * Priority: explicit packageId > active package from conversation > error\n *\n * Also validates that the package exists and checks if it's read-only.\n *\n * @returns Object with packageId or error message\n */\nasync function resolvePackageId(\n ctx: MetadataToolContext,\n explicitPackageId?: string,\n): Promise<{ packageId: string | null; error?: string; warning?: string }> {\n let packageId: string | null = null;\n\n // 1. Try explicit packageId parameter\n if (explicitPackageId) {\n packageId = explicitPackageId;\n } else {\n // 2. Try active package from conversation\n packageId = await getActivePackageId(ctx);\n }\n\n // If no package ID could be resolved, return null (backward compatibility)\n // This allows metadata to be stored without package association\n if (!packageId) {\n return {\n packageId: null,\n warning: 'No package specified. Metadata will be created without package association. Consider using set_active_package or providing packageId parameter.',\n };\n }\n\n // Validate package exists (if registry is available)\n if (ctx.packageRegistry) {\n const exists = await ctx.packageRegistry.exists(packageId);\n if (!exists) {\n return {\n packageId: null,\n error: `Package \"${packageId}\" not found. Use list_packages to see available packages or create_package to create a new one.`,\n };\n }\n\n // Check if package is read-only (code-based)\n const pkg = await ctx.packageRegistry.get(packageId);\n if (pkg?.manifest.source === 'filesystem') {\n return {\n packageId: null,\n error: `Package \"${packageId}\" is read-only (loaded from code). Only database packages can be modified. Use create_package to create a new database package.`,\n };\n }\n }\n\n return { packageId };\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 /** Optional: Conversation service for retrieving active package context */\n conversationService?: {\n getMetadata?(conversationId: string): Promise<Record<string, unknown> | undefined>;\n };\n\n /** Optional: Current conversation ID (if in a conversation context) */\n conversationId?: string;\n\n /** Optional: Package registry for validating package existence */\n packageRegistry?: {\n exists(packageId: string): Promise<boolean>;\n get(packageId: string): Promise<{ manifest: { scope?: string; source?: string } } | undefined>;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createCreateObjectHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { name, label, packageId: explicitPackageId, fields, enableFeatures } = args as {\n name: string;\n label: string;\n packageId?: 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 // Resolve package ID\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\n }\n const packageId = resolved.packageId;\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 ...(packageId ? { packageId } : {}),\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 ...(packageId ? { packageId } : {}),\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, packageId: explicitPackageId } = 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 packageId?: string;\n };\n\n if (!objectName || !name || !type) {\n return JSON.stringify({ error: '\"objectName\", \"name\", and \"type\" are required' });\n }\n\n // Resolve package ID (for validation and tracking)\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\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 packageId: resolved.packageId,\n });\n };\n}\n\nfunction createModifyFieldHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, fieldName, changes, packageId: explicitPackageId } = args as {\n objectName: string;\n fieldName: string;\n changes: Record<string, unknown>;\n packageId?: string;\n };\n\n if (!objectName || !fieldName || !changes) {\n return JSON.stringify({ error: '\"objectName\", \"fieldName\", and \"changes\" are required' });\n }\n\n // Resolve package ID (for validation and tracking)\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\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 packageId: resolved.packageId,\n });\n };\n}\n\nfunction createDeleteFieldHandler(ctx: MetadataToolContext): ToolHandler {\n return async (args) => {\n const { objectName, fieldName, packageId: explicitPackageId } = args as {\n objectName: string;\n fieldName: string;\n packageId?: string;\n };\n\n if (!objectName || !fieldName) {\n return JSON.stringify({ error: '\"objectName\" and \"fieldName\" are required' });\n }\n\n // Resolve package ID (for validation and tracking)\n const resolved = await resolvePackageId(ctx, explicitPackageId);\n if (resolved.error) {\n return JSON.stringify({ error: resolved.error });\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 packageId: resolved.packageId,\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(listObjectsTool, createListObjectsHandler(context));\n registry.register(describeObjectTool, createDescribeObjectHandler(context));\n}\n","// 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// Knowledge tools\nexport { registerKnowledgeTools, SEARCH_KNOWLEDGE_TOOL } from './tools/knowledge-tools.js';\nexport type { KnowledgeToolContext } from './tools/knowledge-tools.js';\n\n// Individual tool metadata (first-class Tool definitions via defineTool)\nexport {\n createObjectTool,\n addFieldTool,\n modifyFieldTool,\n deleteFieldTool,\n listObjectsTool,\n describeObjectTool,\n} from './tools/metadata-tools.js';\n\n// Package tools\nexport { registerPackageTools, PACKAGE_TOOL_DEFINITIONS } from './tools/package-tools.js';\nexport type { PackageToolContext, IPackageRegistry, IConversationService } from './tools/package-tools.js';\n\n// Individual package tool metadata\nexport {\n listPackagesTool,\n getPackageTool,\n createPackageTool,\n getActivePackageTool,\n setActivePackageTool,\n} from './tools/package-tools.js';\n\n// Action tools (write-side: turn declarative Actions into AI-callable tools)\nexport {\n registerActionsAsTools,\n actionToToolDefinition,\n actionToolName,\n actionSkipReason,\n} from './tools/action-tools.js';\nexport type { ActionToolsContext } from './tools/action-tools.js';\n\n// Agent runtime\nexport { AgentRuntime } from './agent-runtime.js';\nexport type { AgentChatContext } from './agent-runtime.js';\n\n// Skill registry (Agent → Skill → Tool composition)\nexport { SkillRegistry } from './skill-registry.js';\nexport type { SkillContext, SkillSummary } from './skill-registry.js';\n\n// Built-in agents\nexport { DATA_CHAT_AGENT, METADATA_ASSISTANT_AGENT } from './agents/index.js';\n\n// Built-in skills\nexport {\n DATA_EXPLORER_SKILL,\n METADATA_AUTHORING_SKILL,\n ACTIONS_EXECUTOR_SKILL,\n} from './skills/index.js';\n\n// Object definitions\nexport { AiConversationObject, AiMessageObject, AiTraceObject } from './objects/index.js';\n\n// View definitions (built-in Studio surfaces)\nexport { AiTraceView } from './views/index.js';\n\n// Model registry\nexport { ModelRegistry, computeCost } from './model-registry.js';\nexport type { ModelRegistryConfig, CostEstimate, TokenUsage } from './model-registry.js';\n\n// Trace recorder\nexport {\n NullTraceRecorder,\n ObjectQLTraceRecorder,\n buildTraceEvent,\n} from './trace-recorder.js';\nexport type { TraceRecorder, TraceEvent, TraceOperation } from './trace-recorder.js';\n\n// Schema retriever (keyword-based metadata retrieval for AI prompts)\nexport { SchemaRetriever } from './schema-retriever.js';\nexport type {\n SchemaHit,\n SchemaRetrieverOptions,\n ObjectShape,\n FieldShape,\n} from './schema-retriever.js';\n\n// query_data tool (NL → ObjectQL via structured output)\nexport {\n QUERY_DATA_TOOL,\n createQueryDataHandler,\n registerQueryDataTool,\n} from './tools/query-data.tool.js';\nexport type { QueryDataToolContext, QueryPlan } from './tools/query-data.tool.js';\n\n// Routes\nexport { buildAIRoutes } from './routes/ai-routes.js';\nexport { buildAgentRoutes } from './routes/agent-routes.js';\nexport { buildAssistantRoutes } from './routes/assistant-routes.js';\nexport { buildToolRoutes } from './routes/tool-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 AIObjectResult,\n GenerateObjectOptions,\n IAIService,\n IAIConversationService,\n IDataEngine,\n ChatWithToolsOptions,\n LLMAdapter,\n PendingActionRow,\n PendingActionStatus,\n ProposePendingActionInput,\n} from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport type { z } from 'zod';\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';\nimport { ModelRegistry } from './model-registry.js';\nimport {\n NullTraceRecorder,\n buildTraceEvent,\n type TraceRecorder,\n type TraceOperation,\n} from './trace-recorder.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 /** Model registry for pricing + default model resolution. Optional. */\n modelRegistry?: ModelRegistry;\n /** Trace recorder for per-call observability. Defaults to no-op. */\n traceRecorder?: TraceRecorder;\n /**\n * Data engine used to persist `ai_pending_actions` rows for the\n * actions-as-tools HITL queue. Optional — when omitted, the\n * `proposePendingAction` / `approvePendingAction` methods throw if\n * called. Wired by `AIServicePlugin` after the data driver is up.\n */\n dataEngine?: IDataEngine;\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 adapter: LLMAdapter;\n private readonly logger: Logger;\n readonly toolRegistry: ToolRegistry;\n readonly conversationService: IAIConversationService;\n readonly modelRegistry?: ModelRegistry;\n readonly traceRecorder: TraceRecorder;\n /**\n * Map of tool-name → dispatcher used to re-run an approved pending\n * action. Populated by `registerActionsAsTools()` when action\n * approval is enabled. Kept private because callers should go\n * through `approvePendingAction()`.\n */\n private readonly pendingDispatchers = new Map<\n string,\n (input: Record<string, unknown>) => Promise<unknown>\n >();\n /** Data engine for `ai_pending_actions` persistence. */\n private readonly dataEngine?: IDataEngine;\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 this.modelRegistry = config.modelRegistry;\n this.traceRecorder = config.traceRecorder ?? new NullTraceRecorder();\n this.dataEngine = config.dataEngine;\n\n this.logger.info(\n `[AI] Service initialized with adapter=\"${this.adapter.name}\", ` +\n `tools=${this.toolRegistry.size}, models=${this.modelRegistry?.size ?? 0}`,\n );\n }\n\n /** The name of the active LLM adapter. */\n get adapterName(): string {\n return this.adapter.name;\n }\n\n /**\n * Hot-swap the LLM adapter. Used by AIServicePlugin when the `ai`\n * settings namespace changes (provider/key/model edited via Setup UI).\n * In-flight requests bound to the previous adapter complete normally;\n * subsequent calls go through the new adapter.\n */\n setAdapter(next: LLMAdapter): void {\n const prev = this.adapter.name;\n this.adapter = next;\n if (prev !== next.name) {\n this.logger.info(`[AI] LLM adapter swapped: ${prev} → ${next.name}`);\n }\n }\n\n /**\n * Best-effort persistence of a single chat message to the conversation\n * store. Failures are logged at warn level and swallowed — chat requests\n * must never fail because the history write failed. Mirrors the\n * precedent set by `ObjectQLTraceRecorder.record`.\n */\n private async persistMessage(conversationId: string, message: ModelMessage): Promise<void> {\n try {\n await this.conversationService.addMessage(conversationId, message);\n } catch (err) {\n this.logger.warn('[AI] persist message failed', {\n conversationId,\n role: (message as { role?: string }).role,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /**\n * Run an adapter call and emit a trace event.\n *\n * Records both success and failure. Tracing failures never escape — the\n * recorder is expected to be defensive.\n */\n private async instrument<T extends { model?: string; usage?: AIResult['usage'] }>(\n operation: TraceOperation,\n options: AIRequestOptions | undefined,\n fn: () => Promise<T>,\n ): Promise<T> {\n const started = Date.now();\n try {\n const result = await fn();\n void this.traceRecorder.record(buildTraceEvent({\n operation,\n adapter: this.adapter.name,\n model: result.model ?? options?.model,\n usage: result.usage,\n latencyMs: Date.now() - started,\n status: 'success',\n registry: this.modelRegistry,\n }));\n return result;\n } catch (err) {\n void this.traceRecorder.record(buildTraceEvent({\n operation,\n adapter: this.adapter.name,\n model: options?.model,\n latencyMs: Date.now() - started,\n status: 'error',\n error: err instanceof Error ? err.message : String(err),\n registry: this.modelRegistry,\n }));\n throw err;\n }\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.instrument('chat', options, () => 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.instrument('complete', options, () => this.adapter.complete(prompt, options));\n }\n\n /**\n * Generate a strongly-typed object validated against a Zod schema.\n *\n * Delegates to the adapter's `generateObject` when supported; throws a\n * descriptive error when the adapter does not implement structured output.\n *\n * @example\n * ```ts\n * import { z } from 'zod';\n * const Schema = z.object({ name: z.string(), priority: z.number().int() });\n * const { object } = await ai.generateObject(messages, Schema);\n * ```\n */\n async generateObject<T>(\n messages: ModelMessage[],\n schema: z.ZodType<T>,\n options?: GenerateObjectOptions,\n ): Promise<AIObjectResult<T>> {\n this.logger.debug('[AI] generateObject', { messageCount: messages.length, model: options?.model });\n if (!this.adapter.generateObject) {\n throw new Error(\n `[AI] Adapter \"${this.adapter.name}\" does not support generateObject. ` +\n `Use VercelLLMAdapter with a structured-output-capable model.`,\n );\n }\n return this.instrument('generate_object', options, () =>\n this.adapter.generateObject!(messages, schema, options),\n );\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 return this.instrument('chat_with_tools', options, () =>\n this.chatWithToolsImpl(messages, options),\n );\n }\n\n private async chatWithToolsImpl(\n messages: ModelMessage[],\n options?: ChatWithToolsOptions,\n ): Promise<AIResult> {\n // Destructure loop-specific options so they are never forwarded to the adapter\n const {\n maxIterations: maxIter,\n onToolError,\n toolExecutionContext,\n ...restOptions\n } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n const conversationId = toolExecutionContext?.conversationId;\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 // Persist the inbound user turn when a conversationId is supplied.\n // Only the last message is written — callers are assumed to pass\n // prior history alongside the new turn; we don't diff.\n if (conversationId && messages.length > 0) {\n const last = messages[messages.length - 1];\n if (last && (last as { role?: string }).role === 'user') {\n await this.persistMessage(conversationId, last);\n }\n }\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: result.content,\n } as ModelMessage);\n }\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 const assistantTurn = {\n role: 'assistant',\n content: assistantContent,\n } as ModelMessage;\n conversation.push(assistantTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, assistantTurn);\n }\n\n // Execute all tool calls in parallel, threading the per-request\n // execution context so handlers can attribute work to the actor\n // and enforce row-level security.\n const toolResults: ToolExecutionResult[] = await this.toolRegistry.executeAll(\n result.toolCalls,\n toolExecutionContext,\n );\n\n // Process results: track errors, honour onToolError callback, and\n // append each tool result as a `role: 'tool'` message so the\n // model can react in the next loop iteration.\n for (const tr of toolResults) {\n if (tr.isError) {\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 const toolTurn = {\n role: 'tool',\n content: [tr],\n } as ModelMessage;\n conversation.push(toolTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, toolTurn);\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: finalResult.content,\n } as ModelMessage);\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 {\n maxIterations: maxIter,\n onToolError,\n toolExecutionContext,\n ...restOptions\n } = options ?? {};\n const maxIterations = maxIter ?? AIService.DEFAULT_MAX_ITERATIONS;\n const registeredTools = this.toolRegistry.getAll();\n const conversationId = toolExecutionContext?.conversationId;\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 if (conversationId && messages.length > 0) {\n const last = messages[messages.length - 1];\n if (last && (last as { role?: string }).role === 'user') {\n await this.persistMessage(conversationId, last);\n }\n }\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: result.content,\n } as ModelMessage);\n }\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 const assistantTurn = {\n role: 'assistant',\n content: assistantContent,\n } as ModelMessage;\n conversation.push(assistantTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, assistantTurn);\n }\n\n const toolResults: ToolExecutionResult[] = await this.toolRegistry.executeAll(\n result.toolCalls,\n toolExecutionContext,\n );\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 // Emit tool-result so the client can see tool output via SSE\n yield {\n type: 'tool-result',\n toolCallId: tr.toolCallId,\n toolName: tr.toolName,\n output: tr.output,\n } as TextStreamPart<ToolSet>;\n const toolTurn = {\n role: 'tool',\n content: [tr],\n } as ModelMessage;\n conversation.push(toolTurn);\n if (conversationId) {\n await this.persistMessage(conversationId, toolTurn);\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 if (conversationId) {\n await this.persistMessage(conversationId, {\n role: 'assistant',\n content: result.content,\n } as ModelMessage);\n }\n yield textDeltaPart('stream', result.content);\n yield finishPart(result);\n }\n\n // ── HITL: pending-action queue ─────────────────────────────────\n\n /**\n * Register a dispatcher callback for a tool. Called by\n * `registerActionsAsTools()` when action approval is enabled so the\n * approval handler can re-run the exact same code path the LLM\n * would have triggered.\n */\n registerPendingActionDispatcher(\n toolName: string,\n dispatch: (input: Record<string, unknown>) => Promise<unknown>,\n ): void {\n this.pendingDispatchers.set(toolName, dispatch);\n }\n\n async proposePendingAction(input: ProposePendingActionInput): Promise<{ id: string }> {\n if (!this.dataEngine) {\n throw new Error('proposePendingAction requires a dataEngine — wire it via AIServiceConfig.');\n }\n const id = `pa_${cryptoRandomId()}`;\n const row = {\n id,\n conversation_id: input.conversationId ?? null,\n message_id: input.messageId ?? null,\n object_name: input.objectName,\n action_name: input.actionName,\n tool_name: input.toolName,\n tool_input: JSON.stringify(input.toolInput ?? {}),\n status: 'pending',\n proposed_by: input.proposedBy ?? 'ai_agent',\n proposed_at: new Date().toISOString(),\n };\n await this.dataEngine.insert('ai_pending_actions', row);\n this.logger.info(\n `[AI] pending action proposed: ${id} (${input.toolName} on ${input.objectName})`,\n );\n return { id };\n }\n\n async approvePendingAction(\n id: string,\n actorId: string,\n ): Promise<{ status: 'executed' | 'failed'; result?: unknown; error?: string }> {\n if (!this.dataEngine) {\n throw new Error('approvePendingAction requires a dataEngine.');\n }\n const row = await this.loadPendingRow(id);\n if (row.status !== 'pending') {\n throw new Error(`pending action ${id} is already ${row.status}`);\n }\n const dispatch = this.pendingDispatchers.get(row.tool_name);\n if (!dispatch) {\n throw new Error(\n `no dispatcher registered for tool '${row.tool_name}' — was the AI plugin restarted without re-registering actions?`,\n );\n }\n await this.dataEngine.update(\n 'ai_pending_actions',\n {\n id,\n status: 'approved',\n decided_by: actorId,\n decided_at: new Date().toISOString(),\n },\n { where: { id } },\n );\n let parsed: Record<string, unknown> = {};\n try {\n parsed = row.tool_input ? (JSON.parse(row.tool_input) as Record<string, unknown>) : {};\n } catch {\n parsed = {};\n }\n try {\n const out = await dispatch(parsed);\n await this.dataEngine.update(\n 'ai_pending_actions',\n { id, status: 'executed', result: JSON.stringify(out ?? null) },\n { where: { id } },\n );\n this.logger.info(`[AI] pending action ${id} executed by ${actorId}`);\n return { status: 'executed', result: out };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n await this.dataEngine.update(\n 'ai_pending_actions',\n { id, status: 'failed', error: msg },\n { where: { id } },\n );\n this.logger.warn(`[AI] pending action ${id} failed after approval: ${msg}`);\n return { status: 'failed', error: msg };\n }\n }\n\n async rejectPendingAction(id: string, actorId: string, reason?: string): Promise<void> {\n if (!this.dataEngine) {\n throw new Error('rejectPendingAction requires a dataEngine.');\n }\n const row = await this.loadPendingRow(id);\n if (row.status !== 'pending') {\n throw new Error(`pending action ${id} is already ${row.status}`);\n }\n await this.dataEngine.update(\n 'ai_pending_actions',\n {\n id,\n status: 'rejected',\n decided_by: actorId,\n decided_at: new Date().toISOString(),\n rejection_reason: reason ?? null,\n },\n { where: { id } },\n );\n this.logger.info(`[AI] pending action ${id} rejected by ${actorId}`);\n }\n\n async listPendingActions(filter?: {\n status?: PendingActionStatus | PendingActionStatus[];\n conversationId?: string;\n objectName?: string;\n limit?: number;\n }): Promise<PendingActionRow[]> {\n if (!this.dataEngine) return [];\n const where: Record<string, unknown> = {};\n if (filter?.status) {\n where.status = Array.isArray(filter.status) ? { in: filter.status } : filter.status;\n }\n if (filter?.conversationId) where.conversation_id = filter.conversationId;\n if (filter?.objectName) where.object_name = filter.objectName;\n const rows = (await this.dataEngine.find('ai_pending_actions', {\n where,\n limit: filter?.limit ?? 100,\n orderBy: [{ field: 'proposed_at', order: 'desc' }],\n })) as PendingActionRow[];\n return rows;\n }\n\n private async loadPendingRow(id: string): Promise<PendingActionRow> {\n const rows = (await this.dataEngine!.find('ai_pending_actions', {\n where: { id },\n limit: 1,\n })) as PendingActionRow[];\n const row = rows[0];\n if (!row) throw new Error(`pending action ${id} not found`);\n return row;\n }\n}\n\nfunction cryptoRandomId(): string {\n // crypto.randomUUID is available in Node 16+ and modern browsers; fall\n // back to a timestamp+random pair for environments that lack it.\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { z } from 'zod';\nimport type {\n ModelMessage,\n AIRequestOptions,\n AIResult,\n AIObjectResult,\n GenerateObjectOptions,\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 userText = typeof userContent === 'string' ? userContent : '(complex content)';\n\n // ── Heuristic tool-calling support ──────────────────────────────────────\n // When `chatWithTools` injects available tools the adapter drives a\n // small two-step plan so demos/tests work end-to-end without a real\n // LLM provider:\n //\n // 1. If the user's message looks like an *action* request\n // (verbs like \"complete\", \"start\", \"clone\", ...) and an\n // `action_<name>` tool is registered, prefer it. Resolve the\n // record id from any prior `query_data` result.\n // 2. Otherwise, if a `query_data` tool is present and hasn't been\n // called yet, call it with the user's text.\n // 3. After a `role: 'tool'` result comes back, summarise it.\n const tools = options?.tools as Array<{ name: string; description?: string }> | undefined;\n const hasQueryDataTool = Array.isArray(tools) && tools.some(t => t?.name === 'query_data');\n const alreadyCalledQueryData = messages.some(\n m =>\n m.role === 'tool' &&\n Array.isArray(m.content) &&\n (m.content as Array<{ toolName?: string }>).some(c => c?.toolName === 'query_data'),\n );\n const alreadyCalledAction = messages.some(\n m =>\n m.role === 'tool' &&\n Array.isArray(m.content) &&\n (m.content as Array<{ toolName?: string }>).some(\n c => typeof c?.toolName === 'string' && c.toolName.startsWith('action_'),\n ),\n );\n\n // ── Step 1: route action verbs to a matching `action_<name>` tool ──\n if (Array.isArray(tools) && !alreadyCalledAction && lastUserMessage) {\n const actionTools = tools.filter(t => typeof t?.name === 'string' && t.name.startsWith('action_'));\n const chosen = pickActionTool(userText, actionTools);\n if (chosen) {\n const recordId = extractRecordIdFromMessages(messages, userText);\n if (recordId) {\n const toolCallId = `memory_tc_${Date.now().toString(36)}`;\n return {\n content: '',\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n toolCalls: [\n {\n type: 'tool-call',\n toolCallId,\n toolName: chosen.name,\n input: { recordId },\n } as unknown as NonNullable<AIResult['toolCalls']>[number],\n ],\n };\n }\n // Need a record id but don't have one — fall through to query_data\n // first so we can resolve the target record.\n }\n }\n\n // ── Step 2: route data questions to `query_data` ──\n\n if (hasQueryDataTool && !alreadyCalledQueryData && lastUserMessage) {\n const toolCallId = `memory_tc_${Date.now().toString(36)}`;\n return {\n content: '',\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n toolCalls: [\n {\n type: 'tool-call',\n toolCallId,\n toolName: 'query_data',\n input: { request: userText },\n } as unknown as NonNullable<AIResult['toolCalls']>[number],\n ],\n };\n }\n\n // If a query_data result is already in the conversation, summarise it\n // (or fall through to step 1 if the action wasn't yet routable).\n if (alreadyCalledAction) {\n const lastTool = [...messages].reverse().find(m => m.role === 'tool');\n const part = Array.isArray(lastTool?.content)\n ? (lastTool!.content as Array<{\n toolName?: string;\n output?: { type?: string; value?: unknown };\n result?: unknown;\n }>).find(c => typeof c?.toolName === 'string' && c.toolName.startsWith('action_'))\n : undefined;\n const raw =\n part?.output && typeof part.output === 'object' && 'value' in part.output\n ? part.output.value\n : part?.result;\n let payload: { ok?: boolean; message?: string; error?: string; action?: string } = {};\n if (typeof raw === 'string') {\n try { payload = JSON.parse(raw); } catch { /* leave empty */ }\n } else if (raw && typeof raw === 'object') {\n payload = raw as typeof payload;\n }\n if (payload.error) {\n return {\n content: `[memory] action ${payload.action ?? ''} failed: ${payload.error}`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n return {\n content: `[memory] ${payload.message ?? 'Action executed.'} (${payload.action ?? 'action'})`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n if (alreadyCalledQueryData) {\n const lastTool = [...messages].reverse().find(m => m.role === 'tool');\n const part = Array.isArray(lastTool?.content)\n ? (lastTool!.content as Array<{\n toolName?: string;\n output?: { type?: string; value?: unknown };\n result?: unknown;\n }>).find(c => c?.toolName === 'query_data')\n : undefined;\n let payload: { records?: unknown[]; count?: number; error?: string } = {};\n const raw =\n part?.output && typeof part.output === 'object' && 'value' in part.output\n ? part.output.value\n : part?.result;\n if (typeof raw === 'string') {\n try {\n payload = JSON.parse(raw);\n } catch {\n payload = {};\n }\n } else if (raw && typeof raw === 'object') {\n payload = raw as typeof payload;\n }\n if (payload.error) {\n return {\n content: `[memory] query_data failed: ${payload.error}`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n const records = payload.records ?? [];\n const count = payload.count ?? records.length;\n return {\n content: `[memory] Found ${count} record${count === 1 ? '' : 's'} for \"${userText}\".`,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n\n const content = lastUserMessage\n ? `[memory] ${userText}`\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 /**\n * Heuristic structured-output for testing & demos — NOT a real LLM.\n *\n * Strategy:\n * 1. Extract candidate object names from the system messages by matching\n * schema-context headers (`### name — Label`) emitted by\n * {@link SchemaRetriever.renderSnippet}.\n * 2. Pick the candidate whose tokens overlap most with the last user\n * message (falls back to the first candidate).\n * 3. Try `schema.safeParse({ objectName, limit: 20 })` — this satisfies the\n * `QueryPlanSchema` used by the built-in `query_data` tool.\n * 4. If that fails, fall back to `schema.safeParse({})` for schemas that\n * accept defaults.\n * 5. Otherwise throw with a clear message — the demo needs a real provider.\n */\n async generateObject<T = unknown>(\n messages: ModelMessage[],\n schema: z.ZodType<T>,\n options?: GenerateObjectOptions,\n ): Promise<AIObjectResult<T>> {\n const sys = messages\n .filter(m => m.role === 'system')\n .map(m => (typeof m.content === 'string' ? m.content : ''))\n .join('\\n');\n\n // Parse headers of the form `### machine_name — Label (Plural)` emitted\n // by SchemaRetriever.renderSnippet. Capture every alias so we can match\n // against natural-language user queries like \"show me my tasks\".\n const headerRe = /^###\\s+([a-z0-9_]+)(?:\\s+—\\s+([^\\n]+))?/gim;\n type Candidate = { name: string; aliasTokens: Set<string> };\n const candidates: Candidate[] = [];\n for (const match of sys.matchAll(headerRe)) {\n const machineName = match[1];\n if (!machineName) continue;\n const aliasText = match[2] ?? '';\n const aliasTokens = new Set<string>();\n // Tokens from the snake_case machine name\n for (const t of machineName.split(/[^a-z0-9]+/)) {\n if (t) aliasTokens.add(t);\n }\n // Tokens from the label / plural label (everything after the em dash)\n for (const t of aliasText.toLowerCase().split(/[^a-z0-9]+/)) {\n if (t) aliasTokens.add(t);\n }\n // Naive stem: include singular form of plural tokens ending in \"s\"\n for (const t of [...aliasTokens]) {\n if (t.length > 3 && t.endsWith('s')) aliasTokens.add(t.slice(0, -1));\n }\n candidates.push({ name: machineName, aliasTokens });\n }\n\n const lastUser = [...messages].reverse().find(m => m.role === 'user');\n const userText = typeof lastUser?.content === 'string'\n ? lastUser.content.toLowerCase()\n : '';\n const userTokens = new Set(\n userText.split(/[^a-z0-9_]+/).filter(t => t.length > 1),\n );\n // Apply the same naive plural→singular stem to user tokens so \"tasks\"\n // also looks up as \"task\".\n for (const t of [...userTokens]) {\n if (t.length > 3 && t.endsWith('s')) userTokens.add(t.slice(0, -1));\n }\n\n let chosen = candidates[0]?.name;\n let bestScore = -1;\n for (const cand of candidates) {\n let score = 0;\n for (const tok of cand.aliasTokens) {\n if (userTokens.has(tok)) score += 1;\n }\n if (score > bestScore) {\n bestScore = score;\n chosen = cand.name;\n }\n }\n\n const attempts: Array<Record<string, unknown>> = [];\n if (chosen) attempts.push({ objectName: chosen, limit: 20 });\n attempts.push({});\n\n for (const attempt of attempts) {\n const result = schema.safeParse(attempt);\n if (result.success) {\n return {\n object: result.data,\n model: options?.model ?? 'memory',\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n }\n }\n\n throw new Error(\n 'MemoryLLMAdapter.generateObject: unable to synthesise a value for the ' +\n 'requested schema. The memory adapter only handles QueryPlan-shaped ' +\n 'schemas — wire a real LLM adapter (OpenAI / Anthropic / Google) for ' +\n 'arbitrary structured output.',\n );\n }\n}\n\n// ── Heuristic helpers (memory adapter only) ─────────────────────────\n\n/**\n * Naive intent matcher for action-style requests.\n *\n * Returns the best matching `action_*` tool when:\n * 1. user text contains an \"action verb\" (a token shared with the tool's\n * name *that isn't the object noun*), AND\n * 2. that match isn't a pure query verb (\"show\", \"list\", \"find\", ...).\n *\n * Query verbs alone are routed to query_data instead.\n */\nfunction pickActionTool(\n userText: string,\n actionTools: Array<{ name: string; description?: string }>,\n): { name: string; description?: string } | null {\n if (actionTools.length === 0 || !userText) return null;\n const userTokens = new Set(\n userText\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter(t => t.length > 2),\n );\n // Action verbs imply a write — query verbs alone never route here.\n const ACTION_VERBS = new Set([\n 'complete', 'finish', 'done', 'close',\n 'start', 'begin', 'resume',\n 'clone', 'copy', 'duplicate',\n 'cancel', 'abort',\n 'archive', 'restore',\n 'approve', 'reject',\n 'assign', 'unassign',\n 'export', 'import',\n 'send', 'notify',\n 'publish', 'unpublish',\n 'mark',\n 'delete', 'remove', 'purge', 'destroy', 'erase',\n ]);\n const hasActionVerb = [...userTokens].some(t => ACTION_VERBS.has(t));\n if (!hasActionVerb) return null;\n\n let best: { name: string; description?: string } | null = null;\n let bestScore = 0;\n for (const tool of actionTools) {\n // Score by overlap on the action verb portion of the tool name. We\n // intentionally weight verbs higher than nouns (\"task\"/\"record\"/...)\n // so `action_complete_task` beats `action_clone_task` for \"complete\n // my groceries\".\n const nameTokens = tool.name\n .replace(/^action_/, '')\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter(t => t.length > 2);\n let score = 0;\n for (const tok of nameTokens) {\n if (!userTokens.has(tok)) continue;\n score += ACTION_VERBS.has(tok) ? 3 : 1;\n }\n if (score > bestScore) {\n bestScore = score;\n best = tool;\n }\n }\n // Require an action-verb match (score ≥ 3) to avoid noun-only false hits.\n return bestScore >= 3 ? best : null;\n}\n\n/**\n * Look back through the conversation for a `query_data` tool result and\n * pull a record id out of it. Picks the first record id whose subject /\n * label / name tokens overlap with the user's request — the same\n * heuristic the action picker uses but applied to record fields.\n */\nfunction extractRecordIdFromMessages(\n messages: ModelMessage[],\n userText: string,\n): string | undefined {\n const userTokens = userText\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter(t => t.length > 2);\n\n for (let i = messages.length - 1; i >= 0; i--) {\n const m = messages[i];\n if (m.role !== 'tool' || !Array.isArray(m.content)) continue;\n const parts = m.content as Array<{\n toolName?: string;\n output?: { value?: unknown };\n result?: unknown;\n }>;\n for (const part of parts) {\n if (part?.toolName !== 'query_data') continue;\n const raw =\n part.output && typeof part.output === 'object' && 'value' in part.output\n ? part.output.value\n : part.result;\n let payload: { records?: Array<Record<string, unknown>> } = {};\n if (typeof raw === 'string') {\n try { payload = JSON.parse(raw); } catch { /* ignore */ }\n } else if (raw && typeof raw === 'object') {\n payload = raw as typeof payload;\n }\n const records = payload.records ?? [];\n if (records.length === 0) continue;\n\n // Pick the record whose text fields best overlap user tokens.\n let bestId: string | undefined;\n let bestScore = -1;\n for (const rec of records) {\n if (!rec || typeof rec !== 'object') continue;\n const id = rec.id;\n if (typeof id !== 'string' && typeof id !== 'number') continue;\n const hay = Object.values(rec)\n .filter((v): v is string => typeof v === 'string')\n .join(' ')\n .toLowerCase();\n const hayTokens = hay.split(/[^a-z0-9]+/).filter(Boolean);\n let score = 0;\n for (const ut of userTokens) {\n if (hayTokens.includes(ut)) score += 1;\n }\n if (score > bestScore) {\n bestScore = score;\n bestId = String(id);\n }\n }\n // Fallback to the first record id when no tokens overlap.\n return bestId ?? String(records[0].id);\n }\n }\n return undefined;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIToolDefinition,\n ToolCallPart,\n ToolResultPart,\n ToolExecutionContext,\n} from '@objectstack/spec/contracts';\n\n/**\n * Re-exported {@link ToolExecutionContext} from `@objectstack/spec` so\n * tool implementations in this package can import a single canonical\n * symbol without depending on spec internals.\n *\n * The spec hosts the authoritative shape because `ChatWithToolsOptions`\n * exposes the same type to external callers (HTTP routes, custom\n * agents).\n */\nexport type { ToolExecutionContext };\n\n/**\n * Handler function for a registered tool.\n *\n * Receives parsed arguments and an optional per-call execution context.\n * Returns the tool output as a string (typically JSON). Tools that\n * require permission enforcement should use `ctx.actor` and propagate\n * it into the underlying engine call.\n */\nexport type ToolHandler = (\n args: Record<string, unknown>,\n ctx?: ToolExecutionContext,\n) => 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 * @param toolCall The decoded tool-call part from the model response.\n * @param ctx Optional per-call execution context (actor, conversation,\n * environment). Handlers may use this to enforce RLS,\n * attribute audit entries, or correlate traces. When\n * omitted, handlers should fall back to system-level\n * behaviour for backward compatibility.\n */\n async execute(\n toolCall: ToolCallPart,\n ctx?: ToolExecutionContext,\n ): 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, ctx);\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, threading the same\n * execution context to each handler.\n */\n async executeAll(\n toolCalls: ToolCallPart[],\n ctx?: ToolExecutionContext,\n ): Promise<ToolExecutionResult[]> {\n return Promise.all(toolCalls.map(tc => this.execute(tc, ctx)));\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\nimport { randomUUID } from 'node:crypto';\nimport type { IDataEngine, Logger } from '@objectstack/spec/contracts';\nimport type { ModelRegistry, CostEstimate } from './model-registry.js';\n\n/** Object name used for persistence. */\nconst TRACE_OBJECT = 'ai_traces';\n\n/**\n * The operation that produced a trace.\n */\nexport type TraceOperation =\n | 'chat'\n | 'complete'\n | 'stream_chat'\n | 'chat_with_tools'\n | 'generate_object'\n | 'embed';\n\n/**\n * Data captured for every LLM invocation.\n *\n * Token counts default to 0 when the adapter does not report usage.\n * Cost fields are populated only when a {@link ModelRegistry} can resolve\n * pricing for the reported model.\n */\nexport interface TraceEvent {\n operation: TraceOperation;\n adapter: string;\n model?: string;\n agentId?: string;\n conversationId?: string;\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n latencyMs: number;\n status: 'success' | 'error';\n error?: string;\n cost?: CostEstimate;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * TraceRecorder — Records {@link TraceEvent}s.\n *\n * Implementations are expected to be non-throwing — a tracing failure must\n * never crash an AI call. The default {@link ObjectQLTraceRecorder} swallows\n * errors and logs at `warn`.\n */\nexport interface TraceRecorder {\n record(event: TraceEvent): Promise<void> | void;\n}\n\n/** Discard all traces. Default when no data engine is wired. */\nexport class NullTraceRecorder implements TraceRecorder {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n record(_event: TraceEvent): void {\n // intentional no-op\n }\n}\n\n/**\n * ObjectQLTraceRecorder — Persists traces via {@link IDataEngine}.\n *\n * Writes one row per call to the `ai_traces` object. Failures are logged\n * but never propagated.\n *\n * @example\n * ```ts\n * const recorder = new ObjectQLTraceRecorder(dataEngine, { logger });\n * ```\n */\nexport class ObjectQLTraceRecorder implements TraceRecorder {\n private readonly engine: IDataEngine;\n private readonly logger?: Logger;\n\n constructor(engine: IDataEngine, options: { logger?: Logger } = {}) {\n this.engine = engine;\n this.logger = options.logger;\n }\n\n async record(event: TraceEvent): Promise<void> {\n const row = {\n id: `trace_${randomUUID()}`,\n conversation_id: event.conversationId ?? null,\n agent_id: event.agentId ?? null,\n operation: event.operation,\n model: event.model ?? null,\n adapter: event.adapter,\n prompt_tokens: event.promptTokens,\n completion_tokens: event.completionTokens,\n total_tokens: event.totalTokens,\n input_cost: event.cost?.inputCost ?? null,\n output_cost: event.cost?.outputCost ?? null,\n total_cost: event.cost?.totalCost ?? null,\n currency: event.cost?.currency ?? null,\n latency_ms: event.latencyMs,\n status: event.status,\n error: event.error ?? null,\n metadata: event.metadata ? JSON.stringify(event.metadata) : null,\n created_at: new Date().toISOString(),\n };\n\n try {\n await this.engine.insert(TRACE_OBJECT, row);\n } catch (err) {\n this.logger?.warn('[AI] Failed to record trace (non-fatal)',\n err instanceof Error ? { error: err.message } : { error: String(err) });\n }\n }\n}\n\n/**\n * Helper: build a {@link TraceEvent} from a measured call.\n *\n * Resolves cost via the optional {@link ModelRegistry} when the model is\n * reported and pricing is available.\n */\nexport function buildTraceEvent(input: {\n operation: TraceOperation;\n adapter: string;\n model?: string;\n agentId?: string;\n conversationId?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n latencyMs: number;\n status: 'success' | 'error';\n error?: string;\n registry?: ModelRegistry;\n metadata?: Record<string, unknown>;\n}): TraceEvent {\n const usage = input.usage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n const cost = input.model && input.registry\n ? input.registry.estimateCost(input.model, usage)\n : undefined;\n return {\n operation: input.operation,\n adapter: input.adapter,\n model: input.model,\n agentId: input.agentId,\n conversationId: input.conversationId,\n promptTokens: usage.promptTokens,\n completionTokens: usage.completionTokens,\n totalTokens: usage.totalTokens,\n latencyMs: input.latencyMs,\n status: input.status,\n error: input.error,\n cost,\n metadata: input.metadata,\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, IAutomationService, IDataEngine, IEmbedder, IMetadataService, LLMAdapter } from '@objectstack/spec/contracts';\nimport { EMBEDDER_SERVICE } from '@objectstack/spec/contracts';\nimport type * as AI from '@objectstack/spec/ai';\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 { buildAssistantRoutes } from './routes/assistant-routes.js';\nimport { buildToolRoutes } from './routes/tool-routes.js';\nimport { buildPendingActionRoutes } from './routes/pending-action-routes.js';\nimport { ObjectQLConversationService } from './conversation/objectql-conversation-service.js';\nimport { AiConversationObject, AiMessageObject, AiPendingActionObject, AiTraceObject } from './objects/index.js';\nimport { AiTraceView, AiPendingActionView } from './views/index.js';\nimport { registerDataTools } from './tools/data-tools.js';\nimport { registerMetadataTools } from './tools/metadata-tools.js';\nimport { registerQueryDataTool } from './tools/query-data.tool.js';\nimport { registerActionsAsTools } from './tools/action-tools.js';\nimport { AgentRuntime } from './agent-runtime.js';\nimport { SkillRegistry } from './skill-registry.js';\nimport { DATA_CHAT_AGENT, METADATA_ASSISTANT_AGENT } from './agents/index.js';\nimport { DATA_EXPLORER_SKILL, METADATA_AUTHORING_SKILL, ACTIONS_EXECUTOR_SKILL } from './skills/index.js';\nimport { VercelLLMAdapter } from './adapters/vercel-adapter.js';\nimport { MemoryLLMAdapter } from './adapters/memory-adapter.js';\nimport { ModelRegistry } from './model-registry.js';\nimport { ObjectQLTraceRecorder, type TraceRecorder } from './trace-recorder.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 * Models to register in the runtime {@link ModelRegistry}.\n *\n * Used for default-model resolution and cost attribution in traces.\n * If omitted, the registry starts empty and trace `cost_*` fields are null.\n */\n models?: AI.ModelConfig[];\n /** Default model id (must appear in `models`). */\n defaultModelId?: string;\n /**\n * Explicit trace recorder override. When set, auto-detection\n * of {@link ObjectQLTraceRecorder} is skipped.\n *\n * Set to `null` to disable tracing entirely.\n */\n /**\n * Explicit trace recorder override. When set, auto-detection\n * of {@link ObjectQLTraceRecorder} is skipped.\n *\n * Set to `null` to disable tracing entirely.\n */\n traceRecorder?: TraceRecorder | null;\n /**\n * Base URL prepended to relative `target` paths for `type:'api'`\n * actions invoked by the AI tool runtime. When unset, falls back to\n * `process.env.OS_AI_ACTION_API_BASE_URL`. If neither is set, api\n * actions are skipped at registration with a clear reason.\n */\n apiActionBaseUrl?: string;\n /**\n * Extra HTTP headers (e.g. `{ Authorization: 'Bearer ...' }`) applied\n * to every `type:'api'` action dispatch. Useful for forwarding the\n * caller's session token so server-side authorization still applies.\n */\n apiActionHeaders?: Record<string, string>;\n /**\n * Opt into Human-In-The-Loop approval for dangerous actions exposed\n * as AI tools. When `true`, actions with `confirmText`, `mode:'delete'`,\n * or `variant:'danger'` are still registered as tools — but invoking\n * them enqueues an `ai_pending_actions` row and returns\n * `{ status: 'pending_approval' }` instead of running. A human\n * operator approves via Studio's pending-actions inbox to execute.\n *\n * Defaults to `false` (safer: dangerous actions stay invisible to LLM\n * until an operator explicitly enables this routing).\n */\n enableActionApproval?: boolean;\n /**\n * Bind to the `ai` settings namespace and rebuild the LLM adapter on\n * every `settings:changed` event. When enabled (default), operators\n * can edit provider/credentials/model via the Setup app and the\n * change applies live without restart. Disable to lock the adapter\n * to whatever was resolved at boot (constructor option or env var).\n */\n bindToSettings?: boolean;\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 * Build an LLM adapter from a provider/key/model triple. Used both\n * by the boot-time auto-detect path and by the live `settings:changed`\n * rebuild path. Returns `null` if the requested provider cannot be\n * loaded or required credentials are missing.\n */\n private async buildAdapterFromValues(\n ctx: PluginContext,\n values: Record<string, unknown>,\n ): Promise<{ adapter: LLMAdapter; description: string } | null> {\n const provider = String(values.provider ?? 'memory');\n\n if (provider === 'memory') {\n return { adapter: new MemoryLLMAdapter(), description: 'MemoryLLMAdapter (echo mode)' };\n }\n\n if (provider === 'gateway') {\n const gatewayModel = String(values.gateway_model ?? '').trim();\n if (!gatewayModel) return null;\n try {\n const gatewayPkg = '@ai-sdk/gateway';\n const { gateway } = await import(/* webpackIgnore: true */ gatewayPkg);\n return {\n adapter: new VercelLLMAdapter({ model: gateway(gatewayModel) }),\n description: `Vercel AI Gateway (model: ${gatewayModel})`,\n };\n } catch (err) {\n ctx.logger.warn(\n `[AI] Failed to load @ai-sdk/gateway for provider=gateway`,\n err instanceof Error ? { error: err.message } : undefined,\n );\n return null;\n }\n }\n\n const providerSpecs: Record<string, { pkg: string; factory: string; defaultModel: string; displayName: string }> = {\n openai: { pkg: '@ai-sdk/openai', factory: 'openai', defaultModel: 'gpt-4o', displayName: 'OpenAI' },\n anthropic: { pkg: '@ai-sdk/anthropic', factory: 'anthropic', defaultModel: 'claude-sonnet-4-20250514', displayName: 'Anthropic' },\n google: { pkg: '@ai-sdk/google', factory: 'google', defaultModel: 'gemini-2.0-flash', displayName: 'Google' },\n };\n const spec = providerSpecs[provider];\n if (!spec) return null;\n\n const apiKey = String(values[`${provider}_api_key`] ?? '').trim();\n if (!apiKey) return null;\n\n // The Vercel-style provider SDKs read credentials from environment\n // variables. To honor the settings-supplied key without forcing the\n // operator to also set the env var, mirror it onto process.env for\n // the duration of the adapter construction.\n const envKey =\n provider === 'openai' ? 'OPENAI_API_KEY'\n : provider === 'anthropic' ? 'ANTHROPIC_API_KEY'\n : 'GOOGLE_GENERATIVE_AI_API_KEY';\n process.env[envKey] = apiKey;\n\n try {\n const mod = await import(/* webpackIgnore: true */ spec.pkg);\n const factory = mod[spec.factory] ?? mod.default;\n if (typeof factory !== 'function') return null;\n const modelId = String(values[`${provider}_model`] ?? '').trim() || spec.defaultModel;\n // For OpenAI, prefer the Chat Completions API. See note in detectAdapter().\n const useChatApi = provider === 'openai' && typeof (factory as any).chat === 'function';\n const model = useChatApi ? (factory as any).chat(modelId) : factory(modelId);\n const apiSuffix = useChatApi ? ' [chat-completions]' : '';\n return {\n adapter: new VercelLLMAdapter({ model }),\n description: `${spec.displayName} (model: ${modelId})${apiSuffix}`,\n };\n } catch (err) {\n ctx.logger.warn(\n `[AI] Failed to load ${spec.pkg} for provider=${provider}`,\n err instanceof Error ? { error: err.message } : undefined,\n );\n return null;\n }\n }\n\n /**\n * Build an `IEmbedder` instance from embedder settings values\n * (`embedder_provider`, `embedder_api_key`, …) by dynamically\n * importing `@objectstack/embedder-openai`. Returns `null` for\n * `none` (embedder disabled) or when required credentials are\n * missing / the package isn't installed.\n *\n * The OpenAI-compatible plugin covers OpenAI, Azure, 阿里通义,\n * 智谱, 硅基流动, 火山 Doubao, MiniMax, Ollama, and any custom\n * OpenAI-shape endpoint via `embedder_base_url`.\n */\n private async buildEmbedderFromValues(\n ctx: PluginContext,\n values: Record<string, unknown>,\n ): Promise<{ embedder: IEmbedder; description: string } | null> {\n const provider = String(values.embedder_provider ?? 'none').trim();\n if (!provider || provider === 'none') return null;\n\n const apiKey = String(values.embedder_api_key ?? '').trim();\n const model = String(values.embedder_model ?? '').trim() || undefined;\n const baseUrlOverride = String(values.embedder_base_url ?? '').trim() || undefined;\n const dimensions =\n values.embedder_dimensions != null && values.embedder_dimensions !== ''\n ? Number(values.embedder_dimensions)\n : undefined;\n\n // ollama and custom typically run unauthenticated. Other providers\n // require an api key.\n if (!apiKey && provider !== 'ollama') {\n ctx.logger.warn(\n `[AI] Embedder provider=${provider} requires embedder_api_key — embedder unchanged.`,\n );\n return null;\n }\n if ((provider === 'custom' || provider === 'azure') && !baseUrlOverride) {\n ctx.logger.warn(\n `[AI] Embedder provider=${provider} requires embedder_base_url — embedder unchanged.`,\n );\n return null;\n }\n\n try {\n const pkg = '@objectstack/embedder-openai';\n const mod = await import(/* webpackIgnore: true */ pkg);\n const create = mod.createOpenAIEmbedder ?? mod.default?.createOpenAIEmbedder;\n if (typeof create !== 'function') {\n ctx.logger.warn(\n `[AI] ${pkg} did not export createOpenAIEmbedder — embedder unchanged.`,\n );\n return null;\n }\n const embedder = create({\n preset: provider === 'custom' ? undefined : provider,\n baseUrl: baseUrlOverride,\n apiKey: apiKey || 'ollama',\n model,\n dimensions: Number.isFinite(dimensions) ? dimensions : undefined,\n id: provider,\n }) as IEmbedder;\n const dimsLabel = embedder.dimensions ? `dims=${embedder.dimensions}` : 'dims=?';\n return {\n embedder,\n description: `OpenAI-compatible embedder (provider=${provider}${model ? `, model=${model}` : ''}, ${dimsLabel})`,\n };\n } catch (err) {\n ctx.logger.warn(\n `[AI] Failed to load @objectstack/embedder-openai for embedder provider=${provider}`,\n err instanceof Error ? { error: err.message } : undefined,\n );\n return null;\n }\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 provider = mod[factory] ?? mod.default;\n if (typeof provider === 'function') {\n const modelId = process.env.AI_MODEL ?? defaultModel;\n // For OpenAI, prefer the Chat Completions API (`openai.chat(...)`)\n // over the new Responses API. The Responses endpoint\n // (`/v1/responses`) is not supported by common reverse proxies\n // such as the Vercel AI Gateway, Cloudflare AI Gateway, or\n // Azure-style OpenAI deployments — calling it returns 403\n // Forbidden and the chat completion silently fails. The Chat\n // Completions endpoint (`/v1/chat/completions`) is the\n // industry-standard contract every gateway supports.\n const useChatApi = factory === 'openai' && typeof (provider as any).chat === 'function';\n const model = useChatApi\n ? (provider as any).chat(modelId)\n : provider(modelId);\n const adapter = new VercelLLMAdapter({ model });\n const apiSuffix = useChatApi ? ' [chat-completions]' : '';\n return { adapter, description: `${displayName} (model: ${modelId})${apiSuffix}` };\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 // Model registry — empty by default; populated from plugin options.\n const modelRegistry = new ModelRegistry({\n models: this.options.models,\n defaultModelId: this.options.defaultModelId,\n });\n if (modelRegistry.size > 0) {\n ctx.logger.info(`[AI] ModelRegistry initialised with ${modelRegistry.size} model(s)`);\n }\n\n // Trace recorder — explicit > auto-detect IDataEngine > NullTraceRecorder\n let traceRecorder: TraceRecorder | undefined;\n let dataEngine: IDataEngine | undefined;\n try {\n const engine = ctx.getService<IDataEngine>('data');\n if (engine && typeof engine.insert === 'function') {\n dataEngine = engine;\n }\n } catch {\n // No data engine — pending-action queue will be a no-op.\n }\n if (this.options.traceRecorder === null) {\n // Explicit opt-out\n ctx.logger.debug('[AI] Tracing disabled (traceRecorder=null)');\n } else if (this.options.traceRecorder) {\n traceRecorder = this.options.traceRecorder;\n } else if (dataEngine) {\n traceRecorder = new ObjectQLTraceRecorder(dataEngine, { logger: ctx.logger });\n ctx.logger.info('[AI] Using ObjectQLTraceRecorder (IDataEngine detected)');\n }\n\n const config: AIServiceConfig = {\n adapter,\n logger: ctx.logger,\n conversationService,\n modelRegistry,\n traceRecorder,\n dataEngine,\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 scope: 'project',\n namespace: 'ai',\n objects: [AiConversationObject, AiMessageObject, AiTraceObject, AiPendingActionObject],\n views: [AiTraceView, AiPendingActionView],\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 tools & agents when services are available ──\n let metadataService: IMetadataService | undefined;\n // Helper: race a promise against a timeout, resolving null on timeout\n const withTimeout = <T>(promise: Promise<T>, ms = 2000): Promise<T | null> =>\n Promise.race([promise, new Promise<null>(resolve => setTimeout(() => resolve(null), ms))]);\n try {\n metadataService = ctx.getService<IMetadataService>('metadata');\n console.log('[AI Plugin] Retrieved metadata service:', !!metadataService, 'has getRegisteredTypes:', typeof (metadataService as any)?.getRegisteredTypes);\n } catch (e: any) {\n console.log('[AI] Metadata service not available:', e.message);\n ctx.logger.debug('[AI] Metadata service not available');\n }\n\n // Probe metadata service reachability with a short timeout.\n // If the backing store (e.g. Turso) is unreachable, exists() will hang.\n // A single probe determines whether persistence is available for all subsequent calls.\n if (metadataService && typeof metadataService.exists === 'function') {\n const probeResult = await withTimeout(metadataService.exists('tool', '__probe__'), 3000);\n if (probeResult === null) {\n ctx.logger.warn('[AI] Metadata service unreachable (timed out) — AI tools/agents will work but Studio visibility unavailable');\n metadataService = undefined; // disable persistence for this boot\n }\n }\n\n // Data tools require only the data engine\n try {\n const dataEngine = ctx.getService<IDataEngine>('data');\n if (dataEngine) {\n registerDataTools(this.service.toolRegistry, { dataEngine });\n ctx.logger.info('[AI] Built-in data tools registered');\n\n // Register query_data tool when metadata service is also available —\n // it composes AI + Metadata + Data into a single NL-to-records call.\n if (metadataService) {\n registerQueryDataTool(this.service.toolRegistry, {\n ai: this.service,\n metadata: metadataService,\n dataEngine,\n });\n ctx.logger.info('[AI] query_data tool registered');\n\n // Register actions-as-tools: enumerate every object's actions[]\n // and surface the script-type ones as `action_<name>` tools.\n // This is what gives agents the ability to *do things* (mark\n // task complete, clone record, ...) — the write-side counterpart\n // to query_data.\n try {\n // Resolve automation service (optional — flow actions get\n // skipped gracefully if unavailable).\n let automation: IAutomationService | undefined;\n try {\n automation = ctx.getService<IAutomationService>('automation');\n } catch {\n automation = undefined;\n }\n const apiBaseUrl =\n this.options.apiActionBaseUrl ?? process.env.OS_AI_ACTION_API_BASE_URL;\n const apiHeaders = this.options.apiActionHeaders;\n const { registered, skipped } = await registerActionsAsTools(\n this.service.toolRegistry,\n {\n metadata: metadataService,\n dataEngine,\n automation,\n apiBaseUrl,\n apiHeaders,\n enableActionApproval: this.options.enableActionApproval ?? false,\n aiService: this.service,\n },\n );\n if (registered.length > 0) {\n ctx.logger.info(\n `[AI] ${registered.length} action tool(s) registered: ${registered.join(', ')}`,\n );\n }\n if (skipped.length > 0) {\n ctx.logger.debug(\n `[AI] Skipped ${skipped.length} action(s) for AI exposure`,\n { skipped },\n );\n }\n } catch (err) {\n ctx.logger.warn(\n '[AI] Failed to register action tools',\n err instanceof Error ? { error: err.message } : { error: String(err) },\n );\n }\n }\n\n // Register data tools as metadata (for Studio visibility)\n if (metadataService) {\n const { DATA_TOOL_DEFINITIONS } = await import('./tools/data-tools.js');\n for (const toolDef of DATA_TOOL_DEFINITIONS) {\n const toolExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('tool', toolDef.name))\n : false;\n\n if (toolExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence');\n break;\n }\n\n if (!toolExists) {\n try {\n await withTimeout(metadataService.register('tool', toolDef.name, toolDef));\n } catch (err) {\n ctx.logger.warn('[AI] Failed to persist tool metadata (non-fatal)',\n err instanceof Error ? { tool: toolDef.name, error: err.message } : { tool: toolDef.name });\n }\n }\n }\n ctx.logger.info(`[AI] ${DATA_TOOL_DEFINITIONS.length} data tools registered as metadata`);\n }\n\n // Register the built-in data_chat agent (requires metadata service)\n if (metadataService) {\n try {\n const agentExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('agent', DATA_CHAT_AGENT.name))\n : false;\n\n if (agentExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking data_chat agent, skipping');\n } else if (!agentExists) {\n await withTimeout(metadataService.register('agent', DATA_CHAT_AGENT.name, DATA_CHAT_AGENT));\n console.log('[AI] Registered data_chat agent to metadataService');\n ctx.logger.info('[AI] data_chat agent registered');\n } else {\n console.log('[AI] data_chat agent already exists, skipping');\n ctx.logger.debug('[AI] data_chat agent already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register data_chat agent', err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });\n }\n\n // Register the built-in data_explorer skill (capability bundle for data_chat)\n try {\n const skillExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('skill', DATA_EXPLORER_SKILL.name))\n : false;\n\n if (skillExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking data_explorer skill, skipping');\n } else if (!skillExists) {\n await withTimeout(metadataService.register('skill', DATA_EXPLORER_SKILL.name, DATA_EXPLORER_SKILL));\n ctx.logger.info('[AI] data_explorer skill registered');\n } else {\n ctx.logger.debug('[AI] data_explorer skill already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register data_explorer skill', err instanceof Error ? { error: err.message } : { error: String(err) });\n }\n\n // Register the built-in actions_executor skill (write-side bundle for data_chat)\n try {\n const skillExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('skill', ACTIONS_EXECUTOR_SKILL.name))\n : false;\n\n if (skillExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking actions_executor skill, skipping');\n } else if (!skillExists) {\n await withTimeout(metadataService.register('skill', ACTIONS_EXECUTOR_SKILL.name, ACTIONS_EXECUTOR_SKILL));\n ctx.logger.info('[AI] actions_executor skill registered');\n } else {\n ctx.logger.debug('[AI] actions_executor skill already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register actions_executor skill', err instanceof Error ? { error: err.message } : { error: String(err) });\n }\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 metadata tools as metadata (for Studio visibility)\n const { METADATA_TOOL_DEFINITIONS } = await import('./tools/metadata-tools.js');\n for (const toolDef of METADATA_TOOL_DEFINITIONS) {\n const toolExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('tool', toolDef.name))\n : false;\n\n if (toolExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence');\n break;\n }\n\n if (!toolExists) {\n try {\n await withTimeout(metadataService.register('tool', toolDef.name, toolDef));\n } catch (err) {\n ctx.logger.warn('[AI] Failed to persist tool metadata (non-fatal)',\n err instanceof Error ? { tool: toolDef.name, error: err.message } : { tool: toolDef.name });\n }\n }\n }\n ctx.logger.info(`[AI] ${METADATA_TOOL_DEFINITIONS.length} metadata tools registered as metadata`);\n\n // Register the built-in metadata_assistant agent\n try {\n const agentExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('agent', METADATA_ASSISTANT_AGENT.name))\n : false;\n\n if (agentExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking metadata_assistant agent, skipping');\n } else if (!agentExists) {\n await withTimeout(metadataService.register('agent', METADATA_ASSISTANT_AGENT.name, METADATA_ASSISTANT_AGENT));\n console.log('[AI] Registered metadata_assistant agent to metadataService');\n ctx.logger.info('[AI] metadata_assistant agent registered');\n } else {\n console.log('[AI] metadata_assistant agent already exists, skipping');\n ctx.logger.debug('[AI] metadata_assistant agent already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register metadata_assistant agent', err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });\n }\n\n // Register the built-in metadata_authoring skill (capability bundle for metadata_assistant)\n try {\n const skillExists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('skill', METADATA_AUTHORING_SKILL.name))\n : false;\n\n if (skillExists === null) {\n ctx.logger.warn('[AI] Metadata service timed out checking metadata_authoring skill, skipping');\n } else if (!skillExists) {\n await withTimeout(metadataService.register('skill', METADATA_AUTHORING_SKILL.name, METADATA_AUTHORING_SKILL));\n ctx.logger.info('[AI] metadata_authoring skill registered');\n } else {\n ctx.logger.debug('[AI] metadata_authoring skill already exists, skipping auto-registration');\n }\n } catch (err) {\n ctx.logger.warn('[AI] Failed to register metadata_authoring skill', err instanceof Error ? { error: err.message } : { error: String(err) });\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 // ── Bridge stack-defined agents from the ObjectQL registry into the\n // MetadataService so AgentRuntime.listAgents() / loadAgent() can see\n // them. Agents declared via defineStack({ agents: [...] }) are stored\n // in the ObjectQL registry by the AppPlugin, but the MetadataManager\n // keeps an independent in-memory store. Without this bridge,\n // /api/v1/ai/agents would only return agents the AI plugin registered\n // itself (data_chat, metadata_assistant).\n if (metadataService) {\n try {\n const objectql = ctx.getService<any>('objectql');\n const registry = objectql?.registry;\n if (registry && typeof registry.listItems === 'function') {\n const stackAgents = registry.listItems('agent') as Array<any>;\n let bridged = 0;\n for (const entry of stackAgents) {\n const agent = entry?.content ?? entry;\n const agentName = agent?.name;\n if (!agentName || typeof agentName !== 'string') continue;\n const exists =\n typeof metadataService.exists === 'function'\n ? await withTimeout(metadataService.exists('agent', agentName))\n : false;\n if (exists === true) continue;\n try {\n await withTimeout(metadataService.register('agent', agentName, agent));\n bridged++;\n } catch (err) {\n ctx.logger.warn(\n '[AI] Failed to bridge stack agent into metadata service (non-fatal)',\n err instanceof Error ? { agent: agentName, error: err.message } : { agent: agentName },\n );\n }\n }\n if (bridged > 0) {\n ctx.logger.info(`[AI] Bridged ${bridged} stack-defined agent(s) from ObjectQL registry`);\n console.log(`[AI] Bridged ${bridged} stack-defined agent(s) from ObjectQL registry`);\n }\n }\n } catch (err) {\n ctx.logger.debug('[AI] ObjectQL registry not available, skipping agent bridge', err instanceof Error ? err : undefined);\n }\n }\n\n // Build and expose route definitions\n const routes = buildAIRoutes(this.service, this.service.conversationService, ctx.logger);\n\n // Build tool routes\n const toolRoutes = buildToolRoutes(this.service, ctx.logger);\n routes.push(...toolRoutes);\n ctx.logger.info(`[AI] Tool routes registered (${toolRoutes.length} routes)`);\n\n // Build HITL pending-action routes\n const pendingRoutes = buildPendingActionRoutes(this.service, ctx.logger);\n routes.push(...pendingRoutes);\n ctx.logger.info(`[AI] Pending-action routes registered (${pendingRoutes.length} routes)`);\n\n // Build agent routes if metadata service is available\n if (metadataService) {\n const skillRegistry = new SkillRegistry(metadataService);\n const agentRuntime = new AgentRuntime(metadataService, skillRegistry);\n const agentRoutes = buildAgentRoutes(this.service, agentRuntime, ctx.logger);\n routes.push(...agentRoutes);\n ctx.logger.info(`[AI] Agent routes registered (${agentRoutes.length} routes)`);\n\n const assistantRoutes = buildAssistantRoutes(this.service, agentRuntime, skillRegistry, ctx.logger);\n routes.push(...assistantRoutes);\n ctx.logger.info(`[AI] Assistant (ambient) routes registered (${assistantRoutes.length} routes)`);\n } else {\n ctx.logger.debug('[AI] Metadata service not available, skipping agent and assistant 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 // ── Bind to the `ai` settings namespace ───────────────────────\n // Apply persisted settings (provider/keys/model) once, then\n // subscribe to live changes so admin edits in the Setup app\n // swap the adapter without restart. Mirrors the storage pattern.\n if (this.options.bindToSettings !== false) {\n ctx.hook('kernel:ready', async () => {\n await this.bindSettings(ctx);\n });\n }\n }\n\n /**\n * Resolve the `settings` service, apply any persisted `ai` values,\n * subscribe to changes, and register the live `ai/test` action\n * (overrides the manifest's fallback stub).\n */\n private async bindSettings(ctx: PluginContext): Promise<void> {\n if (!this.service) return;\n let settings: any;\n try {\n settings = ctx.getService<any>('settings');\n } catch {\n return; // settings service not mounted — env-only mode stays in effect\n }\n if (!settings || typeof settings.getNamespace !== 'function') return;\n\n const applySettings = async (): Promise<void> => {\n if (!this.service) return;\n try {\n const payload = await settings.getNamespace('ai');\n const values: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(payload.values as Record<string, any>)) {\n values[k] = v?.value;\n }\n const provider = String(values.provider ?? 'memory');\n // memory provider is the manifest default; treat it as \"no override\"\n // so the env-detected adapter chosen at init stays in place.\n if (provider === 'memory') return;\n const built = await this.buildAdapterFromValues(ctx, values);\n if (!built) {\n ctx.logger.warn(\n `[AI] Settings provider=${provider} could not be applied (missing credentials or package). ` +\n `Adapter unchanged (current=\"${this.service.adapterName}\").`,\n );\n return;\n }\n this.service.setAdapter(built.adapter);\n ctx.logger.info(`[AI] Adapter rebuilt from settings: ${built.description}`);\n } catch (err: any) {\n ctx.logger.warn('[AI] Failed to apply ai settings: ' + (err?.message ?? err));\n }\n };\n\n await applySettings();\n if (typeof settings.subscribe === 'function') {\n settings.subscribe('ai', () => { void applySettings(); });\n ctx.logger.info('[AI] Bound to settings:changed for namespace=ai');\n }\n\n // ── Embedder binding ────────────────────────────────────────\n // Build an IEmbedder from `embedder_*` settings and register it\n // as the kernel-level `EMBEDDER_SERVICE`. Knowledge adapters\n // (`@objectstack/knowledge-turso`, …) resolve this service when\n // their `embedding` constructor option is omitted, so operators\n // only need to configure the embedder once in Setup.\n let currentEmbedderId: string | null = null;\n const applyEmbedder = async (): Promise<void> => {\n try {\n const payload = await settings.getNamespace('ai');\n const values: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(payload.values as Record<string, any>)) {\n values[k] = v?.value;\n }\n const built = await this.buildEmbedderFromValues(ctx, values);\n if (!built) {\n if (currentEmbedderId !== null) {\n ctx.logger.info('[AI] Embedder disabled by settings; kernel embedder service unset.');\n currentEmbedderId = null;\n }\n return;\n }\n // Register or replace under the well-known DI token.\n const replace = (ctx as any).replaceService ?? ctx.registerService;\n replace.call(ctx, EMBEDDER_SERVICE, built.embedder);\n currentEmbedderId = built.embedder.id;\n ctx.logger.info(`[AI] Embedder registered from settings: ${built.description}`);\n } catch (err: any) {\n ctx.logger.warn('[AI] Failed to apply embedder settings: ' + (err?.message ?? err));\n }\n };\n\n await applyEmbedder();\n if (typeof settings.subscribe === 'function') {\n settings.subscribe('ai', () => { void applyEmbedder(); });\n }\n\n // Live `ai/test_embedder` action — overrides the manifest's\n // fallback stub with a real one-shot embed of \"ping\" against\n // the form's (possibly unsaved) values.\n if (typeof settings.registerAction === 'function') {\n settings.registerAction('ai', 'test_embedder', async ({ values, payload }: any) => {\n const overrides =\n payload && typeof payload === 'object' && payload !== null && 'values' in payload\n ? (payload as { values?: Record<string, unknown> }).values ?? {}\n : {};\n const merged: Record<string, unknown> = { ...(values ?? {}), ...overrides };\n const provider = String(merged.embedder_provider ?? 'none');\n if (provider === 'none') {\n return {\n ok: false,\n severity: 'warning',\n message: 'Embedder disabled (provider=none). Select a provider to enable knowledge search.',\n };\n }\n let built;\n try {\n built = await this.buildEmbedderFromValues(ctx, merged);\n } catch (err: any) {\n return { ok: false, severity: 'error', message: err?.message ?? String(err) };\n }\n if (!built) {\n return {\n ok: false,\n severity: 'error',\n message: `Could not build embedder for provider=${provider}. Check api key, base URL, and that @objectstack/embedder-openai is installed.`,\n };\n }\n const started = Date.now();\n try {\n const vectors = await built.embedder.embed(['ping']);\n const latency = Date.now() - started;\n const dim = vectors[0]?.length ?? 0;\n return {\n ok: true,\n severity: 'info',\n message: `${built.description} responded in ${latency}ms (vector dims=${dim}).`,\n };\n } catch (err: any) {\n return {\n ok: false,\n severity: 'error',\n message: `${built.description} request failed: ${err?.message ?? String(err)}`,\n };\n }\n });\n ctx.logger.info('[AI] Registered live settings action ai/test_embedder');\n }\n\n // Override the manifest's fallback test handler with a live\n // round-trip against a temporary adapter built from the posted\n // (possibly unsaved) form values.\n if (typeof settings.registerAction === 'function') {\n settings.registerAction('ai', 'test', async ({ values, payload }: any) => {\n const overrides =\n payload && typeof payload === 'object' && payload !== null && 'values' in payload\n ? (payload as { values?: Record<string, unknown> }).values ?? {}\n : {};\n const merged: Record<string, unknown> = { ...(values ?? {}), ...overrides };\n const provider = String(merged.provider ?? 'memory');\n if (provider === 'memory') {\n return {\n ok: true,\n severity: 'warning',\n message: 'Memory provider is an echo stub — no external call to validate. Switch to a real provider for production.',\n };\n }\n let built;\n try {\n built = await this.buildAdapterFromValues(ctx, merged);\n } catch (err: any) {\n return { ok: false, severity: 'error', message: err?.message ?? String(err) };\n }\n if (!built) {\n return {\n ok: false,\n severity: 'error',\n message: `Could not build adapter for provider=${provider}. Check API key and that the provider SDK package is installed.`,\n };\n }\n const started = Date.now();\n try {\n const result = await built.adapter.chat(\n [{ role: 'user', content: 'ping' }],\n { maxTokens: 8 },\n );\n const latency = Date.now() - started;\n const preview = String((result as any)?.text ?? '').slice(0, 60);\n return {\n ok: true,\n severity: 'info',\n message: `${built.description} responded in ${latency}ms${preview ? ` — \"${preview}\"` : ''}.`,\n };\n } catch (err: any) {\n return {\n ok: false,\n severity: 'error',\n message: `${built.description} request failed: ${err?.message ?? String(err)}`,\n };\n }\n });\n ctx.logger.info('[AI] Registered live settings action ai/test');\n }\n }\n\n async destroy(): Promise<void> {\n this.service = undefined;\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/**\n * Encode data using Vercel AI SDK Data Stream Protocol prefixes.\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n */\nfunction dataStreamLine(prefix: string, data: object): string {\n return `${prefix}:${JSON.stringify(data)}\\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 // Handle reasoning/thinking streams (DeepSeek R1, o1-style models)\n // Use 'g:' prefix for reasoning content per Vercel AI SDK protocol\n case 'reasoning-start':\n return dataStreamLine('g', { text: '' });\n\n case 'reasoning-delta':\n return dataStreamLine('g', { text: part.text });\n\n case 'reasoning-end':\n return ''; // No specific end marker needed for reasoning\n\n // finish-step and finish are handled by the generator, not here\n default:\n // Pass through any unknown event types that might be custom\n // (e.g., step-start, step-finish from custom providers)\n if ((part as any).type?.startsWith('step-')) {\n return sse(part as any);\n }\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 let errorMessage: string | undefined;\n\n try {\n for await (const part of events) {\n // Surface error parts emitted by the underlying provider stream.\n if ((part as { type: string }).type === 'error') {\n const errPart = part as unknown as { error?: unknown };\n const raw = errPart.error;\n errorMessage =\n (raw && typeof raw === 'object' && 'message' in raw\n ? String((raw as { message: unknown }).message)\n : typeof raw === 'string'\n ? raw\n : 'Unknown provider error');\n finishReason = 'error';\n break;\n }\n\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 } catch (err) {\n // Upstream provider threw (auth failure, network error, etc.). Without\n // this catch the SSE response would hang half-open and the client would\n // never leave its \"streaming\" state.\n errorMessage = err instanceof Error ? err.message : String(err);\n finishReason = 'error';\n }\n\n // Close text if still open (safety)\n if (textOpen) {\n yield sse({ type: 'text-end', id: '0' });\n }\n\n // If we recorded an error, emit it as a UI Message Stream `error` part so\n // the client can display it instead of spinning forever.\n if (errorMessage) {\n yield sse({ type: 'error', errorText: errorMessage });\n }\n\n // Postamble — always emit so the client transitions out of \"streaming\".\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 { ModelMessage } from '@objectstack/spec/contracts';\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 *\n * Shared between the general chat routes and agent chat routes.\n */\nexport function 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 message content/parts format (role-agnostic).\n *\n * Returns `null` when the content shape is valid, or an error string\n * describing the first violation found.\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 * - Null/undefined `content` for assistant messages (when `allowEmpty` is true)\n */\nexport function validateMessageContent(\n msg: Record<string, unknown>,\n opts?: { allowEmptyContent?: boolean },\n): string | null {\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 // Allow empty content for certain roles (e.g. assistant tool-call messages)\n if ((content === null || content === undefined) && opts?.allowEmptyContent) {\n return null;\n }\n\n return 'message.content must be a string, an array, or include parts';\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';\nimport { normalizeMessage, validateMessageContent } from './message-utils.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 * 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\n // Assistant / tool messages may legitimately have null or missing content\n const allowEmpty = msg.role === 'assistant' || msg.role === 'tool';\n return validateMessageContent(msg, { allowEmptyContent: allowEmpty });\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: 'GET',\n path: '/api/v1/ai/conversations/:id',\n description: 'Get a conversation with its full message history',\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 try {\n const conversation = await conversationService.get(id);\n if (!conversation) {\n return { status: 404, body: { error: `Conversation \"${id}\" not found` } };\n }\n if (req.user?.userId && conversation.userId && conversation.userId !== req.user.userId) {\n return { status: 403, body: { error: 'You do not have access to this conversation' } };\n }\n return { status: 200, body: conversation };\n } catch (err) {\n logger.error('[AI Route] GET /conversations/:id 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';\nimport { normalizeMessage, validateMessageContent } from './message-utils.js';\nimport { encodeVercelDataStream } from '../stream/vercel-stream-encoder.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\n // Assistant messages may legitimately have empty content (e.g. tool-call-only)\n const allowEmpty = msg.role === 'assistant';\n return validateMessageContent(msg, { allowEmptyContent: allowEmpty });\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 // Dual-mode endpoint matching the general chat route 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/agents/:agentName/chat',\n description: 'Chat with a specific AI agent (supports Vercel AI Data Stream Protocol)',\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 body = (req.body ?? {}) as Record<string, unknown>;\n const {\n messages: rawMessages,\n context: chatContext,\n options: extraOptions,\n } = 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 // Resolve active skills for this agent in the current context\n const activeSkills = await agentRuntime.resolveActiveSkills(agent, chatContext);\n\n // Build system messages from agent instructions + UI context + skills\n const systemMessages = agentRuntime.buildSystemMessages(agent, chatContext, activeSkills);\n\n // Resolve agent model/tools + skill tools → request options\n const agentOptions = agentRuntime.buildRequestOptions(\n agent,\n aiService.toolRegistry.getAll(),\n activeSkills,\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.map(m => normalizeMessage(m as Record<string, unknown>)),\n ];\n\n const chatWithToolsOptions = {\n ...mergedOptions,\n maxIterations: agent.planning?.maxIterations,\n // Forward authenticated actor → built-in data tools enforce\n // ObjectQL RLS, action tools attribute audit to the user.\n toolExecutionContext: req.user\n ? {\n actor: {\n id: req.user.userId,\n name: req.user.displayName,\n roles: req.user.roles,\n permissions: req.user.permissions,\n },\n conversationId:\n typeof body.conversationId === 'string' ? body.conversationId : undefined,\n environmentId:\n typeof chatContext?.environmentId === 'string'\n ? chatContext.environmentId\n : undefined,\n }\n : undefined,\n };\n\n // ── Choose response mode ─────────────────────────────\n const wantStream = body.stream !== false;\n\n if (wantStream) {\n // Vercel Data Stream Protocol (SSE) — matches general chat behaviour\n if (!aiService.streamChatWithTools) {\n return { status: 501, body: { error: 'Streaming is not supported by the configured AI service' } };\n }\n const events = aiService.streamChatWithTools(fullMessages, chatWithToolsOptions);\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 }\n\n // JSON response (non-streaming / legacy)\n const result = await aiService.chatWithTools(fullMessages, chatWithToolsOptions);\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 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 { SkillRegistry } from '../skill-registry.js';\nimport type { RouteDefinition } from './ai-routes.js';\nimport { normalizeMessage, validateMessageContent } from './message-utils.js';\nimport { encodeVercelDataStream } from '../stream/vercel-stream-encoder.js';\n\nconst ALLOWED_ROLES = new Set<string>(['user', 'assistant']);\n\nfunction validateAssistantMessage(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_ROLES.has(msg.role)) {\n return `message.role must be one of ${[...ALLOWED_ROLES].map(r => `\"${r}\"`).join(', ')} for assistant chat`;\n }\n const allowEmpty = msg.role === 'assistant';\n return validateMessageContent(msg, { allowEmptyContent: allowEmpty });\n}\n\nfunction parseContext(raw: unknown): AgentChatContext {\n if (typeof raw !== 'object' || raw === null) return {};\n const obj = raw as Record<string, unknown>;\n const ctx: AgentChatContext = {};\n for (const key of Object.keys(obj)) {\n ctx[key] = obj[key];\n }\n return ctx;\n}\n\n/**\n * Build ambient assistant routes — the \"single chat entry\" pattern\n * inspired by Claude Code, Salesforce Agentforce, and ServiceNow Now\n * Assist.\n *\n * Unlike `/api/v1/ai/agents/:name/chat`, these endpoints do not require\n * the caller to pre-select an agent. The default agent for the active\n * application is resolved automatically from metadata, skills are\n * filtered by the runtime context, and the LLM decides which tool to\n * invoke.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | GET | /api/v1/ai/assistant | Resolve the active assistant + skills for the given context |\n * | GET | /api/v1/ai/assistant/skills | List active skills (for slash-command palettes) |\n * | POST | /api/v1/ai/assistant/chat | Ambient chat against the resolved default agent |\n */\nexport function buildAssistantRoutes(\n aiService: AIService,\n agentRuntime: AgentRuntime,\n skillRegistry: SkillRegistry,\n logger: Logger,\n): RouteDefinition[] {\n return [\n // ── Resolve current assistant + skill set ──────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/assistant',\n description: 'Resolve the default AI assistant and active skills for a given context',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n try {\n const context = parseContextFromQuery(req.query);\n // Optional explicit agent override (e.g. Studio passes\n // `?agent=metadata_assistant`). Falls back to the standard\n // resolution chain (app.defaultAgent → first active).\n const explicitAgentName = typeof req.query?.agent === 'string' ? req.query.agent : undefined;\n const agent = explicitAgentName\n ? await agentRuntime.loadAgent(explicitAgentName)\n : await agentRuntime.resolveDefaultAgent(context);\n if (!agent) {\n return {\n status: 200,\n body: { agent: null, skills: [] },\n };\n }\n const skills = await agentRuntime.resolveActiveSkills(agent, context);\n return {\n status: 200,\n body: {\n agent: {\n name: agent.name,\n label: agent.label,\n role: agent.role,\n avatar: agent.avatar,\n instructions: agent.instructions,\n },\n skills: skills.map((s) => skillRegistry.toSummary(s)),\n context,\n },\n };\n } catch (err) {\n logger.error('[AI Route] /assistant error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── List active skills (slash-command palette) ─────────────\n {\n method: 'GET',\n path: '/api/v1/ai/assistant/skills',\n description: 'List active AI skills for a given context (used by slash-command palettes)',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n try {\n const context = parseContextFromQuery(req.query);\n // Optional: restrict by query param `agent` to scope to one agent's skill set\n const agentName = typeof req.query?.agent === 'string' ? req.query.agent : undefined;\n let restrictTo: readonly string[] | undefined;\n if (agentName) {\n const agent = await agentRuntime.loadAgent(agentName);\n if (agent?.skills) restrictTo = agent.skills;\n }\n const skills = await skillRegistry.listActiveSkills(context, restrictTo);\n return {\n status: 200,\n body: { skills: skills.map((s) => skillRegistry.toSummary(s)) },\n };\n } catch (err) {\n logger.error('[AI Route] /assistant/skills error', err instanceof Error ? err : undefined);\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Ambient chat (the \"single entry\" Claude-Code pattern) ──\n {\n method: 'POST',\n path: '/api/v1/ai/assistant/chat',\n description: 'Ambient AI chat — auto-resolves agent and skills from context (supports Vercel Data Stream Protocol)',\n auth: true,\n permissions: ['ai:chat'],\n handler: async (req) => {\n const body = (req.body ?? {}) as Record<string, unknown>;\n const {\n messages: rawMessages,\n context: rawContext,\n options: extraOptions,\n agent: explicitAgentName,\n skill: explicitSkillName,\n } = body as {\n messages?: unknown[];\n context?: unknown;\n options?: Record<string, unknown>;\n agent?: string;\n skill?: string;\n };\n\n if (!Array.isArray(rawMessages) || rawMessages.length === 0) {\n return { status: 400, body: { error: 'messages array is required' } };\n }\n for (const msg of rawMessages) {\n const err = validateAssistantMessage(msg);\n if (err) return { status: 400, body: { error: err } };\n }\n\n const context = parseContext(rawContext);\n\n // Resolve agent: explicit > defaultAgent(app) > first active\n const agent = explicitAgentName\n ? await agentRuntime.loadAgent(explicitAgentName)\n : await agentRuntime.resolveDefaultAgent(context);\n\n if (!agent) {\n return {\n status: 404,\n body: { error: 'No active assistant available — register at least one agent or set defaultAgent on the app metadata' },\n };\n }\n if (agent.active === false) {\n return { status: 403, body: { error: `Agent \"${agent.name}\" is not active` } };\n }\n\n try {\n // Resolve active skills. When the caller pinned a slash command via\n // `skill: '<name>'` we restrict to that single skill so the LLM is\n // forced to use it (Claude-Code `/skill-name` semantics).\n let activeSkills = await agentRuntime.resolveActiveSkills(agent, context);\n if (explicitSkillName) {\n activeSkills = activeSkills.filter((s) => s.name === explicitSkillName);\n if (activeSkills.length === 0) {\n const direct = await skillRegistry.loadSkill(explicitSkillName);\n if (direct && direct.active !== false) activeSkills = [direct];\n }\n }\n\n const systemMessages = agentRuntime.buildSystemMessages(agent, context, activeSkills);\n const agentOptions = agentRuntime.buildRequestOptions(\n agent,\n aiService.toolRegistry.getAll(),\n activeSkills,\n );\n\n // Whitelist only safe caller overrides\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)) safeOverrides[key] = extraOptions[key];\n }\n }\n const mergedOptions = { ...agentOptions, ...safeOverrides };\n\n const fullMessages: ModelMessage[] = [\n ...systemMessages,\n ...rawMessages.map((m) => normalizeMessage(m as Record<string, unknown>)),\n ];\n\n const chatWithToolsOptions = {\n ...mergedOptions,\n maxIterations: agent.planning?.maxIterations,\n // Forward the authenticated actor into every tool the loop\n // invokes — built-in data tools promote this into the\n // ObjectQL execution context so row-level security scopes\n // the LLM to whatever the human user can already see/do.\n toolExecutionContext: req.user\n ? {\n actor: {\n id: req.user.userId,\n name: req.user.displayName,\n roles: req.user.roles,\n permissions: req.user.permissions,\n },\n conversationId:\n typeof body.conversationId === 'string' ? body.conversationId : undefined,\n environmentId:\n typeof context.environmentId === 'string' ? context.environmentId : undefined,\n }\n : undefined,\n };\n\n const wantStream = body.stream !== false;\n\n if (wantStream) {\n if (!aiService.streamChatWithTools) {\n return { status: 501, body: { error: 'Streaming is not supported by the configured AI service' } };\n }\n const events = aiService.streamChatWithTools(fullMessages, chatWithToolsOptions);\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 'x-objectstack-agent': agent.name,\n 'x-objectstack-skills': activeSkills.map((s) => s.name).join(','),\n },\n events: encodeVercelDataStream(events),\n };\n }\n\n const result = await aiService.chatWithTools(fullMessages, chatWithToolsOptions);\n\n return {\n status: 200,\n body: {\n ...((result as object) ?? {}),\n _agent: agent.name,\n _skills: activeSkills.map((s) => s.name),\n },\n };\n } catch (err) {\n logger.error(\n '[AI Route] /assistant/chat error',\n err instanceof Error ? err : undefined,\n );\n // Surface a brief upstream message so the client UI can render it\n // instead of an opaque \"Internal AI service error\". Stack traces\n // stay in the logger.\n const upstreamMsg = err instanceof Error ? err.message : String(err);\n return {\n status: 500,\n body: { error: 'Internal AI service error', detail: upstreamMsg },\n };\n }\n },\n },\n ];\n}\n\n/**\n * Parse the runtime context from query-string parameters.\n *\n * Accepts the same field set as {@link AgentChatContext}:\n * `appName`, `objectName`, `recordId`, `viewName`, `channel`, `userRole`.\n * Unknown fields are passed through verbatim so caller-defined trigger\n * conditions remain extensible.\n */\nfunction parseContextFromQuery(query: Record<string, string> | undefined): AgentChatContext {\n if (!query) return {};\n const ctx: AgentChatContext = {};\n for (const [key, value] of Object.entries(query)) {\n if (value == null) continue;\n ctx[key] = value;\n }\n return ctx;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Logger } from '@objectstack/spec/contracts';\nimport type { AIService } from '../ai-service.js';\nimport type { RouteDefinition } from './ai-routes.js';\n\n/**\n * Extract string value from tool execution result output.\n */\nfunction extractOutputValue(output: any): string {\n if (!output) return '';\n if (typeof output === 'string') return output;\n if (typeof output === 'object' && 'value' in output) {\n return String(output.value ?? '');\n }\n return JSON.stringify(output);\n}\n\n/**\n * Build tool-specific REST routes.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | GET | /api/v1/ai/tools | List all registered tools |\n * | POST | /api/v1/ai/tools/:toolName/execute | Execute a tool with parameters |\n */\nexport function buildToolRoutes(\n aiService: AIService,\n logger: Logger,\n): RouteDefinition[] {\n return [\n // ── List registered tools ──────────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/tools',\n description: 'List all registered AI tools',\n auth: true,\n permissions: ['ai:tools'],\n handler: async () => {\n try {\n const tools = aiService.toolRegistry.getAll();\n return {\n status: 200,\n body: {\n tools: tools.map(t => ({\n name: t.name,\n description: t.description,\n category: (t as any).category,\n }))\n }\n };\n } catch (err) {\n logger.error(\n '[AI Route] /tools list error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Internal AI service error' } };\n }\n },\n },\n\n // ── Execute a tool ──────────────────────────────────────────────\n //\n // Executes a tool with the provided parameters.\n // This is intended for testing/playground use.\n //\n {\n method: 'POST',\n path: '/api/v1/ai/tools/:toolName/execute',\n description: 'Execute a tool with parameters (playground/testing)',\n auth: true,\n permissions: ['ai:tools', 'ai:execute'],\n handler: async (req) => {\n const toolName = req.params?.toolName;\n if (!toolName) {\n return { status: 400, body: { error: 'toolName parameter is required' } };\n }\n\n // Parse request body\n const body = (req.body ?? {}) as Record<string, unknown>;\n const { parameters } = body as {\n parameters?: Record<string, unknown>;\n };\n\n if (!parameters || typeof parameters !== 'object') {\n return { status: 400, body: { error: 'parameters object is required' } };\n }\n\n try {\n // Check if tool exists\n if (!aiService.toolRegistry.has(toolName)) {\n return { status: 404, body: { error: `Tool \"${toolName}\" not found` } };\n }\n\n // Execute the tool using ToolRegistry's execute method\n const startTime = Date.now();\n\n const toolCallPart = {\n type: 'tool-call' as const,\n toolCallId: `playground-${Date.now()}`,\n toolName,\n input: parameters,\n };\n\n const result = await aiService.toolRegistry.execute(toolCallPart);\n const duration = Date.now() - startTime;\n\n // Check if execution resulted in an error\n if (result.isError) {\n const errorMsg = extractOutputValue(result.output);\n logger.error(\n `[AI Route] Tool execution error: ${toolName}`,\n new Error(errorMsg),\n );\n return {\n status: 500,\n body: {\n error: errorMsg,\n duration,\n },\n };\n }\n\n return {\n status: 200,\n body: {\n result: extractOutputValue(result.output),\n duration,\n toolName,\n },\n };\n } catch (err) {\n logger.error(\n '[AI Route] /tools/:toolName/execute 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 type { Logger } from '@objectstack/spec/contracts';\nimport type { IAIService } from '@objectstack/spec/contracts';\nimport type { RouteDefinition } from './ai-routes.js';\n\n/**\n * Build pending-action (HITL approval) REST routes.\n *\n * | Method | Path | Description |\n * |:---|:---|:---|\n * | GET | /api/v1/ai/pending-actions | List pending actions (filter by status) |\n * | GET | /api/v1/ai/pending-actions/:id | Get a single pending action |\n * | POST | /api/v1/ai/pending-actions/:id/approve | Approve & execute |\n * | POST | /api/v1/ai/pending-actions/:id/reject | Reject with optional reason |\n *\n * Auth: requires `ai:approve` permission for approve/reject. Listing/reads\n * require the lighter `ai:read` permission so operators can monitor the\n * queue without execution rights.\n */\nexport function buildPendingActionRoutes(\n aiService: IAIService,\n logger: Logger,\n): RouteDefinition[] {\n // Guard: if the AI service doesn't implement HITL methods (e.g. older\n // build or no dataEngine wired), surface a clear 501 instead of NPE.\n const supported =\n typeof aiService.listPendingActions === 'function' &&\n typeof aiService.approvePendingAction === 'function' &&\n typeof aiService.rejectPendingAction === 'function';\n\n if (!supported) {\n logger.warn(\n '[AI] HITL pending-action methods not implemented on AI service — routes return 501.',\n );\n }\n\n const notImpl = () => ({\n status: 501,\n body: { error: 'Pending-action queue not available (dataEngine not wired)' },\n });\n\n return [\n // ── List pending actions ───────────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/pending-actions',\n description: 'List pending actions in the HITL approval queue',\n auth: true,\n permissions: ['ai:read'],\n handler: async (req) => {\n if (!supported) return notImpl();\n try {\n const query = (req.query ?? {}) as Record<string, unknown>;\n const status = typeof query.status === 'string' ? (query.status as any) : undefined;\n const conversationId =\n typeof query.conversationId === 'string' ? query.conversationId : undefined;\n const limitRaw = query.limit;\n const limit = typeof limitRaw === 'string' ? Number(limitRaw) : undefined;\n const rows = await aiService.listPendingActions!({\n status,\n conversationId,\n limit: Number.isFinite(limit) ? limit : undefined,\n });\n return { status: 200, body: { items: rows, total: rows.length } };\n } catch (err) {\n logger.error(\n '[AI Route] /pending-actions list error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Failed to list pending actions' } };\n }\n },\n },\n\n // ── Get a single pending action ────────────────────────────────\n {\n method: 'GET',\n path: '/api/v1/ai/pending-actions/:id',\n description: 'Get a single pending action by id',\n auth: true,\n permissions: ['ai:read'],\n handler: async (req) => {\n if (!supported) return notImpl();\n const id = req.params?.id;\n if (!id) return { status: 400, body: { error: 'id is required' } };\n try {\n const rows = await aiService.listPendingActions!({});\n const found = rows.find(r => r.id === id);\n if (!found) return { status: 404, body: { error: `Pending action ${id} not found` } };\n return { status: 200, body: found };\n } catch (err) {\n logger.error(\n '[AI Route] /pending-actions/:id error',\n err instanceof Error ? err : undefined,\n );\n return { status: 500, body: { error: 'Failed to load pending action' } };\n }\n },\n },\n\n // ── Approve & execute ──────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/pending-actions/:id/approve',\n description: 'Approve a pending action and execute it immediately',\n auth: true,\n permissions: ['ai:approve'],\n handler: async (req) => {\n if (!supported) return notImpl();\n const id = req.params?.id;\n if (!id) return { status: 400, body: { error: 'id is required' } };\n const actorId = req.user?.id ?? 'system';\n try {\n const outcome = await aiService.approvePendingAction!(id, actorId);\n // outcome.status is 'executed' on success, 'failed' on dispatch error\n const httpStatus = outcome.status === 'executed' ? 200 : 500;\n return { status: httpStatus, body: outcome };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error('[AI Route] /pending-actions/:id/approve error', err instanceof Error ? err : undefined);\n // 409 = state conflict (already approved/rejected/etc.); 404 = missing\n if (/not found/i.test(msg)) return { status: 404, body: { error: msg } };\n if (/already|not pending|no dispatcher/i.test(msg)) {\n return { status: 409, body: { error: msg } };\n }\n return { status: 500, body: { error: msg } };\n }\n },\n },\n\n // ── Reject ─────────────────────────────────────────────────────\n {\n method: 'POST',\n path: '/api/v1/ai/pending-actions/:id/reject',\n description: 'Reject a pending action (will not be executed)',\n auth: true,\n permissions: ['ai:approve'],\n handler: async (req) => {\n if (!supported) return notImpl();\n const id = req.params?.id;\n if (!id) return { status: 400, body: { error: 'id is required' } };\n const actorId = req.user?.id ?? 'system';\n const body = (req.body ?? {}) as Record<string, unknown>;\n const reason = typeof body.reason === 'string' ? body.reason : undefined;\n try {\n await aiService.rejectPendingAction!(id, actorId, reason);\n return { status: 200, body: { status: 'rejected', id } };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error('[AI Route] /pending-actions/:id/reject error', err instanceof Error ? err : undefined);\n if (/not found/i.test(msg)) return { status: 404, body: { error: msg } };\n if (/already|not pending/i.test(msg)) {\n return { status: 409, body: { error: msg } };\n }\n return { status: 500, body: { error: msg } };\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 name: 'ai_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',\n required: false,\n maxLength: 128,\n description: 'Associated AI agent (metadata name — agents live as JSON in sys_metadata, no lookup table)',\n }),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n required: false,\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 name: 'ai_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.lookup('ai_conversations', {\n label: 'Conversation',\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 { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * ai_traces — AI Call Trace Object\n *\n * Records every LLM call made through the {@link AIService} for observability,\n * cost attribution, and debugging.\n *\n * One row per `chat()` / `complete()` invocation (tool-call loops produce\n * multiple rows). Persisted via {@link ObjectQLTraceRecorder} when a data\n * engine is available; otherwise traces are no-op.\n *\n * @namespace ai\n */\nexport const AiTraceObject = ObjectSchema.create({\n name: 'ai_traces',\n label: 'AI Trace',\n pluralLabel: 'AI Traces',\n icon: 'activity',\n isSystem: true,\n description: 'Per-call LLM invocation trace with token usage and cost',\n\n fields: {\n id: Field.text({\n label: 'Trace ID',\n required: true,\n readonly: true,\n }),\n\n conversation_id: Field.lookup('ai_conversations', {\n label: 'Conversation',\n required: false,\n description: 'Parent conversation, if any',\n }),\n\n agent_id: Field.text({\n label: 'Agent',\n required: false,\n maxLength: 128,\n description: 'Agent metadata name that originated the call',\n }),\n\n operation: Field.select({\n label: 'Operation',\n required: true,\n options: [\n { label: 'Chat', value: 'chat' },\n { label: 'Complete', value: 'complete' },\n { label: 'Stream Chat', value: 'stream_chat' },\n { label: 'Chat With Tools', value: 'chat_with_tools' },\n { label: 'Generate Object', value: 'generate_object' },\n { label: 'Embed', value: 'embed' },\n ],\n }),\n\n model: Field.text({\n label: 'Model',\n required: false,\n maxLength: 128,\n description: 'Model identifier reported by the adapter',\n }),\n\n adapter: Field.text({\n label: 'Adapter',\n required: false,\n maxLength: 64,\n description: 'LLM adapter name (e.g. \"vercel\", \"memory\")',\n }),\n\n prompt_tokens: Field.number({\n label: 'Prompt Tokens',\n required: false,\n defaultValue: 0,\n }),\n\n completion_tokens: Field.number({\n label: 'Completion Tokens',\n required: false,\n defaultValue: 0,\n }),\n\n total_tokens: Field.number({\n label: 'Total Tokens',\n required: false,\n defaultValue: 0,\n }),\n\n input_cost: Field.number({\n label: 'Input Cost',\n required: false,\n description: 'Cost attributable to prompt tokens (currency in `currency` field)',\n }),\n\n output_cost: Field.number({\n label: 'Output Cost',\n required: false,\n description: 'Cost attributable to completion tokens',\n }),\n\n total_cost: Field.number({\n label: 'Total Cost',\n required: false,\n description: 'input_cost + output_cost',\n }),\n\n currency: Field.text({\n label: 'Currency',\n required: false,\n maxLength: 8,\n defaultValue: 'USD',\n }),\n\n latency_ms: Field.number({\n label: 'Latency (ms)',\n required: true,\n defaultValue: 0,\n description: 'Wall-clock duration of the LLM call',\n }),\n\n status: Field.select({\n label: 'Status',\n required: true,\n options: [\n { label: 'Success', value: 'success' },\n { label: 'Error', value: 'error' },\n ],\n }),\n\n error: Field.textarea({\n label: 'Error',\n required: false,\n description: 'Error message when status=error',\n }),\n\n metadata: Field.textarea({\n label: 'Metadata',\n required: false,\n description: 'JSON-serialized extra fields (request id, user id, …)',\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: ['agent_id'] },\n { fields: ['model'] },\n { fields: ['status'] },\n { fields: ['created_at'] },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list'],\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_pending_actions — Human-in-the-Loop queue for AI-initiated actions.\n *\n * When the agent picks a tool that maps to a dangerous declarative action\n * (delete, danger variant, or any action with `confirmText`), the tool\n * runtime does **not** dispatch immediately. Instead it persists a row\n * here and returns a `{ status: 'pending_approval', pendingActionId }`\n * envelope so the LLM can summarise the request. A human then approves\n * (or rejects) via Studio's pending-actions inbox, at which point the\n * service re-dispatches the action with full permissions.\n *\n * One row per proposed tool call. Lifecycle:\n * pending → approved → executed (happy path)\n * ↘ approved → failed (execution blew up)\n * ↘ rejected (human said no)\n *\n * @namespace ai\n */\nexport const AiPendingActionObject = ObjectSchema.create({\n name: 'ai_pending_actions',\n label: 'AI Pending Action',\n pluralLabel: 'AI Pending Actions',\n icon: 'shield-check',\n isSystem: true,\n description: 'Queue of AI-proposed action invocations awaiting human approval',\n\n fields: {\n id: Field.text({\n label: 'Request ID',\n required: true,\n readonly: true,\n }),\n\n conversation_id: Field.lookup('ai_conversations', {\n label: 'Conversation',\n required: false,\n description: 'Conversation that produced this proposal, if any',\n }),\n\n message_id: Field.lookup('ai_messages', {\n label: 'Message',\n required: false,\n description: 'Assistant message containing the proposed tool call',\n }),\n\n object_name: Field.text({\n label: 'Object',\n required: true,\n maxLength: 128,\n description: 'Target object name (e.g. \"task\")',\n }),\n\n action_name: Field.text({\n label: 'Action',\n required: true,\n maxLength: 128,\n description: 'Declarative action name (e.g. \"delete_task\")',\n }),\n\n tool_name: Field.text({\n label: 'Tool',\n required: true,\n maxLength: 128,\n description: 'AI tool name exposed to the LLM (e.g. \"action_delete_task\")',\n }),\n\n tool_input: Field.textarea({\n label: 'Tool Input',\n required: true,\n description: 'JSON-serialised tool arguments the LLM passed',\n }),\n\n status: Field.select({\n label: 'Status',\n required: true,\n defaultValue: 'pending',\n options: [\n { label: 'Pending Approval', value: 'pending' },\n { label: 'Approved (queued)', value: 'approved' },\n { label: 'Executed', value: 'executed' },\n { label: 'Failed', value: 'failed' },\n { label: 'Rejected', value: 'rejected' },\n ],\n }),\n\n result: Field.textarea({\n label: 'Execution Result',\n required: false,\n description: 'JSON-serialised result from the action when executed',\n }),\n\n error: Field.textarea({\n label: 'Error',\n required: false,\n description: 'Error message when status=failed',\n }),\n\n rejection_reason: Field.textarea({\n label: 'Rejection Reason',\n required: false,\n description: 'Why the reviewer rejected (shown back to the LLM)',\n }),\n\n proposed_by: Field.text({\n label: 'Proposed By',\n required: false,\n maxLength: 128,\n description: 'Principal id of the AI agent that proposed the action',\n }),\n\n decided_by: Field.text({\n label: 'Decided By',\n required: false,\n maxLength: 128,\n description: 'User id of the human who approved/rejected',\n }),\n\n proposed_at: Field.datetime({\n label: 'Proposed At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n decided_at: Field.datetime({\n label: 'Decided At',\n required: false,\n description: 'When approve/reject happened',\n }),\n },\n\n indexes: [\n { fields: ['status'] },\n { fields: ['conversation_id'] },\n { fields: ['object_name'] },\n { fields: ['proposed_at'] },\n ],\n\n actions: [\n {\n name: 'approve_pending_action',\n label: 'Approve',\n type: 'api',\n target: '/api/v1/ai/pending-actions/{recordId}/approve',\n method: 'POST',\n locations: ['list_item', 'record_header'],\n variant: 'primary',\n confirmText: 'Approve and execute this action now?',\n successMessage: 'Action approved and executed.',\n // The approval click is the operator's authorisation gesture —\n // the LLM must not be allowed to bypass HITL by approving itself.\n aiExposed: false,\n },\n {\n name: 'reject_pending_action',\n label: 'Reject',\n type: 'api',\n target: '/api/v1/ai/pending-actions/{recordId}/reject',\n method: 'POST',\n locations: ['list_item', 'record_header'],\n variant: 'danger',\n confirmText: 'Reject this pending action? It will not be executed.',\n successMessage: 'Action rejected.',\n aiExposed: false,\n },\n ],\n\n enable: {\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineView } from '@objectstack/spec';\n\n/**\n * ai_traces — built-in Studio list view.\n *\n * Exposes per-call observability for every LLM invocation that flowed\n * through the `AIService`. Ships with the platform so users don't have\n * to author a view for an object they didn't create.\n *\n * - Default list: grid sorted by `created_at` desc, showing the columns an\n * operator usually wants at a glance (operation, model, latency, tokens,\n * cost, status).\n * - `errors` view: pre-filtered to status=\"error\" for triage.\n * - `by_model` view: grouped by model for cost / quality comparison.\n *\n * Registered via the AIService plugin's manifest payload — appears\n * automatically in Studio when AIService is loaded.\n */\nexport const AiTraceView = defineView({\n list: {\n type: 'grid',\n data: { provider: 'object', object: 'ai_traces' },\n columns: [\n { field: 'created_at', label: 'Time' },\n { field: 'operation' },\n { field: 'model' },\n { field: 'agent_id', label: 'Agent' },\n { field: 'latency_ms', label: 'Latency (ms)' },\n { field: 'total_tokens', label: 'Tokens' },\n { field: 'cost_total', label: 'Cost' },\n { field: 'status' },\n ],\n sort: [{ field: 'created_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n searchableFields: ['conversation_id', 'agent_id', 'model', 'error'],\n filterableFields: ['operation', 'model', 'status'],\n },\n listViews: {\n errors: {\n label: 'Errors',\n type: 'grid',\n data: { provider: 'object', object: 'ai_traces' },\n columns: [\n { field: 'created_at', label: 'Time' },\n { field: 'operation' },\n { field: 'model' },\n { field: 'latency_ms', label: 'Latency (ms)' },\n { field: 'error' },\n ],\n filter: [\n { field: 'status', operator: '=', value: 'error' },\n ],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n by_model: {\n label: 'By Model',\n type: 'grid',\n data: { provider: 'object', object: 'ai_traces' },\n columns: [\n { field: 'model' },\n { field: 'operation' },\n { field: 'latency_ms', label: 'Latency (ms)' },\n { field: 'total_tokens', label: 'Tokens' },\n { field: 'cost_total', label: 'Cost' },\n { field: 'status' },\n { field: 'created_at', label: 'Time' },\n ],\n grouping: { fields: [{ field: 'model' }] },\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineView } from '@objectstack/spec';\n\n/**\n * ai_pending_actions — built-in Studio inbox view.\n *\n * Surfaces the HITL approval queue: every action the LLM proposed that\n * was classified \"dangerous\" (confirmText, mode='delete', variant='danger')\n * and gated behind human approval. Operators triage from this list and\n * either Approve (re-runs the action immediately under the AI principal)\n * or Reject (closes the row without execution).\n *\n * ## UI shape\n *\n * Studio renders three things from this definition:\n *\n * 1. A **list view** with four named tabs — pending / executed / rejected /\n * failed — sorted reverse-chronologically. Each row is clickable.\n * 2. A **drawer detail view** (opened on row click) that shows the full\n * tool-call envelope, the LLM context (conversation + message links),\n * decision trail (proposed_at / decided_at relative timestamps), and\n * outcome (result / error / rejection_reason in collapsible sections).\n * 3. The two object-level actions (`approve_pending_action`,\n * `reject_pending_action`, declared on the object schema with\n * `locations: ['list_item', 'record_header']`) are surfaced as both\n * row-level buttons in the grid and primary buttons in the drawer\n * header, hitting the REST contract directly.\n *\n * The drawer is conditionally-actionable: Approve/Reject buttons are only\n * useful for `status='pending'` rows, but Studio's per-row action filtering\n * handles that via the underlying record state.\n *\n * Bundled with the platform so users don't need to author a view for\n * a system table. Appears automatically in Studio when AIService is\n * loaded with `enableActionApproval: true`.\n */\nexport const AiPendingActionView = defineView({\n list: {\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'proposed_at', label: 'Proposed', type: 'datetime-relative', width: 140 },\n { field: 'status', width: 130 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'proposed_by', label: 'Proposed by', width: 160 },\n { field: 'decided_by', label: 'Decided by', width: 160 },\n { field: 'decided_at', label: 'Decided', type: 'datetime-relative', width: 140 },\n ],\n sort: [{ field: 'proposed_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n searchableFields: ['action_name', 'object_name', 'tool_name', 'proposed_by'],\n filterableFields: ['status', 'object_name', 'action_name'],\n rowActions: ['approve_pending_action', 'reject_pending_action'],\n // Click a row → open the detail drawer instead of navigating to a page.\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n rowColor: {\n field: 'status',\n mapping: {\n pending: 'amber',\n approved: 'blue',\n executed: 'green',\n failed: 'red',\n rejected: 'gray',\n },\n } as never,\n },\n\n form: {\n type: 'drawer',\n data: { provider: 'object', object: 'ai_pending_actions' },\n sections: [\n {\n label: 'Proposal',\n columns: 2,\n fields: [\n { field: 'status', readonly: true },\n { field: 'proposed_at', readonly: true, widget: 'datetime-relative' },\n { field: 'object_name', label: 'Target object', readonly: true },\n { field: 'action_name', label: 'Action', readonly: true },\n { field: 'tool_name', label: 'Tool exposed to LLM', readonly: true, colSpan: 2 },\n { field: 'proposed_by', label: 'Proposed by (AI agent)', readonly: true, colSpan: 2 },\n ],\n },\n {\n label: 'Tool input',\n collapsible: true,\n columns: 1,\n fields: [\n {\n field: 'tool_input',\n label: 'Arguments the LLM sent',\n readonly: true,\n widget: 'json',\n colSpan: 1,\n helpText: 'Pretty-printed JSON. Review carefully before approving — this is the exact payload that will be re-played against the handler.',\n },\n ],\n },\n {\n label: 'Conversation context',\n collapsible: true,\n collapsed: true,\n columns: 2,\n fields: [\n // Both are lookups — Studio renders them as links to the related\n // ai_conversations / ai_messages record so operators can jump to\n // the full transcript for context.\n { field: 'conversation_id', label: 'Conversation', readonly: true },\n { field: 'message_id', label: 'Assistant message', readonly: true },\n ],\n },\n {\n label: 'Decision',\n collapsible: true,\n // Only meaningful once the row has been actioned; left collapsed\n // by default for pending rows so the eye lands on the proposal.\n collapsed: true,\n columns: 2,\n fields: [\n { field: 'decided_by', label: 'Decided by', readonly: true },\n { field: 'decided_at', label: 'Decided', readonly: true, widget: 'datetime-relative' },\n {\n field: 'rejection_reason',\n label: 'Rejection reason',\n readonly: true,\n colSpan: 2,\n visibleOn: 'record.status == \"rejected\"',\n },\n {\n field: 'result',\n label: 'Execution result',\n readonly: true,\n widget: 'json',\n colSpan: 2,\n visibleOn: 'record.status == \"executed\"',\n },\n {\n field: 'error',\n label: 'Error',\n readonly: true,\n colSpan: 2,\n visibleOn: 'record.status == \"failed\"',\n },\n ],\n },\n ],\n },\n\n formViews: {\n detail: {\n type: 'drawer',\n data: { provider: 'object', object: 'ai_pending_actions' },\n // Mirror of the default form. Named separately so the list's\n // `navigation.view: 'detail'` resolves explicitly — Studio falls back\n // to `form` if a named view isn't registered, but being explicit\n // makes the wiring legible to readers of the metadata.\n sections: [\n {\n label: 'Proposal',\n columns: 2,\n fields: [\n { field: 'status', readonly: true },\n { field: 'proposed_at', readonly: true, widget: 'datetime-relative' },\n { field: 'object_name', label: 'Target object', readonly: true },\n { field: 'action_name', label: 'Action', readonly: true },\n { field: 'tool_name', label: 'Tool exposed to LLM', readonly: true, colSpan: 2 },\n { field: 'proposed_by', label: 'Proposed by (AI agent)', readonly: true, colSpan: 2 },\n ],\n },\n {\n label: 'Tool input',\n collapsible: true,\n columns: 1,\n fields: [\n { field: 'tool_input', label: 'Arguments the LLM sent', readonly: true, widget: 'json' },\n ],\n },\n {\n label: 'Conversation context',\n collapsible: true,\n collapsed: true,\n columns: 2,\n fields: [\n { field: 'conversation_id', label: 'Conversation', readonly: true },\n { field: 'message_id', label: 'Assistant message', readonly: true },\n ],\n },\n {\n label: 'Decision',\n collapsible: true,\n collapsed: true,\n columns: 2,\n fields: [\n { field: 'decided_by', label: 'Decided by', readonly: true },\n { field: 'decided_at', label: 'Decided', readonly: true, widget: 'datetime-relative' },\n { field: 'rejection_reason', label: 'Rejection reason', readonly: true, colSpan: 2, visibleOn: 'record.status == \"rejected\"' },\n { field: 'result', label: 'Execution result', readonly: true, widget: 'json', colSpan: 2, visibleOn: 'record.status == \"executed\"' },\n { field: 'error', label: 'Error', readonly: true, colSpan: 2, visibleOn: 'record.status == \"failed\"' },\n ],\n },\n ],\n },\n },\n\n listViews: {\n pending: {\n label: 'Pending',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'proposed_at', label: 'Proposed', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'proposed_by', label: 'Proposed by', width: 160 },\n { field: 'tool_name', label: 'Tool', width: 200 },\n ],\n filter: [{ field: 'status', operator: '=', value: 'pending' }],\n sort: [{ field: 'proposed_at', order: 'desc' }],\n rowActions: ['approve_pending_action', 'reject_pending_action'],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n },\n executed: {\n label: 'Executed',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'decided_at', label: 'Approved', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'decided_by', label: 'Approved by', width: 160 },\n { field: 'proposed_by', label: 'Proposed by', width: 160 },\n ],\n filter: [{ field: 'status', operator: '=', value: 'executed' }],\n sort: [{ field: 'decided_at', order: 'desc' }],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n },\n rejected: {\n label: 'Rejected',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'decided_at', label: 'Rejected', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'decided_by', label: 'Rejected by', width: 160 },\n { field: 'rejection_reason', label: 'Reason', wrap: true },\n ],\n filter: [{ field: 'status', operator: '=', value: 'rejected' }],\n sort: [{ field: 'decided_at', order: 'desc' }],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n },\n failed: {\n label: 'Failed',\n type: 'grid',\n data: { provider: 'object', object: 'ai_pending_actions' },\n columns: [\n { field: 'decided_at', label: 'When', type: 'datetime-relative', width: 140 },\n { field: 'object_name', label: 'Object', width: 140 },\n { field: 'action_name', label: 'Action', width: 180 },\n { field: 'error', wrap: true },\n ],\n filter: [{ field: 'status', operator: '=', value: 'failed' }],\n sort: [{ field: 'decided_at', order: 'desc' }],\n navigation: { mode: 'drawer', view: 'detail', width: '640px' },\n },\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { z } from 'zod';\nimport type {\n AIToolDefinition,\n IAIService,\n IDataEngine,\n IMetadataService,\n ModelMessage,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport { SchemaRetriever } from '../schema-retriever.js';\nimport type { ToolHandler, ToolRegistry, ToolExecutionContext } from './tool-registry.js';\n\n/** See `data-tools.ts#buildEngineContext` — duplicated here to keep\n * this single-tool module dependency-free from the data-tools file. */\nfunction buildAiEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\n}\n\n/**\n * Context for the `query_data` tool.\n *\n * Wires together the three services it needs:\n * - {@link IAIService} for structured-output generation of the ObjectQL query\n * - {@link IMetadataService} for schema discovery\n * - {@link IDataEngine} for actually executing the resolved query\n */\nexport interface QueryDataToolContext {\n ai: IAIService;\n metadata: IMetadataService;\n dataEngine: IDataEngine;\n /** Maximum number of records returned per call (default: 100). */\n maxLimit?: number;\n}\n\n/**\n * Zod schema used to constrain the LLM's structured output.\n *\n * Kept small and strict — every property is documented so providers like\n * OpenAI Structured Outputs and Anthropic Tool Use can render high-quality\n * prompts from the schema metadata.\n *\n * NOTE: `where` is intentionally typed as a JSON string rather than a free-form\n * record. OpenAI's Structured Outputs surface rejects `propertyNames`\n * (which Zod's `z.record(z.string(), ...)` emits), and Anthropic's tool-use\n * surface dislikes open-ended object schemas without `additionalProperties`.\n * Having the model emit a JSON-encoded filter sidesteps both restrictions and\n * keeps the tool portable across providers.\n */\nconst QueryPlanSchema = z.object({\n objectName: z\n .string()\n .min(1)\n .describe('The snake_case object name to query (e.g. \"task\", \"account\").'),\n whereJson: z\n .string()\n .nullable()\n .describe(\n 'Filter conditions encoded as a JSON object string. Examples: ' +\n '`{\"status\":\"completed\"}`, `{\"subject\":{\"$contains\":\"Build\"}}`, ' +\n '`{\"amount\":{\"$gt\":100}}`. Pass null to match all records.',\n ),\n fields: z\n .array(z.string())\n .nullable()\n .describe('Field names to return. Pass null to return all fields.'),\n orderBy: z\n .array(\n z.object({\n field: z.string(),\n order: z.enum(['asc', 'desc']),\n }),\n )\n .nullable()\n .describe('Sort order. First entry is primary sort key. Pass null for no sort.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(200)\n .nullable()\n .describe('Maximum number of records (default 20, max 200). Pass null for default.'),\n});\n\n/** Strongly-typed query plan inferred from the LLM. */\nexport type QueryPlan = z.infer<typeof QueryPlanSchema>;\n\n/**\n * Tool definition advertised to the LLM in the outer tool-call loop.\n *\n * The model invokes this tool with a single `request` argument — a\n * paraphrased question. The handler then performs:\n * 1. Schema retrieval (keyword match on the metadata catalogue)\n * 2. Structured-output generation of an ObjectQL plan (via Zod schema)\n * 3. Execution of that plan against the data engine\n * 4. Returns the results as JSON for the model to summarise.\n *\n * This collapses what used to be \"schema retriever middleware + NLQ service\"\n * into one tool, fully consistent with the platform's tool-calling pattern.\n */\nexport const QUERY_DATA_TOOL: AIToolDefinition = {\n name: 'query_data',\n description:\n 'Answer a natural-language question about the user\\'s data. ' +\n 'Internally retrieves the relevant object schema, generates an ObjectQL ' +\n 'query, executes it, and returns the matching records. Prefer this tool ' +\n 'over `query_records` / `aggregate_data` when the user\\'s intent is ' +\n 'expressed in plain language.',\n parameters: {\n type: 'object',\n properties: {\n request: {\n type: 'string',\n description:\n 'The natural-language question to answer (paraphrase the user\\'s ' +\n 'request if needed for clarity).',\n },\n },\n required: ['request'],\n additionalProperties: false,\n },\n};\n\n/**\n * Create a handler for the `query_data` tool.\n *\n * The handler is intentionally stateless — every call performs a fresh\n * schema lookup so newly registered objects are picked up immediately.\n */\nexport function createQueryDataHandler(ctx: QueryDataToolContext): ToolHandler {\n const retriever = new SchemaRetriever(ctx.metadata);\n const maxLimit = ctx.maxLimit ?? 100;\n\n return async (args, execCtx) => {\n const { request } = args as { request: string };\n\n if (!request || typeof request !== 'string') {\n return JSON.stringify({ error: 'query_data: `request` is required' });\n }\n\n if (!ctx.ai.generateObject) {\n return JSON.stringify({\n error:\n 'query_data requires structured-output support. Configure a ' +\n 'Vercel-AI-SDK-backed adapter (OpenAI, Anthropic, Google).',\n });\n }\n\n // 1. Schema retrieval\n const hits = await retriever.retrieve(request);\n if (hits.length === 0) {\n return JSON.stringify({\n error:\n 'No matching objects in metadata. Ask the user which object(s) ' +\n 'to query, or list available objects via list_objects.',\n });\n }\n const snippet = SchemaRetriever.renderSnippet(hits);\n\n // 2. Plan generation\n const planMessages: ModelMessage[] = [\n {\n role: 'system',\n content:\n 'You translate user data questions into a single ObjectQL query plan. ' +\n 'Use ONLY the objects and fields listed in the schema context below. ' +\n 'Never invent field names. If the question is ambiguous, pick the ' +\n 'most likely interpretation and use a reasonable `limit`.\\n\\n' +\n 'Filter operator hints:\\n' +\n ' • For partial string matches (e.g. \"task named Foo\", \"find X\"), ' +\n 'use case-insensitive substring matching with `$contains`: ' +\n '`{\"subject\": {\"$contains\": \"Foo\"}}`. Do NOT use equality unless ' +\n 'the user clearly supplied the exact full value.\\n' +\n ' • For numeric/date ranges use `$gt` / `$gte` / `$lt` / `$lte`.\\n' +\n ' • For \"is one of\" use `$in: [...]`.\\n' +\n ' • For exact equality just write the value: `{\"status\": \"completed\"}`.\\n\\n' +\n snippet,\n },\n { role: 'user', content: request },\n ];\n\n let plan: QueryPlan;\n try {\n const generated = await ctx.ai.generateObject(planMessages, QueryPlanSchema, {\n schemaName: 'ObjectQLQueryPlan',\n schemaDescription: 'A single ObjectQL find() query to answer the user request.',\n });\n plan = generated.object;\n } catch (err) {\n return JSON.stringify({\n error: `Failed to plan query: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // 3. Validate the plan against the retrieved schema\n const matchedObject = hits.find(h => h.object.name === plan.objectName)?.object\n ?? hits[0].object;\n if (matchedObject.name !== plan.objectName) {\n return JSON.stringify({\n error:\n `Planned object \"${plan.objectName}\" is not in the retrieved schema. ` +\n `Available: ${hits.map(h => h.object.name).join(', ')}`,\n });\n }\n\n // 4. Execution\n const limit = Math.min(plan.limit ?? 20, maxLimit);\n let where: Record<string, unknown> | undefined;\n if (plan.whereJson) {\n try {\n const parsed = JSON.parse(plan.whereJson);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n where = parsed as Record<string, unknown>;\n } else {\n return JSON.stringify({\n plan,\n error: `whereJson must encode a JSON object, got: ${plan.whereJson}`,\n });\n }\n } catch (err) {\n return JSON.stringify({\n plan,\n error: `whereJson is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n try {\n const records = await ctx.dataEngine.find(plan.objectName, {\n where,\n fields: plan.fields ?? undefined,\n orderBy: plan.orderBy ?? undefined,\n limit,\n context: buildAiEngineContext(execCtx),\n });\n return JSON.stringify({\n plan: { ...plan, where },\n count: records.length,\n records,\n });\n } catch (err) {\n return JSON.stringify({\n plan,\n error: `Query execution failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n };\n}\n\n/**\n * Register the `query_data` tool on the given {@link ToolRegistry}.\n *\n * Typically called from {@link AIServicePlugin.start} once the AI, metadata,\n * and data services are all available.\n */\nexport function registerQueryDataTool(\n registry: ToolRegistry,\n context: QueryDataToolContext,\n): void {\n registry.register(QUERY_DATA_TOOL, createQueryDataHandler(context));\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { IMetadataService } from '@objectstack/spec/contracts';\n\n/**\n * SchemaRetriever — Keyword-based metadata retrieval for AI prompts.\n *\n * Given a free-text query (typically the user's last message), surfaces the\n * most relevant `object` definitions and renders a compact schema snippet\n * suitable for injection into the system prompt.\n *\n * v1 strategy is intentionally simple:\n * - Tokenise the query into lower-case alphanumeric terms\n * - Score each registered object by counting term hits against its name,\n * label, field names, and field labels\n * - Return the top `limit` matches above the score threshold\n *\n * This does *not* use embeddings — for v1 the user-defined object catalogue\n * is small enough (< 1000 objects in practice) that a single linear scan\n * over already-cached metadata is faster than a vector round-trip and\n * eliminates the need for a vector store.\n *\n * Future versions can swap in {@link IAIService.embed} backed retrieval\n * behind the same `retrieve()` shape.\n *\n * @example\n * ```ts\n * const retriever = new SchemaRetriever(metadataService);\n * const hits = await retriever.retrieve('how many open tasks are due this week?');\n * const snippet = SchemaRetriever.renderSnippet(hits);\n * // snippet:\n * // ## Schema context (auto-injected)\n * // ### task — Project Task\n * // - id: text\n * // - title: text\n * // - status: select(open|in_progress|done)\n * // - due_date: date\n * ```\n */\nexport class SchemaRetriever {\n private readonly metadata: IMetadataService;\n private readonly options: Required<SchemaRetrieverOptions>;\n\n constructor(metadata: IMetadataService, options: SchemaRetrieverOptions = {}) {\n this.metadata = metadata;\n this.options = {\n limit: options.limit ?? 3,\n minScore: options.minScore ?? 1,\n maxFieldsPerObject: options.maxFieldsPerObject ?? 12,\n };\n }\n\n /**\n * Find object definitions whose name/label/fields match terms in the query.\n *\n * Returns matches sorted by score (descending) capped at `limit`. When\n * the query yields no matches, returns an empty array — callers may\n * fall back to a generic \"describe what data exists\" tool call.\n */\n async retrieve(query: string): Promise<SchemaHit[]> {\n const terms = tokenise(query);\n if (terms.length === 0) return [];\n\n const objects = await this.metadata.listObjects();\n const hits: SchemaHit[] = [];\n\n for (const raw of objects) {\n const obj = raw as ObjectShape;\n if (!obj?.name) continue;\n const score = scoreObject(obj, terms);\n if (score >= this.options.minScore) {\n hits.push({ object: obj, score });\n }\n }\n\n hits.sort((a, b) => b.score - a.score);\n return hits.slice(0, this.options.limit);\n }\n\n /**\n * Render hits as a compact Markdown schema snippet.\n *\n * Designed to be appended to the system message — every line carries\n * exactly the information a model needs to choose object/field names\n * for query construction.\n */\n static renderSnippet(hits: SchemaHit[], maxFieldsPerObject = 12): string {\n if (hits.length === 0) return '';\n const lines: string[] = ['## Schema context (auto-injected)'];\n for (const hit of hits) {\n const obj = hit.object;\n // Emit `### name — Label (Plural)` so downstream consumers (system\n // prompt for the LLM, MemoryAdapter heuristic) can score by either\n // the machine name, the singular label, or the plural label. Real\n // users typically say \"show me my tasks\", not \"list todo_task\".\n const parts: string[] = [];\n if (obj.label) parts.push(obj.label);\n if (obj.pluralLabel && obj.pluralLabel !== obj.label) parts.push(`(${obj.pluralLabel})`);\n const header = parts.length > 0 ? ` — ${parts.join(' ')}` : '';\n lines.push(`### ${obj.name}${header}`);\n const fields = Object.entries(obj.fields ?? {}).slice(0, maxFieldsPerObject);\n for (const [name, field] of fields) {\n lines.push(` - ${name}: ${describeField(field)}`);\n }\n const total = Object.keys(obj.fields ?? {}).length;\n if (total > fields.length) {\n lines.push(` - …${total - fields.length} more field(s)`);\n }\n }\n return lines.join('\\n');\n }\n}\n\n/** A scored retrieval result. */\nexport interface SchemaHit {\n object: ObjectShape;\n score: number;\n}\n\n/** Options for {@link SchemaRetriever}. */\nexport interface SchemaRetrieverOptions {\n /** Maximum number of objects to return (default: 3). */\n limit?: number;\n /** Minimum score required to include an object (default: 1). */\n minScore?: number;\n /** Maximum fields rendered per object in the snippet (default: 12). */\n maxFieldsPerObject?: number;\n}\n\n/** Minimal shape of an object definition we care about. */\nexport interface ObjectShape {\n name: string;\n label?: string;\n pluralLabel?: string;\n description?: string;\n fields?: Record<string, FieldShape>;\n}\n\n/** Minimal shape of a field definition. */\nexport interface FieldShape {\n type?: string;\n label?: string;\n options?: unknown;\n reference?: string;\n}\n\n// ── internal helpers ──────────────────────────────────────────────\n\n/** Lower-case alphanumeric tokens of length ≥ 2 (English stop-words excluded). */\nfunction tokenise(query: string): string[] {\n // Split on any non-alphanumeric (including underscores) so `todo_task`\n // tokenises to ['todo', 'task'] and matches snake_case object names.\n const raw = query.toLowerCase().match(/[a-z0-9]+/g) ?? [];\n return raw.filter(t => t.length >= 2 && !STOPWORDS.has(t));\n}\n\nconst STOPWORDS = new Set([\n 'the', 'and', 'for', 'with', 'from', 'are', 'has', 'have', 'had', 'was', 'were',\n 'this', 'that', 'these', 'those', 'all', 'any', 'how', 'what', 'when', 'where',\n 'who', 'why', 'which', 'show', 'list', 'find', 'get', 'count', 'of', 'in', 'on',\n 'at', 'to', 'as', 'by', 'is', 'it', 'an', 'or', 'be', 'me',\n]);\n\n/**\n * Score an object by term hits.\n *\n * Weights: name match = 3, label match = 2, description match = 1,\n * field name match = 2, field label match = 1. A term may contribute at\n * most once per field source.\n */\nfunction scoreObject(obj: ObjectShape, terms: string[]): number {\n let score = 0;\n const nameTokens = splitSnake(obj.name);\n const labelTokens = obj.label ? tokenise(obj.label) : [];\n const pluralTokens = obj.pluralLabel ? tokenise(obj.pluralLabel) : [];\n const descTokens = obj.description ? tokenise(obj.description) : [];\n\n for (const term of terms) {\n if (nameTokens.includes(term)) score += 3;\n else if (labelTokens.includes(term) || pluralTokens.includes(term)) score += 2;\n else if (descTokens.includes(term)) score += 1;\n }\n\n for (const [fieldName, field] of Object.entries(obj.fields ?? {})) {\n const fnTokens = splitSnake(fieldName);\n const flTokens = field.label ? tokenise(field.label) : [];\n for (const term of terms) {\n if (fnTokens.includes(term)) score += 2;\n else if (flTokens.includes(term)) score += 1;\n }\n }\n\n return score;\n}\n\n/** Split snake_case identifier into lower-case word tokens. */\nfunction splitSnake(name: string): string[] {\n return name.toLowerCase().split('_').filter(Boolean);\n}\n\n/** Compact human-readable description of a field's type. */\nfunction describeField(field: FieldShape): string {\n const t = field.type ?? 'unknown';\n if (t === 'lookup' && field.reference) return `lookup → ${field.reference}`;\n if (t === 'select' && Array.isArray(field.options)) {\n const values = field.options\n .map((o: unknown) =>\n typeof o === 'string' ? o : (o as { value?: string }).value,\n )\n .filter(Boolean)\n .slice(0, 6);\n return `select(${values.join('|')})`;\n }\n return t;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Actions-as-Tools — turn declarative {@link Action} metadata into\n * AI-callable tools so an agent can not only **read** the user's data\n * (via `query_data` / `data_explorer`) but also **act** on it.\n *\n * Phase 1 scope (this module):\n * - Only `type: 'script'` actions are auto-exposed. Their handler is\n * resolved through {@link IDataEngine.executeAction} (the same\n * dispatcher used by Studio's \"row toolbar\" buttons), so the LLM\n * ends up calling exactly the same business logic the UI does.\n * - Skip any action that is dangerous (`confirmText`, `variant: 'danger'`,\n * `mode: 'delete'`) — these require Phase 2 HITL plumbing.\n * - Skip any action whose owner opted out via `aiExposed: false` (the\n * hint is read from the action record but not formalised in the Zod\n * schema yet; spec change is backwards-compatible additive).\n *\n * The tool's JSON Schema is materialised from `action.params[]`,\n * resolving field-backed params (`{ field: 'priority' }`) against the\n * owning object so the LLM sees the same type/options/required\n * constraints the modal dialog would render.\n */\n\nimport type {\n AIToolDefinition,\n IAutomationService,\n IDataEngine,\n IMetadataService,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport type { Action, ActionParam } from '@objectstack/spec/ui';\nimport type { ToolHandler, ToolRegistry, ToolExecutionContext } from './tool-registry.js';\n\n/** Minimal field shape we care about when resolving param types. */\ninterface FieldDef {\n type?: string;\n label?: string;\n required?: boolean;\n options?: Array<{ value: string; label?: unknown } | string>;\n description?: string;\n}\n\n/** Minimal object shape — same as what {@link SchemaRetriever} consumes. */\ninterface ObjectDef {\n name: string;\n label?: string;\n pluralLabel?: string;\n fields?: Record<string, FieldDef>;\n actions?: Action[];\n}\n\n/**\n * Dependencies needed to invoke an Action from the AI tool runtime.\n *\n * The `metadata` service is used at registration time to resolve param\n * field types; the `dataEngine` is used at call time to (a) load the\n * subject record when a `recordIdParam` is configured and (b) dispatch\n * to the registered handler via `executeAction`.\n *\n * `automation` enables `type:'flow'` actions to dispatch into the\n * automation service's flow runner. When omitted, flow actions are\n * skipped at registration time with a clear reason.\n *\n * `apiClient` (or `apiBaseUrl`) enables `type:'api'` actions to perform\n * an HTTP call to the action's `target` URL. The default client uses\n * the global `fetch` and prepends `apiBaseUrl` to relative `target`s.\n * Supply a custom client when you need bespoke auth, in-process\n * routing, or stubbing in tests.\n *\n * `principal` lets callers attribute AI-initiated mutations to a known\n * user id; it defaults to a synthetic `'ai_agent'` user so traces /\n * audit always have *some* actor.\n */\nexport interface ActionToolsContext {\n metadata: IMetadataService;\n dataEngine: IDataEngine;\n /** Automation service for `type:'flow'` action dispatch. Optional. */\n automation?: IAutomationService;\n /** Custom API client for `type:'api'` actions. Defaults to a fetch-based client. */\n apiClient?: ApiActionClient;\n /** Base URL prepended to relative `target` paths for `type:'api'` actions. */\n apiBaseUrl?: string;\n /** Extra HTTP headers (e.g. auth bearer) applied to every `type:'api'` call. */\n apiHeaders?: Record<string, string>;\n /** Synthetic user attribution for AI-initiated calls. */\n principal?: { id: string; name?: string };\n /** Tool-name prefix (default: `action_`). Keeps namespace separate from data tools. */\n toolPrefix?: string;\n /**\n * AI service used to enqueue HITL approvals for dangerous actions.\n * When supplied together with `enableActionApproval: true`, actions\n * that would otherwise be skipped on safety grounds (`confirmText`,\n * `mode:'delete'`, `variant:'danger'`) are registered as tools whose\n * handler proposes a pending action and returns\n * `{ status: 'pending_approval' }` instead of executing.\n */\n aiService?: {\n proposePendingAction?: (input: {\n objectName: string;\n actionName: string;\n toolName: string;\n toolInput: Record<string, unknown>;\n conversationId?: string;\n messageId?: string;\n proposedBy?: string;\n }) => Promise<{ id: string }>;\n registerPendingActionDispatcher?: (\n toolName: string,\n dispatch: (input: Record<string, unknown>) => Promise<unknown>,\n ) => void;\n };\n /**\n * Opt into the HITL approval queue for dangerous actions. Default\n * is `false` (safer: dangerous actions stay invisible to the LLM\n * until an operator explicitly enables approval routing).\n */\n enableActionApproval?: boolean;\n}\n\n/**\n * Minimal HTTP client shape used by `type:'api'` action dispatch.\n *\n * Implementations are expected to return a JSON-deserialised body (or\n * `null` for empty responses) on 2xx, and throw on non-2xx so the tool\n * surfaces the failure to the LLM as a tool error.\n */\nexport interface ApiActionClient {\n request(input: {\n url: string;\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n body?: Record<string, unknown>;\n headers?: Record<string, string>;\n }): Promise<unknown>;\n}\n\n/** Result returned to the LLM after invoking an action. */\ninterface ActionInvocationResult {\n ok: boolean;\n action: string;\n objectName?: string;\n recordId?: string;\n message?: string;\n result?: unknown;\n error?: string;\n}\n\n// ── Skip-list predicates ────────────────────────────────────────────\n\n/**\n * Decide whether an action should be auto-exposed as a tool.\n *\n * Returns `null` when exposed, or a string reason when skipped.\n * Exported for tests and Studio \"AI exposure\" diagnostics.\n *\n * Supported types as of Phase 2: `script`, `api`, `flow`. Studio-only\n * UI types (`url`, `modal`, `form`) remain skipped — they have no\n * headless invocation path.\n */\n/**\n * True when an action is \"dangerous\" and should be routed through the\n * HITL approval queue (rather than dispatched directly). Exported so\n * Studio's AI-exposure surface can highlight which actions require\n * approval.\n */\nexport function actionRequiresApproval(action: Action): boolean {\n return Boolean(\n action.confirmText || action.mode === 'delete' || action.variant === 'danger',\n );\n}\n\nexport function actionSkipReason(\n action: Action,\n ctx?: {\n automation?: IAutomationService;\n apiClient?: ApiActionClient;\n apiBaseUrl?: string;\n enableActionApproval?: boolean;\n aiService?: ActionToolsContext['aiService'];\n },\n): string | null {\n if (action.aiExposed === false) {\n return 'opted-out via aiExposed:false';\n }\n // Skip Studio-only types (no headless invocation surface).\n if (action.type === 'url' || action.type === 'modal' || action.type === 'form') {\n return `type='${action.type}' is UI-only`;\n }\n if (action.type !== 'script' && action.type !== 'api' && action.type !== 'flow') {\n return `type='${action.type}' not supported`;\n }\n if (action.type === 'script' && !action.target && !action.body) {\n return 'no target or body';\n }\n if ((action.type === 'api' || action.type === 'flow') && !action.target) {\n return `type='${action.type}' requires a target`;\n }\n // Wiring availability checks — only meaningful when ctx is supplied.\n if (ctx) {\n if (action.type === 'flow' && !ctx.automation) {\n return 'no automation service available';\n }\n if (action.type === 'api' && !ctx.apiClient && !ctx.apiBaseUrl) {\n return 'no apiClient or apiBaseUrl configured';\n }\n }\n // Safety: dangerous actions normally require explicit human approval.\n // When the caller has opted in to the HITL queue (and wired aiService),\n // we *register* them and route to the queue instead of skipping.\n if (actionRequiresApproval(action)) {\n const approvalReady =\n ctx?.enableActionApproval === true && Boolean(ctx?.aiService?.proposePendingAction);\n if (!approvalReady) {\n if (action.confirmText) return 'requires confirmation (confirmText set)';\n if (action.mode === 'delete') return \"mode='delete' — destructive\";\n if (action.variant === 'danger') return \"variant='danger' — destructive\";\n }\n }\n return null;\n}\n\n// ── Param → JSON Schema ─────────────────────────────────────────────\n\n/**\n * Map an ObjectStack field type to a JSON-Schema primitive type.\n *\n * Intentionally conservative — anything we don't recognise becomes\n * `string` so the LLM can still pass *something*. Handlers should\n * re-validate via Zod / runtime checks anyway.\n */\nfunction fieldTypeToJsonType(t: string | undefined): 'string' | 'number' | 'boolean' | 'array' {\n switch (t) {\n case 'number':\n case 'currency':\n case 'percent':\n case 'rating':\n case 'slider':\n case 'autonumber':\n return 'number';\n case 'boolean':\n case 'toggle':\n return 'boolean';\n case 'multiselect':\n case 'checkboxes':\n case 'tags':\n return 'array';\n default:\n return 'string';\n }\n}\n\n/**\n * Resolve a single {@link ActionParam} into a `(name, jsonSchema, required)`\n * tuple by consulting the owning object's field definition when the param\n * uses field-backing.\n */\nfunction resolveParam(\n param: ActionParam,\n ownerObject: ObjectDef | undefined,\n allObjects: Map<string, ObjectDef>,\n): { name: string; schema: Record<string, unknown>; required: boolean } | null {\n const fieldRef = param.field;\n const owner =\n param.objectOverride && allObjects.get(param.objectOverride)\n ? allObjects.get(param.objectOverride)\n : ownerObject;\n const field = fieldRef ? owner?.fields?.[fieldRef] : undefined;\n\n const name = param.name ?? fieldRef;\n if (!name) return null;\n\n const type = param.type ?? field?.type;\n const jsonType = fieldTypeToJsonType(type);\n const schema: Record<string, unknown> = { type: jsonType };\n\n const label = typeof param.label === 'string' ? param.label : field?.label;\n const help = param.helpText ?? field?.description;\n const description = [label, help].filter(Boolean).join(' — ') || undefined;\n if (description) schema.description = description;\n\n // Enum sourcing — explicit override wins, otherwise field options\n const optionSource = param.options ?? field?.options;\n if (Array.isArray(optionSource) && optionSource.length > 0) {\n const values = optionSource\n .map(o => (typeof o === 'string' ? o : (o as { value?: string }).value))\n .filter((v): v is string => typeof v === 'string');\n if (values.length > 0) {\n schema.enum = jsonType === 'array' ? undefined : values;\n if (jsonType === 'array') {\n schema.items = { type: 'string', enum: values };\n }\n }\n } else if (jsonType === 'array') {\n schema.items = { type: 'string' };\n }\n\n if (param.defaultValue !== undefined) {\n schema.default = param.defaultValue;\n }\n\n const required = Boolean(param.required ?? field?.required ?? false);\n return { name, schema, required };\n}\n\n/**\n * Build the JSON Schema body for an action's `parameters` field.\n *\n * In addition to user-declared params, we always inject a `recordId`\n * argument when the action is bound to an object — the LLM needs *some*\n * way to say \"complete _this_ task\". The argument is optional for\n * actions that work without a record (`list_toolbar` only) and required\n * when the action declares `recordIdParam`.\n */\nfunction buildParametersSchema(\n action: Action,\n ownerObject: ObjectDef | undefined,\n allObjects: Map<string, ObjectDef>,\n): AIToolDefinition['parameters'] {\n const properties: Record<string, Record<string, unknown>> = {};\n const required: string[] = [];\n\n // Inject recordId for object-bound, row-context actions\n const isRowContext =\n Array.isArray(action.locations) &&\n action.locations.some(l => l === 'list_item' || l === 'record_header' || l === 'record_more' || l === 'record_related');\n if (action.objectName && isRowContext) {\n properties.recordId = {\n type: 'string',\n description: `The ${action.objectName} record id to act on.`,\n };\n // Mark required if action explicitly references a row field for id seeding\n if (action.recordIdParam || action.recordIdField) {\n required.push('recordId');\n }\n }\n\n for (const param of action.params ?? []) {\n const resolved = resolveParam(param, ownerObject, allObjects);\n if (!resolved) continue;\n properties[resolved.name] = resolved.schema;\n if (resolved.required) required.push(resolved.name);\n }\n\n return {\n type: 'object',\n properties,\n ...(required.length > 0 ? { required } : {}),\n additionalProperties: false,\n };\n}\n\n// ── Tool name + description ─────────────────────────────────────────\n\n/** Compute the AI tool name for a given action (prefixed for namespacing). */\nexport function actionToolName(action: Action, prefix = 'action_'): string {\n return `${prefix}${action.name}`;\n}\n\nfunction describeAction(action: Action, ownerObject: ObjectDef | undefined): string {\n const label =\n typeof action.label === 'string'\n ? action.label\n : action.name.replace(/_/g, ' ');\n const target = action.objectName ?? ownerObject?.name;\n const targetLabel = ownerObject?.label ?? target;\n const parts: string[] = [];\n parts.push(`${label}${targetLabel ? ` — operates on ${targetLabel}` : ''}.`);\n if (action.successMessage && typeof action.successMessage === 'string') {\n parts.push(`On success: ${action.successMessage}`);\n }\n if (action.mode) parts.push(`Mode: ${action.mode}.`);\n parts.push(\n 'Use this when the user asks to perform this operation in natural language.',\n );\n return parts.join(' ');\n}\n\n// ── Builders ────────────────────────────────────────────────────────\n\n/**\n * Convert a single {@link Action} into a complete {@link AIToolDefinition}.\n *\n * Returns `null` when the action is filtered out by {@link actionSkipReason}.\n */\nexport function actionToToolDefinition(\n action: Action,\n ownerObject: ObjectDef | undefined,\n allObjects: Map<string, ObjectDef>,\n toolPrefix = 'action_',\n): AIToolDefinition | null {\n // NOTE: skip eligibility is decided by the caller (registerActionsAsTools)\n // with full context (apiClient, automation, HITL approval wiring). This\n // function only checks the *structural* invariants that make a\n // definition impossible to build.\n if (action.aiExposed === false) return null;\n if (action.type === 'url' || action.type === 'modal' || action.type === 'form') return null;\n return {\n name: actionToolName(action, toolPrefix),\n description: describeAction(action, ownerObject),\n parameters: buildParametersSchema(action, ownerObject, allObjects),\n };\n}\n\n// ── Handler / dispatch ─────────────────────────────────────────────\n\n/**\n * Adapter that wraps {@link IDataEngine} into the shape user-authored\n * action handlers expect (see `examples/app-todo/src/actions/task.handlers.ts`).\n *\n * Handlers in the wild use a pseudo-ORM `engine.update(obj, id, data)`\n * convention, while {@link IDataEngine.update} takes `(obj, data, opts)`\n * with a `where`-style options bag. We adapt at the boundary so existing\n * Studio-side handlers run unchanged.\n */\nfunction buildHandlerEngineAdapter(engine: IDataEngine): {\n update: (object: string, id: string, data: Record<string, unknown>) => Promise<unknown>;\n insert: (object: string, data: Record<string, unknown>) => Promise<unknown>;\n find: (object: string, where: Record<string, unknown>) => Promise<unknown[]>;\n delete: (object: string, ids: string[]) => Promise<unknown>;\n} {\n return {\n update: (object, id, data) =>\n engine.update(object, { ...data, id }, { where: { id } }),\n insert: (object, data) => engine.insert(object, data),\n find: (object, where) => engine.find(object, { where }),\n delete: async (object, ids) => {\n if (!Array.isArray(ids) || ids.length === 0) return 0;\n // Loop scalar deletes — engine.delete prioritises a scalar `id`\n // extracted from `where.id` over the `multi:true` branch, so passing\n // `{ where: { id: { $in: [...] } } }` breaks at the driver layer.\n let count = 0;\n for (const id of ids) {\n await engine.delete(object, { where: { id } });\n count++;\n }\n return count;\n },\n };\n}\n\n/**\n * Shared entry-point: load record (when row-context), assemble user\n * params, then delegate to the type-specific executor.\n */\nfunction createActionToolHandler(\n action: Action,\n ctx: ActionToolsContext,\n): ToolHandler {\n const fallbackPrincipal = ctx.principal ?? { id: 'ai_agent', name: 'AI Assistant' };\n const requiresRecord =\n Array.isArray(action.locations) &&\n action.locations.some(\n l => l === 'list_item' || l === 'record_header' || l === 'record_more' || l === 'record_related',\n );\n\n return async (args, execCtx) => {\n // Per-request execution context wins over the static principal so\n // every audit/dispatch entry attributes the work to the real user\n // when one is known. Falls back to the registration-time principal\n // (or the synthetic `ai_agent`) for unauthenticated callers.\n const principal = execCtx?.actor\n ? { id: execCtx.actor.id, name: execCtx.actor.name }\n : fallbackPrincipal;\n const engineCtx = buildActionEngineContext(execCtx);\n const objectName = action.objectName;\n const target = action.target;\n const result: ActionInvocationResult = {\n ok: false,\n action: action.name,\n objectName,\n };\n\n if (!objectName) {\n result.error = 'Action has no objectName; cannot dispatch.';\n return JSON.stringify(result);\n }\n if (!target && action.type !== 'script') {\n result.error = 'Action has no target.';\n return JSON.stringify(result);\n }\n\n const recordId =\n typeof args.recordId === 'string' && args.recordId.length > 0\n ? args.recordId\n : undefined;\n\n let record: Record<string, unknown> | undefined;\n if (requiresRecord) {\n if (!recordId) {\n result.error =\n 'recordId is required for this action — supply the id of the ' +\n `${objectName} record to act on (use query_data first if you don't have it).`;\n return JSON.stringify(result);\n }\n try {\n // RLS engages here too — if the actor can't see the record,\n // the agent gets a \"not found\" error instead of leaking data.\n const found = await ctx.dataEngine.find(objectName, {\n where: { id: recordId },\n limit: 1,\n context: engineCtx,\n });\n record = (found as Array<Record<string, unknown>>)[0];\n if (!record) {\n result.error = `Record ${recordId} not found in ${objectName}.`;\n return JSON.stringify(result);\n }\n result.recordId = recordId;\n } catch (err) {\n result.error = `Failed to load record: ${err instanceof Error ? err.message : String(err)}`;\n return JSON.stringify(result);\n }\n }\n\n // Strip recordId from params before forwarding so handlers receive only\n // user-collected fields (mirroring the Studio modal-submit shape).\n const { recordId: _omit, ...userParams } = args as Record<string, unknown>;\n\n // ── HITL routing ──────────────────────────────────────────────\n // When the action is dangerous AND approval is wired, persist a\n // pending request and return the \"pending\" envelope instead of\n // dispatching. The dispatcher itself was pre-registered with\n // aiService.registerPendingActionDispatcher() at registration time\n // so approval re-runs the exact same code path.\n if (\n ctx.enableActionApproval &&\n actionRequiresApproval(action) &&\n ctx.aiService?.proposePendingAction\n ) {\n try {\n const toolName = `${ctx.toolPrefix ?? 'action_'}${action.name}`;\n const { id } = await ctx.aiService.proposePendingAction({\n objectName: objectName!,\n actionName: action.name,\n toolName,\n toolInput: args as Record<string, unknown>,\n conversationId: execCtx?.conversationId,\n messageId: execCtx?.messageId,\n proposedBy: principal.id,\n });\n const pending: ActionInvocationResult & {\n status?: string;\n pendingActionId?: string;\n } = {\n ok: true,\n action: action.name,\n objectName,\n recordId,\n status: 'pending_approval',\n pendingActionId: id,\n message:\n `Action '${action.name}' is destructive and requires human approval. ` +\n `Proposal queued as ${id}. ` +\n `An operator must approve via Studio's pending-actions inbox before it runs. ` +\n `Do NOT call this tool again for the same intent — wait for the operator.`,\n };\n return JSON.stringify(pending);\n } catch (err) {\n result.error = `Failed to enqueue approval: ${err instanceof Error ? err.message : String(err)}`;\n return JSON.stringify(result);\n }\n }\n\n try {\n let out: unknown;\n if (action.type === 'api') {\n out = await dispatchApiAction(action, ctx, userParams, record, recordId);\n } else if (action.type === 'flow') {\n out = await dispatchFlowAction(action, ctx, userParams, record, principal);\n } else {\n // 'script' (default) — existing behaviour.\n out = await dispatchScriptAction(action, ctx, userParams, record, principal);\n }\n result.ok = true;\n result.result = out ?? null;\n const successMsg =\n typeof action.successMessage === 'string' ? action.successMessage : undefined;\n result.message = successMsg ?? `Action '${action.name}' executed successfully.`;\n return JSON.stringify(result);\n } catch (err) {\n result.error = err instanceof Error ? err.message : String(err);\n return JSON.stringify(result);\n }\n };\n}\n\n/**\n * Translate the AI-side {@link ToolExecutionContext} into an ObjectQL\n * {@link ExecutionContext} for record lookups inside action handlers.\n * Mirrors `data-tools.ts#buildEngineContext` — kept local so this file\n * has no inter-tool dependency.\n */\nfunction buildActionEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\n}\n\nasync function dispatchScriptAction(\n action: Action,\n ctx: ActionToolsContext,\n params: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n principal: { id: string; name?: string },\n): Promise<unknown> {\n const engineAdapter = buildHandlerEngineAdapter(ctx.dataEngine);\n const handlerCtx = { record, user: principal, engine: engineAdapter, params };\n return await (ctx.dataEngine as IDataEngine & {\n executeAction?: (o: string, a: string, c: unknown) => Promise<unknown>;\n }).executeAction?.(action.objectName!, action.target!, handlerCtx);\n}\n\n/**\n * Compose the HTTP body for a `type:'api'` action.\n *\n * Order of merge (last-wins):\n * 1. user-collected params (wrapped if `bodyShape.wrap` is set)\n * 2. recordId — placed flat at `recordIdParam` (using `recordIdField`\n * to pick the value off the record, defaulting to `id`)\n * 3. `bodyExtra` constants (always win)\n */\nexport function buildApiRequestBody(\n action: Action,\n args: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n recordId: string | undefined,\n): Record<string, unknown> {\n const shape = action.bodyShape;\n const wrapKey =\n shape && typeof shape === 'object' && 'wrap' in shape && typeof shape.wrap === 'string'\n ? shape.wrap\n : undefined;\n const body: Record<string, unknown> = wrapKey ? { [wrapKey]: { ...args } } : { ...args };\n\n if (action.recordIdParam) {\n const idField = action.recordIdField ?? 'id';\n const idValue = record ? record[idField] : recordId;\n if (idValue !== undefined) body[action.recordIdParam] = idValue;\n }\n\n if (action.bodyExtra && typeof action.bodyExtra === 'object') {\n Object.assign(body, action.bodyExtra as Record<string, unknown>);\n }\n return body;\n}\n\nasync function dispatchApiAction(\n action: Action,\n ctx: ActionToolsContext,\n params: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n recordId: string | undefined,\n): Promise<unknown> {\n const client =\n ctx.apiClient ??\n (ctx.apiBaseUrl\n ? createFetchApiClient({ baseUrl: ctx.apiBaseUrl, headers: ctx.apiHeaders })\n : undefined);\n if (!client) {\n throw new Error('No apiClient configured for type:\"api\" action dispatch.');\n }\n const method = (action.method ?? 'POST') as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n const body = buildApiRequestBody(action, params, record, recordId);\n return await client.request({\n url: action.target!,\n method,\n body: method === 'GET' || method === 'DELETE' ? undefined : body,\n headers: ctx.apiHeaders,\n });\n}\n\nasync function dispatchFlowAction(\n action: Action,\n ctx: ActionToolsContext,\n params: Record<string, unknown>,\n record: Record<string, unknown> | undefined,\n principal: { id: string; name?: string },\n): Promise<unknown> {\n if (!ctx.automation) {\n throw new Error('No automation service available for type:\"flow\" action dispatch.');\n }\n const result = await ctx.automation.execute(action.target!, {\n triggerData: { record, params, user: principal, action: action.name },\n } as Parameters<IAutomationService['execute']>[1]);\n if (result && typeof result === 'object' && 'success' in result && result.success === false) {\n throw new Error(\n `Flow '${action.target}' failed: ${(result as { error?: string }).error ?? 'unknown error'}`,\n );\n }\n return result;\n}\n\n/**\n * Default fetch-based {@link ApiActionClient}. Resolves relative `url`s\n * against `baseUrl`, merges static `headers`, throws on non-2xx, returns\n * the parsed JSON body (or `null` if empty).\n */\nexport function createFetchApiClient(options: {\n baseUrl?: string;\n headers?: Record<string, string>;\n fetch?: typeof fetch;\n}): ApiActionClient {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new Error('createFetchApiClient: no global fetch available; pass options.fetch.');\n }\n return {\n async request({ url, method, body, headers }) {\n const absolute = /^https?:\\/\\//.test(url) ? url : `${(options.baseUrl ?? '').replace(/\\/$/, '')}${url.startsWith('/') ? '' : '/'}${url}`;\n const res = await fetchImpl(absolute, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...(options.headers ?? {}),\n ...(headers ?? {}),\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n const text = await res.text();\n const parsed = text ? safeJsonParse(text) : null;\n if (!res.ok) {\n const msg =\n parsed && typeof parsed === 'object' && 'error' in parsed\n ? (parsed as { error: unknown }).error\n : text;\n throw new Error(`${method} ${absolute} → ${res.status}: ${typeof msg === 'string' ? msg : JSON.stringify(msg)}`);\n }\n return parsed;\n },\n };\n}\n\nfunction safeJsonParse(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return s;\n }\n}\n\n// ── Registration ──────────────────────────────────────────────────\n\n/**\n * Walk every registered object in the {@link IMetadataService}, pick out\n * each object's actions, and register the ones that pass {@link actionSkipReason}\n * as AI tools.\n *\n * Returns the list of registered tool names and a parallel list of\n * `{ action, reason }` for actions that were intentionally skipped —\n * useful for Studio's \"AI exposure\" diagnostics surface.\n */\nexport async function registerActionsAsTools(\n registry: ToolRegistry,\n context: ActionToolsContext,\n): Promise<{\n registered: string[];\n skipped: Array<{ action: string; reason: string }>;\n}> {\n const objects = (await context.metadata.listObjects()) as ObjectDef[];\n const objMap = new Map<string, ObjectDef>(\n objects.filter((o): o is ObjectDef => Boolean(o?.name)).map(o => [o.name, o]),\n );\n\n const registered: string[] = [];\n const skipped: Array<{ action: string; reason: string }> = [];\n const prefix = context.toolPrefix ?? 'action_';\n\n for (const obj of objects) {\n if (!obj?.actions || !Array.isArray(obj.actions)) continue;\n for (const action of obj.actions) {\n if (!action || typeof action.name !== 'string') continue;\n // Backfill objectName if it was elided (defineStack does this normally,\n // but be defensive when metadata comes from external sources).\n const normalized: Action = {\n ...action,\n objectName: action.objectName ?? obj.name,\n };\n\n const reason = actionSkipReason(normalized, {\n automation: context.automation,\n apiClient: context.apiClient,\n apiBaseUrl: context.apiBaseUrl,\n enableActionApproval: context.enableActionApproval,\n aiService: context.aiService,\n });\n if (reason !== null) {\n skipped.push({ action: normalized.name, reason });\n continue;\n }\n\n const definition = actionToToolDefinition(normalized, obj, objMap, prefix);\n if (!definition) continue;\n\n // Avoid colliding with already-registered tools (e.g. metadata tools).\n if (registry.has(definition.name)) {\n skipped.push({ action: normalized.name, reason: 'tool name already registered' });\n continue;\n }\n\n const handler = createActionToolHandler(normalized, context);\n registry.register(definition, handler);\n registered.push(definition.name);\n\n // Pre-register the *bypass-approval* dispatcher under the same tool\n // name so AIService.approvePendingAction can re-run the action by\n // looking up the dispatcher and invoking it with the original input.\n if (\n context.enableActionApproval &&\n actionRequiresApproval(normalized) &&\n context.aiService?.registerPendingActionDispatcher\n ) {\n // Build a parallel context with approval *disabled* so the handler\n // executes directly instead of re-queuing.\n const bypassCtx: ActionToolsContext = {\n ...context,\n enableActionApproval: false,\n };\n const directHandler = createActionToolHandler(normalized, bypassCtx);\n context.aiService.registerPendingActionDispatcher(\n definition.name,\n async (input) => {\n const raw = await directHandler(input);\n // Handlers return a JSON string envelope; parse for the\n // approval pathway so the row's `result` is structured.\n let parsed: unknown = raw;\n try {\n parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;\n } catch {\n parsed = raw;\n }\n // Surface handler-level failures as exceptions so the\n // approval row flips to `failed` (not silently `executed`).\n if (\n parsed &&\n typeof parsed === 'object' &&\n 'ok' in parsed &&\n (parsed as { ok?: unknown }).ok === false\n ) {\n const errMsg =\n (parsed as { error?: unknown }).error != null\n ? String((parsed as { error?: unknown }).error)\n : 'action handler reported failure';\n throw new Error(errMsg);\n }\n return parsed;\n },\n );\n }\n }\n }\n\n return { registered, skipped };\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, Skill } from '@objectstack/spec/ai';\nimport { AgentSchema } from '@objectstack/spec/ai';\nimport { SkillRegistry, type SkillContext } from './skill-registry.js';\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 *\n * Extends {@link SkillContext} so the same context object can drive\n * skill activation in the {@link SkillRegistry}.\n */\nexport interface AgentChatContext extends SkillContext {\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 * + active skill instructions.\n * 3. Derive {@link AIRequestOptions} from agent `model`, `tools`, and\n * resolved skills.\n * 4. Map agent tool references to concrete {@link AIToolDefinition}s\n * registered in the {@link ToolRegistry}.\n *\n * When constructed with a {@link SkillRegistry} the runtime supports\n * the Agent → Skill → Tool composition model. When the registry is\n * omitted (legacy / test mode) only the agent's inline `tools[]` are\n * used.\n */\nexport class AgentRuntime {\n constructor(\n private readonly metadataService: IMetadataService,\n private readonly skillRegistry?: SkillRegistry,\n ) {}\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 * The composed prompt has up to three sections:\n * 1. The agent's base `instructions` (its persona / prime directives).\n * 2. UI context hints from {@link AgentChatContext} (current object,\n * record, view) so the agent can tailor responses without extra\n * tool calls.\n * 3. An \"Active Skills\" block describing the capabilities currently\n * available — only populated when `activeSkills` is provided.\n */\n buildSystemMessages(\n agent: Agent,\n context?: AgentChatContext,\n activeSkills?: readonly Skill[],\n ): 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.appName) ctx.push(`Current app: ${context.appName}`);\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 // Active skill bundle\n if (activeSkills && activeSkills.length > 0 && this.skillRegistry) {\n const block = this.skillRegistry.composeInstructionsBlock(activeSkills);\n if (block) parts.push(block);\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 * Tools belonging to `activeSkills` are also resolved and merged into\n * the final tool list (deduplicated by name).\n *\n * Any unresolved references (tools the agent or skill declares but\n * that are not registered) are silently skipped — this is intentional\n * so that agents/skills 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 * @param activeSkills - Skills resolved from agent.skills[] + context filtering\n * @returns Request options with model config and resolved tool definitions\n */\n buildRequestOptions(\n agent: Agent,\n availableTools: readonly AIToolDefinition[],\n activeSkills?: readonly Skill[],\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 const toolMap = new Map(availableTools.map((t) => [t.name, t]));\n const seen = new Set<string>();\n const resolved: AIToolDefinition[] = [];\n\n if (agent.tools && agent.tools.length > 0) {\n for (const ref of agent.tools) {\n if (seen.has(ref.name)) continue;\n const def = toolMap.get(ref.name);\n if (def) {\n resolved.push(def);\n seen.add(ref.name);\n }\n }\n }\n\n // Merge skill tools (deduplicated)\n if (activeSkills && activeSkills.length > 0 && this.skillRegistry) {\n const skillTools = this.skillRegistry.flattenToTools(activeSkills, availableTools);\n for (const def of skillTools) {\n if (seen.has(def.name)) continue;\n resolved.push(def);\n seen.add(def.name);\n }\n }\n\n if (resolved.length > 0) {\n options.tools = resolved;\n options.toolChoice = 'auto';\n }\n\n return options;\n }\n\n // ── Skill resolution helpers ─────────────────────────────────\n\n /**\n * Resolve the set of skills active for a given agent in a given\n * context. Combines:\n *\n * 1. The agent's declared `skills[]` whitelist (if any).\n * 2. Filtering by `triggerConditions` against the runtime context.\n *\n * When the agent declares no skills, returns the empty list (i.e.\n * the agent only uses its inline `tools[]`).\n *\n * Returns an empty array if no SkillRegistry was provided to the\n * runtime (legacy mode).\n */\n async resolveActiveSkills(agent: Agent, context?: AgentChatContext): Promise<Skill[]> {\n if (!this.skillRegistry) return [];\n if (!agent.skills || agent.skills.length === 0) return [];\n return this.skillRegistry.listActiveSkills(context ?? {}, agent.skills);\n }\n\n /**\n * Pick a default agent for the given context, used by the ambient\n * chat endpoint when the client doesn't specify an `agentName`.\n *\n * Resolution order:\n * 1. The `defaultAgent` of the app named by `context.appName`.\n * 2. The first active agent in the registry (deterministic fallback).\n * 3. `undefined` if no agents are registered.\n */\n async resolveDefaultAgent(context?: AgentChatContext): Promise<Agent | undefined> {\n if (context?.appName) {\n const rawApp = await this.metadataService.get('app', context.appName).catch(() => undefined);\n const defaultAgentName = (rawApp as { defaultAgent?: string } | undefined)?.defaultAgent;\n if (defaultAgentName) {\n const agent = await this.loadAgent(defaultAgentName);\n if (agent && agent.active !== false) return agent;\n }\n }\n\n // Fallback: first active agent in declaration order.\n const summaries = await this.listAgents();\n if (summaries.length === 0) return undefined;\n return this.loadAgent(summaries[0].name);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { AIToolDefinition, IMetadataService } from '@objectstack/spec/contracts';\nimport type { Skill, SkillTriggerCondition } from '@objectstack/spec/ai';\nimport { SkillSchema } from '@objectstack/spec/ai';\n\n/**\n * Runtime context passed when chatting with the ambient assistant.\n *\n * Mirrors the metadata fields used by `Skill.triggerConditions` so that\n * skills can be activated declaratively based on what the user is doing.\n *\n * UI clients populate this from the current route / selected record.\n */\nexport interface SkillContext {\n /** Application the user is currently inside (e.g. \"crm\"). */\n appName?: string;\n /** Object the user is viewing (e.g. \"lead\"). */\n objectName?: string;\n /** Currently selected record ID. */\n recordId?: string;\n /** Current view name. */\n viewName?: string;\n /** Channel/medium of the conversation (e.g. \"web\", \"slack\", \"email\"). */\n channel?: string;\n /** User's role (used by `triggerConditions` with `field=userRole`). */\n userRole?: string;\n /** Free-form additional context fields evaluated against `triggerConditions`. */\n [extraField: string]: unknown;\n}\n\n/**\n * Summary of an active skill suitable for slash-command palettes\n * and `GET /api/v1/ai/skills` responses.\n */\nexport interface SkillSummary {\n name: string;\n label: string;\n description?: string;\n triggerPhrases?: string[];\n toolCount: number;\n}\n\n/**\n * SkillRegistry — Loads and resolves AI Skill metadata.\n *\n * Responsibilities:\n * 1. Load & validate skill definitions from {@link IMetadataService}.\n * 2. Filter by runtime context using `triggerConditions`.\n * 3. Flatten skill `tools[]` references to concrete {@link AIToolDefinition}s.\n * 4. Compose skill `instructions` for system-prompt injection.\n *\n * The registry is stateless; every call re-reads from the metadata\n * service so changes published at runtime become immediately visible.\n *\n * @example\n * ```ts\n * const registry = new SkillRegistry(metadataService);\n * const active = await registry.listActiveSkills({ appName: 'crm', objectName: 'lead' });\n * const tools = registry.flattenToTools(active, allTools);\n * ```\n */\nexport class SkillRegistry {\n constructor(private readonly metadataService: IMetadataService) {}\n\n // ── Loading ────────────────────────────────────────────────────\n\n /**\n * Load and validate a single skill definition by name.\n *\n * Returns `undefined` when the skill is missing or fails Zod\n * validation (so callers don't accidentally feed malformed metadata\n * to the LLM).\n */\n async loadSkill(skillName: string): Promise<Skill | undefined> {\n const raw = await this.metadataService.get('skill', skillName);\n if (!raw) return undefined;\n\n const result = SkillSchema.safeParse(raw);\n if (!result.success) return undefined;\n return result.data;\n }\n\n /**\n * Load all skill definitions, dropping any that fail validation\n * or are explicitly inactive.\n */\n async listSkills(): Promise<Skill[]> {\n const raw = await this.metadataService.list('skill');\n const skills: Skill[] = [];\n for (const item of raw) {\n const result = SkillSchema.safeParse(item);\n if (result.success && result.data.active !== false) {\n skills.push(result.data);\n }\n }\n return skills;\n }\n\n /**\n * Load only the skills referenced by `skillNames`, preserving\n * declaration order. Missing or invalid skill names are silently\n * dropped (logged at the route layer if needed) so an Agent can be\n * defined before all its skills are persisted.\n */\n async loadSkills(skillNames: readonly string[]): Promise<Skill[]> {\n const skills: Skill[] = [];\n for (const name of skillNames) {\n const skill = await this.loadSkill(name);\n if (skill && skill.active !== false) {\n skills.push(skill);\n }\n }\n return skills;\n }\n\n // ── Context filtering ──────────────────────────────────────────\n\n /**\n * Return skills whose `triggerConditions` are satisfied by the\n * given context. Skills without any conditions are always considered\n * active and returned in their declaration order.\n *\n * If `restrictTo` is provided, the result is intersected with that\n * allow-list (typically the agent's `skills[]` field) so an agent\n * never sees skills outside its declared scope.\n */\n async listActiveSkills(\n context: SkillContext = {},\n restrictTo?: readonly string[],\n ): Promise<Skill[]> {\n const allowList = restrictTo ? new Set(restrictTo) : undefined;\n const all = await this.listSkills();\n return all.filter((skill) => {\n if (allowList && !allowList.has(skill.name)) return false;\n return this.matchesContext(skill, context);\n });\n }\n\n /**\n * Evaluate a skill's `triggerConditions` against the given context.\n *\n * Semantics:\n * - No conditions defined → always matches.\n * - All conditions must pass (logical AND).\n * - Operators: `eq`, `neq`, `in`, `not_in`, `contains`.\n * - `contains` does substring matching for strings and `Array.includes`\n * for arrays.\n * - Missing context fields fail unless the operator is `neq` /\n * `not_in` (treating \"absent\" as \"not equal to anything\").\n */\n matchesContext(skill: Skill, context: SkillContext): boolean {\n const conditions = skill.triggerConditions;\n if (!conditions || conditions.length === 0) return true;\n return conditions.every((cond) => this.evaluateCondition(cond, context));\n }\n\n private evaluateCondition(cond: SkillTriggerCondition, context: SkillContext): boolean {\n const fieldValue = context[cond.field];\n const expected = cond.value;\n\n switch (cond.operator) {\n case 'eq':\n return fieldValue === expected;\n case 'neq':\n return fieldValue !== expected;\n case 'in': {\n const list = Array.isArray(expected) ? expected : [expected];\n return list.includes(fieldValue as string);\n }\n case 'not_in': {\n const list = Array.isArray(expected) ? expected : [expected];\n return !list.includes(fieldValue as string);\n }\n case 'contains': {\n if (typeof fieldValue === 'string' && typeof expected === 'string') {\n return fieldValue.includes(expected);\n }\n if (Array.isArray(fieldValue)) {\n return Array.isArray(expected)\n ? expected.every((v) => fieldValue.includes(v))\n : fieldValue.includes(expected as string);\n }\n return false;\n }\n default:\n return false;\n }\n }\n\n // ── Tool resolution ───────────────────────────────────────────\n\n /**\n * Flatten a list of skills to a deduplicated array of concrete tool\n * definitions, preserving the order skills declared their tools.\n *\n * Tools that are declared by a skill but missing from the available\n * tool registry are silently dropped — this is intentional so a skill\n * can be authored before all its underlying tools are registered.\n */\n flattenToTools(skills: readonly Skill[], availableTools: readonly AIToolDefinition[]): AIToolDefinition[] {\n const toolMap = new Map(availableTools.map((t) => [t.name, t]));\n const seen = new Set<string>();\n const resolved: AIToolDefinition[] = [];\n for (const skill of skills) {\n for (const toolName of skill.tools) {\n // Support trailing-wildcard patterns like `action_*` so a skill\n // can subscribe to a *family* of dynamically registered tools\n // (built-in `actions_executor` uses this for the `action_<name>`\n // tools materialised from each object's declarative Action list).\n if (toolName.endsWith('*')) {\n const prefix = toolName.slice(0, -1);\n for (const def of availableTools) {\n if (!def.name.startsWith(prefix)) continue;\n if (seen.has(def.name)) continue;\n resolved.push(def);\n seen.add(def.name);\n }\n continue;\n }\n if (seen.has(toolName)) continue;\n const def = toolMap.get(toolName);\n if (def) {\n resolved.push(def);\n seen.add(toolName);\n }\n }\n }\n return resolved;\n }\n\n // ── System-prompt composition ─────────────────────────────────\n\n /**\n * Build the \"Active Skills\" block to append to an agent's system\n * prompt. The block lists each skill's label + instructions so the\n * LLM knows which capabilities are available and how to invoke them.\n *\n * Returns an empty string when there are no skills, so the caller\n * can safely concatenate without producing dangling whitespace.\n */\n composeInstructionsBlock(skills: readonly Skill[]): string {\n if (skills.length === 0) return '';\n\n const lines: string[] = ['', '--- Active Skills ---'];\n for (const skill of skills) {\n lines.push(`\\n### ${skill.label} (${skill.name})`);\n if (skill.description) lines.push(skill.description);\n if (skill.instructions) lines.push(skill.instructions);\n if (skill.tools.length > 0) {\n lines.push(`Tools: ${skill.tools.join(', ')}`);\n }\n }\n return lines.join('\\n');\n }\n\n /**\n * Project a skill to a wire-friendly summary suitable for the\n * `/api/v1/ai/skills` endpoint and slash-command palettes.\n */\n toSummary(skill: Skill): SkillSummary {\n return {\n name: skill.name,\n label: skill.label,\n description: skill.description,\n triggerPhrases: skill.triggerPhrases,\n toolCount: skill.tools.length,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Agent } from '@objectstack/spec/ai';\n\n/**\n * Built-in `data_chat` agent — a thin **persona** record.\n *\n * Following the platform's metadata-driven philosophy, this agent no\n * longer hardcodes the tools it can call. The capability bundle lives\n * on the `data_explorer` *skill* (see `../skills/data-explorer-skill.ts`).\n * The agent record is now just:\n * - identity (name / label / role)\n * - persona (system prompt)\n * - model + safety config\n * - skills attached → `skills: ['data_explorer']`\n *\n * To grant data-exploration powers to a different agent, just add\n * `data_explorer` to its `skills[]`. To revoke globally, set the\n * skill's `active: false` in metadata.\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\nAlways answer in the same language the user is using. Detailed tool-usage guidance is supplied by the skills attached to this agent.`,\n\n model: {\n provider: 'openai',\n model: 'gpt-4',\n temperature: 0.3,\n maxTokens: 4096,\n },\n\n // Capability bundle lives on the skill; the agent only references it.\n // `data_explorer` = read side, `actions_executor` = write side.\n skills: ['data_explorer', 'actions_executor'],\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\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Agent } from '@objectstack/spec/ai';\n\n/**\n * Built-in `metadata_assistant` agent — a thin **persona** record.\n *\n * Capability bundle is no longer hardcoded here; it lives on the\n * `metadata_authoring` *skill* (see\n * `../skills/metadata-authoring-skill.ts`). Studio's Universal\n * Assistant pins this agent via `?agent=metadata_assistant` because\n * Studio is a metadata-authoring host.\n *\n * To extend this agent (e.g. give it data-exploration too), just add\n * the skill name: `skills: ['metadata_authoring', 'data_explorer']`.\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\nAlways answer in the same language the user is using. If the user's request is ambiguous, ask clarifying questions before proceeding. Detailed tool-usage guidance is supplied by the skills attached to this agent.`,\n\n model: {\n provider: 'openai',\n model: 'gpt-4',\n temperature: 0.2,\n maxTokens: 4096,\n },\n\n // Capability bundle lives on the skill; the agent only references it.\n skills: ['metadata_authoring'],\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\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Skill } from '@objectstack/spec/ai';\n\n/**\n * Built-in `data_explorer` skill — the read-only data-Q&A capability\n * bundle that the `data_chat` agent (and any other agent that wants\n * data-exploration powers) attaches to its `skills[]`.\n *\n * Following the platform's metadata-driven philosophy, the agent\n * itself no longer hardcodes which tools it can call; instead it\n * names this skill and the SkillRegistry resolves the tool list at\n * request time. Disabling this skill via the metadata service\n * disables data exploration for every agent that references it,\n * without code changes.\n */\nexport const DATA_EXPLORER_SKILL: Skill = {\n name: 'data_explorer',\n label: 'Data Explorer',\n description: 'Read-only Q&A over the user\\'s business data — schema discovery, filtered queries, lookups, and aggregations.',\n instructions: `You can explore the user's business data through these tools.\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 tools: [\n 'query_data',\n 'list_objects',\n 'describe_object',\n 'query_records',\n 'get_record',\n 'aggregate_data',\n ],\n triggerPhrases: [\n 'show me',\n 'list',\n 'how many',\n 'count',\n 'find records',\n 'query',\n 'aggregate',\n 'sum',\n 'average',\n ],\n active: true,\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Skill } from '@objectstack/spec/ai';\n\n/**\n * Built-in `metadata_authoring` skill — the write-side schema-design\n * capability bundle attached to the `metadata_assistant` agent (and\n * any other agent that should be allowed to mutate schema).\n *\n * Splitting this off from the agent record lets us:\n * - Reuse the same authoring tools across multiple agent personas\n * (e.g. an \"ops bot\" that ALSO can author).\n * - Disable authoring globally by setting `active: false` on the\n * skill metadata, without redeploying the agent.\n * - Layer permissions via `Skill.permissions` independent of the\n * agent's permissions.\n */\nexport const METADATA_AUTHORING_SKILL: Skill = {\n name: 'metadata_authoring',\n label: 'Metadata Authoring',\n description: 'Create and modify ObjectStack metadata — objects, fields, schema changes through natural language.',\n instructions: `You are an expert metadata architect. When the user asks you to design or change a data model, use these tools.\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_objects to check if a similar one already exists.\n2. Before modifying or deleting fields, use describe_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 tools: [\n 'create_object',\n 'add_field',\n 'modify_field',\n 'delete_field',\n 'list_objects',\n 'describe_object',\n ],\n triggerPhrases: [\n 'create object',\n 'create table',\n 'add field',\n 'add column',\n 'modify field',\n 'change field',\n 'delete field',\n 'drop field',\n 'design schema',\n 'new entity',\n ],\n active: true,\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Skill } from '@objectstack/spec/ai';\n\n/**\n * Built-in `actions_executor` skill — the write-side counterpart to\n * `data_explorer`.\n *\n * Where `data_explorer` lets an agent **answer** questions about the\n * user's data, `actions_executor` lets the same agent **perform**\n * business operations: complete tasks, start workflows, send invites,\n * etc. The concrete tools are not enumerated here — they're materialised\n * at runtime from every `Action` declared on every object the metadata\n * service knows about (see `registerActionsAsTools` in\n * `tools/action-tools.ts`). The skill records the *intent* (\"agent may\n * invoke business actions\"); the registry expands it into actual tools\n * after metadata is loaded.\n *\n * The `tools` array is intentionally empty — Phase 1 lets the\n * skill-registry resolver fall through to the global tool list when an\n * agent's skill bundle would otherwise filter out the dynamically\n * registered `action_*` tools. Skills that want to restrict the set\n * should be authored project-side with the specific `action_<name>`\n * tools they want to expose.\n */\nexport const ACTIONS_EXECUTOR_SKILL: Skill = {\n name: 'actions_executor',\n label: 'Action Executor',\n description:\n \"Perform business operations on the user's data — invoke actions like \" +\n \"'mark as complete', 'start task', 'clone record' through natural language.\",\n instructions: `You can perform business operations by invoking the user's registered actions.\n\nCapabilities:\n- Each tool whose name starts with \\`action_\\` is a business operation declared on an object.\n- Read the tool description carefully — it tells you what the action does and what record types it applies to.\n- Most actions need a \\`recordId\\` argument. If you don't already have one from a prior \\`query_data\\` call, run \\`query_data\\` first to find the right record, then invoke the action with its id.\n\nGuidelines:\n1. Confirm intent — when the user says \"complete it\" / \"start that one\", make sure you know *which* record they mean. Ask if ambiguous.\n2. Use \\`query_data\\` to look up records by natural-language description (\"the design review task\", \"tickets assigned to me\").\n3. After invoking an action, the tool returns \\`{ ok, message, result }\\`. Summarise success in plain language; surface errors verbatim.\n4. Never invent recordIds. If \\`query_data\\` didn't return one, tell the user instead of guessing.\n5. Action tools are pre-filtered for safety — destructive operations (\\`mode: 'delete'\\`, \\`variant: 'danger'\\`, anything with \\`confirmText\\`) are *not* exposed here and require explicit user confirmation in the UI.\n6. Always answer in the same language the user is using.`,\n // Dynamically materialised: the runtime registers one tool per Action,\n // and the skill subscribes to the whole family via the `action_*`\n // glob (resolved by SkillRegistry.flattenToTools).\n tools: ['action_*'],\n triggerPhrases: [\n 'complete',\n 'mark as',\n 'start',\n 'finish',\n 'clone',\n 'duplicate',\n 'do it',\n 'run',\n 'invoke',\n 'execute',\n ],\n active: true,\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 AIObjectResult,\n GenerateObjectOptions,\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 type { z } from 'zod';\nimport { generateText, streamText, generateObject, 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 try {\n for await (const part of result.fullStream) {\n yield part as TextStreamPart<ToolSet>;\n }\n } catch (err) {\n // Convert provider errors into a typed `error` part so the encoder can\n // surface them to the client instead of leaving the SSE stream open.\n yield {\n type: 'error',\n error: err instanceof Error ? err : new Error(String(err)),\n } as unknown 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 generateObject<T>(\n messages: ModelMessage[],\n schema: z.ZodType<T>,\n options?: GenerateObjectOptions,\n ): Promise<AIObjectResult<T>> {\n const { schemaName, schemaDescription, ...rest } = options ?? {};\n const result = await generateObject({\n model: this.model,\n messages,\n schema,\n schemaName,\n schemaDescription,\n ...buildVercelOptions(rest),\n });\n\n return {\n object: result.object as T,\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 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 * as AI from '@objectstack/spec/ai';\n\n/**\n * ModelRegistry — In-memory runtime registry for AI models.\n *\n * Provides:\n * - Model lookup by id\n * - Default model resolution\n * - Token-based cost estimation\n *\n * Populated from `objectstack.config.ts` at boot. Pure in-memory by design —\n * suitable for serverless / edge runtimes. Persistent registries should be\n * implemented as a wrapper that hydrates this registry at start time.\n *\n * @example\n * ```ts\n * const registry = new ModelRegistry({\n * models: [{\n * id: 'gpt-4o',\n * name: 'GPT-4o',\n * version: '2024-08-06',\n * provider: 'openai',\n * capabilities: { textGeneration: true, functionCalling: true },\n * limits: { maxTokens: 128000, contextWindow: 128000 },\n * pricing: { inputCostPer1kTokens: 0.0025, outputCostPer1kTokens: 0.01 },\n * }],\n * defaultModelId: 'gpt-4o',\n * });\n * const cost = registry.estimateCost('gpt-4o', { promptTokens: 1000, completionTokens: 500 });\n * ```\n */\nexport class ModelRegistry {\n private readonly models = new Map<string, AI.ModelConfig>();\n private defaultModelId?: string;\n\n constructor(config: ModelRegistryConfig = {}) {\n for (const model of config.models ?? []) {\n this.models.set(model.id, model);\n }\n this.defaultModelId = config.defaultModelId;\n }\n\n /** Register or replace a model. */\n register(model: AI.ModelConfig): void {\n this.models.set(model.id, model);\n }\n\n /** Look up a model by id. */\n get(id: string): AI.ModelConfig | undefined {\n return this.models.get(id);\n }\n\n /** Look up a model by id, throwing if missing. */\n getOrThrow(id: string): AI.ModelConfig {\n const model = this.models.get(id);\n if (!model) {\n throw new Error(\n `[ModelRegistry] Unknown model \"${id}\". Registered: ${\n [...this.models.keys()].join(', ') || '(none)'\n }`,\n );\n }\n return model;\n }\n\n /** Resolve the default model (explicit > first registered > undefined). */\n getDefault(): AI.ModelConfig | undefined {\n if (this.defaultModelId) {\n return this.models.get(this.defaultModelId);\n }\n return this.models.values().next().value;\n }\n\n /** Set the default model id (must already be registered). */\n setDefault(id: string): void {\n this.getOrThrow(id);\n this.defaultModelId = id;\n }\n\n /** All registered models. */\n list(): AI.ModelConfig[] {\n return [...this.models.values()];\n }\n\n /** Number of registered models. */\n get size(): number {\n return this.models.size;\n }\n\n /**\n * Estimate cost in the model's currency (defaults to USD).\n *\n * Returns `undefined` when the model is unknown or has no pricing data.\n * Costs are computed as `(tokens / 1000) * pricePer1kTokens` for input and\n * output independently, then summed.\n */\n estimateCost(modelId: string, usage: TokenUsage): CostEstimate | undefined {\n const model = this.models.get(modelId);\n if (!model?.pricing) return undefined;\n return computeCost(model.pricing, usage);\n }\n}\n\n/** Token usage shape (mirrors `AIResult['usage']`). */\nexport interface TokenUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens?: number;\n}\n\n/** Cost estimate returned by {@link ModelRegistry.estimateCost}. */\nexport interface CostEstimate {\n /** Cost attributable to prompt/input tokens. */\n inputCost: number;\n /** Cost attributable to completion/output tokens. */\n outputCost: number;\n /** `inputCost + outputCost`. */\n totalCost: number;\n /** ISO 4217 currency code. */\n currency: string;\n}\n\n/** Configuration for {@link ModelRegistry}. */\nexport interface ModelRegistryConfig {\n /** Models to register at construction. */\n models?: AI.ModelConfig[];\n /** Default model id (must appear in `models`). */\n defaultModelId?: string;\n}\n\n/**\n * Compute cost from pricing + usage. Exported for direct use when a registry\n * is not in scope (e.g. tests or one-off calculations).\n */\nexport function computeCost(pricing: AI.ModelPricing, usage: TokenUsage): CostEstimate {\n const inputCost =\n pricing.inputCostPer1kTokens != null\n ? (usage.promptTokens / 1000) * pricing.inputCostPer1kTokens\n : 0;\n const outputCost =\n pricing.outputCostPer1kTokens != null\n ? (usage.completionTokens / 1000) * pricing.outputCostPer1kTokens\n : 0;\n return {\n inputCost,\n outputCost,\n totalCost: inputCost + outputCost,\n currency: pricing.currency ?? 'USD',\n };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type {\n AIToolDefinition,\n IKnowledgeService,\n KnowledgeSearchOptions,\n} from '@objectstack/spec/contracts';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\nimport type {\n ToolHandler,\n ToolExecutionContext,\n ToolRegistry,\n} from './tool-registry.js';\n\n/**\n * Services required by the knowledge tool family.\n */\nexport interface KnowledgeToolContext {\n /** Orchestrator that resolves adapters and applies permission filtering. */\n knowledgeService: IKnowledgeService;\n}\n\n/**\n * Default cap on `topK` when callers omit it or supply something silly.\n * Adapters and the orchestrator may cap further.\n */\nconst DEFAULT_TOP_K = 5;\nconst MAX_TOP_K = 20;\n\n/**\n * Translate a {@link ToolExecutionContext} into the\n * {@link ExecutionContext} that `IKnowledgeService.search` expects.\n *\n * Mirrors the convention used by the data tools: when the AI tool call\n * carries an authenticated actor, RLS is enforced; otherwise we fall\n * back to a system context so legacy / internal callers continue to\n * work unchanged.\n */\nfunction buildEngineContext(ctx?: ToolExecutionContext): ExecutionContext {\n if (ctx?.actor) {\n return {\n userId: ctx.actor.id,\n roles: ctx.actor.roles ?? [],\n permissions: ctx.actor.permissions ?? [],\n isSystem: false,\n ...(ctx.environmentId ? { tenantId: ctx.environmentId } : {}),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n };\n }\n return { roles: [], permissions: [], isSystem: true };\n}\n\nexport const SEARCH_KNOWLEDGE_TOOL: AIToolDefinition = {\n name: 'search_knowledge',\n description:\n 'Search registered knowledge sources (object snapshots, uploaded files, ' +\n 'external URLs) and return the most relevant excerpts. ' +\n 'Use this when the user asks a question whose answer is in documents, ' +\n 'policies, or reference material the LLM does not natively know. ' +\n 'Results are already permission-filtered for the current user.',\n parameters: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Free-text question or keywords to search for.',\n },\n sourceIds: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional list of source ids to restrict the search to. ' +\n 'When omitted, every source the caller can see is queried.',\n },\n topK: {\n type: 'number',\n description: `Maximum hits to return (default ${DEFAULT_TOP_K}, max ${MAX_TOP_K}).`,\n },\n filter: {\n type: 'object',\n description:\n 'Optional adapter-specific metadata filter (e.g. {\"topic\":\"refunds\"}).',\n },\n },\n required: ['query'],\n },\n};\n\nfunction createSearchKnowledgeHandler(context: KnowledgeToolContext): ToolHandler {\n return async (args, ctx) => {\n const query = typeof args.query === 'string' ? args.query.trim() : '';\n if (!query) {\n return JSON.stringify({ error: 'search_knowledge: `query` is required.' });\n }\n\n const sourceIds = Array.isArray(args.sourceIds)\n ? args.sourceIds.filter((x): x is string => typeof x === 'string')\n : undefined;\n const topKRaw = typeof args.topK === 'number' ? args.topK : DEFAULT_TOP_K;\n const topK = Math.max(1, Math.min(MAX_TOP_K, Math.floor(topKRaw)));\n const filter =\n args.filter && typeof args.filter === 'object' && !Array.isArray(args.filter)\n ? (args.filter as Record<string, unknown>)\n : undefined;\n\n const opts: KnowledgeSearchOptions = {\n topK,\n executionContext: buildEngineContext(ctx),\n };\n if (sourceIds && sourceIds.length > 0) opts.sourceIds = sourceIds;\n if (filter) opts.filter = filter;\n\n try {\n const hits = await context.knowledgeService.search(query, opts);\n return JSON.stringify({\n query,\n count: hits.length,\n hits: hits.map((h) => ({\n documentId: h.documentId,\n chunkId: h.chunkId,\n sourceId: h.sourceId,\n sourceRecordId: h.sourceRecordId,\n score: Number(h.score?.toFixed?.(4) ?? h.score ?? 0),\n title: h.title,\n snippet: h.snippet,\n metadata: h.metadata,\n })),\n });\n } catch (err) {\n return JSON.stringify({\n error: `search_knowledge failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n };\n}\n\n/**\n * Register knowledge-related tools on the AI tool registry.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const knowledgeService = ctx.getService<IKnowledgeService>('knowledge');\n * registerKnowledgeTools(aiService.toolRegistry, { knowledgeService });\n * });\n * ```\n */\nexport function registerKnowledgeTools(\n registry: ToolRegistry,\n context: KnowledgeToolContext,\n): void {\n registry.register(SEARCH_KNOWLEDGE_TOOL, createSearchKnowledgeHandler(context));\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { defineTool } from '@objectstack/spec/ai';\n\n/**\n * list_packages — AI Tool Metadata\n *\n * Lists all installed packages in the ObjectStack instance.\n * Useful for understanding what packages are available before creating metadata.\n */\nexport const listPackagesTool = defineTool({\n name: 'list_packages',\n label: 'List Packages',\n description:\n 'Lists all installed packages in the system. Use this to see what packages are available ' +\n 'before creating or modifying metadata. Packages are the containers that hold metadata.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n status: {\n type: 'string',\n description: 'Filter by package status',\n enum: ['installed', 'disabled', 'installing', 'upgrading', 'uninstalling', 'error'],\n },\n enabled: {\n type: 'boolean',\n description: 'Filter by enabled state (true = only enabled, false = only disabled)',\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 * get_package — AI Tool Metadata\n *\n * Gets detailed information about a specific package.\n */\nexport const getPackageTool = defineTool({\n name: 'get_package',\n label: 'Get Package',\n description:\n 'Gets detailed information about a specific installed package, including its manifest, ' +\n 'metadata, and installation status.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n packageId: {\n type: 'string',\n description: 'Package identifier (reverse domain notation, e.g., com.acme.crm)',\n },\n },\n required: ['packageId'],\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 * create_package — AI Tool Metadata\n *\n * Creates a new package for organizing metadata.\n * All metadata (objects, views, flows, etc.) should belong to a package.\n */\nexport const createPackageTool = defineTool({\n name: 'create_package',\n label: 'Create Package',\n description:\n 'Creates a new package (metadata container) with the specified manifest. ' +\n 'All metadata in ObjectStack should belong to a package. Use this when starting new development ' +\n 'or when the user wants to organize their metadata into a new module.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Package identifier in reverse domain notation (e.g., com.acme.crm, org.mycompany.sales)',\n },\n name: {\n type: 'string',\n description: 'Human-readable package name (e.g., \"CRM Application\", \"Sales Module\")',\n },\n version: {\n type: 'string',\n description: 'Semantic version (e.g., \"1.0.0\")',\n default: '1.0.0',\n },\n description: {\n type: 'string',\n description: 'Brief description of what this package provides',\n },\n namespace: {\n type: 'string',\n description: 'Namespace prefix for metadata (snake_case, e.g., crm, sales). If not provided, derived from package ID.',\n },\n type: {\n type: 'string',\n description: 'Package type',\n enum: ['application', 'plugin', 'library', 'template'],\n default: 'application',\n },\n },\n required: ['id', 'name'],\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 * get_active_package — AI Tool Metadata\n *\n * Gets the currently active package in the conversation context.\n */\nexport const getActivePackageTool = defineTool({\n name: 'get_active_package',\n label: 'Get Active Package',\n description:\n 'Gets the currently active package in this conversation. The active package determines ' +\n 'where new metadata will be created. Returns null if no package is set.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {},\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 * set_active_package — AI Tool Metadata\n *\n * Sets the active package for the current conversation.\n * All metadata operations will use this package context.\n */\nexport const setActivePackageTool = defineTool({\n name: 'set_active_package',\n label: 'Set Active Package',\n description:\n 'Sets the active package for this conversation. All subsequent metadata creation operations ' +\n '(objects, views, flows, etc.) will be associated with this package unless explicitly overridden.',\n category: 'utility',\n builtIn: true,\n parameters: {\n type: 'object',\n properties: {\n packageId: {\n type: 'string',\n description: 'Package identifier to set as active (e.g., com.acme.crm)',\n },\n },\n required: ['packageId'],\n additionalProperties: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Tool } from '@objectstack/spec/ai';\nimport type { InstalledPackage } from '@objectstack/spec/kernel';\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 { listPackagesTool } from './list-packages.tool.js';\nexport { getPackageTool } from './get-package.tool.js';\nexport { createPackageTool } from './create-package.tool.js';\nexport { getActivePackageTool } from './get-active-package.tool.js';\nexport { setActivePackageTool } from './set-active-package.tool.js';\n\nimport { listPackagesTool } from './list-packages.tool.js';\nimport { getPackageTool } from './get-package.tool.js';\nimport { createPackageTool } from './create-package.tool.js';\nimport { getActivePackageTool } from './get-active-package.tool.js';\nimport { setActivePackageTool } from './set-active-package.tool.js';\n\n/** All built-in package management tool definitions (Tool metadata). */\nexport const PACKAGE_TOOL_DEFINITIONS: Tool[] = [\n listPackagesTool,\n getPackageTool,\n createPackageTool,\n getActivePackageTool,\n setActivePackageTool,\n];\n\n// ---------------------------------------------------------------------------\n// Package Registry Interface (minimal contract for package operations)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal package registry interface for tool operations.\n * The actual implementation may be a full PackageRegistry service.\n */\nexport interface IPackageRegistry {\n /** List all installed packages */\n list(filter?: { status?: string; enabled?: boolean }): Promise<InstalledPackage[]>;\n\n /** Get a specific package by ID */\n get(packageId: string): Promise<InstalledPackage | undefined>;\n\n /** Install a new package */\n install(manifest: Record<string, unknown>): Promise<InstalledPackage>;\n\n /** Check if a package exists */\n exists(packageId: string): Promise<boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// Conversation Service Interface (for tracking active package)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal conversation service interface for context management.\n */\nexport interface IConversationService {\n /** Get conversation metadata */\n getMetadata?(conversationId: string): Promise<Record<string, unknown> | undefined>;\n\n /** Update conversation metadata */\n updateMetadata?(conversationId: string, metadata: Record<string, unknown>): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Context — injected once at registration time\n// ---------------------------------------------------------------------------\n\n/**\n * Services required by the package 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 PackageToolContext {\n /** Package registry for package CRUD operations */\n packageRegistry: IPackageRegistry;\n\n /** Conversation service for tracking active package context (optional) */\n conversationService?: IConversationService;\n\n /** Current conversation ID (if in a conversation context) */\n conversationId?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Shared validation helpers\n// ---------------------------------------------------------------------------\n\n/** Reverse domain notation pattern (e.g. com.acme.crm). */\nconst REVERSE_DOMAIN_RE = /^[a-z][a-z0-9]*(\\.[a-z][a-z0-9]*)+$/;\n\n/** snake_case identifier pattern. */\nconst SNAKE_CASE_RE = /^[a-z_][a-z0-9_]*$/;\n\n/** Semantic version pattern. */\nconst SEMVER_RE = /^\\d+\\.\\d+\\.\\d+(-[a-z0-9]+(\\.[a-z0-9]+)*)?$/;\n\n/**\n * Validate that a value matches reverse domain notation.\n */\nfunction isReverseDomain(value: string): boolean {\n return REVERSE_DOMAIN_RE.test(value);\n}\n\n/**\n * Validate that a value matches snake_case.\n */\nfunction isSnakeCase(value: string): boolean {\n return SNAKE_CASE_RE.test(value);\n}\n\n/**\n * Validate semantic version.\n */\nfunction isSemVer(value: string): boolean {\n return SEMVER_RE.test(value);\n}\n\n/**\n * Derive namespace from package ID.\n * Example: \"com.acme.crm\" -> \"crm\"\n */\nfunction deriveNamespace(packageId: string): string {\n const parts = packageId.split('.');\n return parts[parts.length - 1];\n}\n\n// ---------------------------------------------------------------------------\n// Handler Factories\n// ---------------------------------------------------------------------------\n\nfunction createListPackagesHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { status, enabled } = (args ?? {}) as {\n status?: string;\n enabled?: boolean;\n };\n\n const filter: { status?: string; enabled?: boolean } = {};\n if (status) filter.status = status;\n if (enabled !== undefined) filter.enabled = enabled;\n\n const packages = await ctx.packageRegistry.list(filter);\n\n const result = packages.map(pkg => ({\n id: pkg.manifest.id,\n name: pkg.manifest.name,\n version: pkg.manifest.version,\n type: pkg.manifest.type,\n status: pkg.status,\n enabled: pkg.enabled,\n installedAt: pkg.installedAt,\n description: pkg.manifest.description,\n }));\n\n return JSON.stringify({\n packages: result,\n total: result.length,\n });\n };\n}\n\nfunction createGetPackageHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { packageId } = args as { packageId: string };\n\n if (!packageId) {\n return JSON.stringify({ error: 'packageId is required' });\n }\n\n const pkg = await ctx.packageRegistry.get(packageId);\n\n if (!pkg) {\n return JSON.stringify({ error: `Package \"${packageId}\" not found` });\n }\n\n return JSON.stringify({\n id: pkg.manifest.id,\n name: pkg.manifest.name,\n version: pkg.manifest.version,\n type: pkg.manifest.type,\n status: pkg.status,\n enabled: pkg.enabled,\n installedAt: pkg.installedAt,\n updatedAt: pkg.updatedAt,\n description: pkg.manifest.description,\n namespace: pkg.manifest.namespace,\n dependencies: pkg.manifest.dependencies,\n registeredNamespaces: pkg.registeredNamespaces,\n });\n };\n}\n\nfunction createCreatePackageHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { id, name, version = '1.0.0', description, namespace, type = 'application' } = args as {\n id: string;\n name: string;\n version?: string;\n description?: string;\n namespace?: string;\n type?: string;\n };\n\n // Validate required fields\n if (!id || !name) {\n return JSON.stringify({ error: 'Both \"id\" and \"name\" are required' });\n }\n\n // Validate package ID format (reverse domain notation)\n if (!isReverseDomain(id)) {\n return JSON.stringify({\n error: `Invalid package ID \"${id}\". Must be in reverse domain notation (e.g., com.acme.crm, org.mycompany.sales)`,\n });\n }\n\n // Validate version format\n if (!isSemVer(version)) {\n return JSON.stringify({\n error: `Invalid version \"${version}\". Must be semantic version (e.g., 1.0.0, 2.1.3-beta)`,\n });\n }\n\n // Check if package already exists\n const exists = await ctx.packageRegistry.exists(id);\n if (exists) {\n return JSON.stringify({ error: `Package \"${id}\" already exists` });\n }\n\n // Derive or validate namespace\n const derivedNamespace = namespace || deriveNamespace(id);\n if (!isSnakeCase(derivedNamespace)) {\n return JSON.stringify({\n error: `Invalid namespace \"${derivedNamespace}\". Must be snake_case (e.g., crm, sales_module)`,\n });\n }\n\n // Build manifest\n const manifest: Record<string, unknown> = {\n id,\n name,\n version,\n type,\n namespace: derivedNamespace,\n ...(description ? { description } : {}),\n };\n\n // Install the package\n const installedPackage = await ctx.packageRegistry.install(manifest);\n\n // Set as active package in conversation if conversation service is available\n if (ctx.conversationService && ctx.conversationId) {\n try {\n await ctx.conversationService.updateMetadata?.(ctx.conversationId, {\n activePackageId: id,\n });\n } catch (err) {\n // Non-critical error - package was created successfully\n console.warn('Failed to set active package in conversation:', err);\n }\n }\n\n return JSON.stringify({\n packageId: installedPackage.manifest.id,\n name: installedPackage.manifest.name,\n version: installedPackage.manifest.version,\n namespace: installedPackage.manifest.namespace,\n status: installedPackage.status,\n message: `Package \"${name}\" created successfully and set as active package`,\n });\n };\n}\n\nfunction createGetActivePackageHandler(ctx: PackageToolContext): ToolHandler {\n return async () => {\n // If no conversation service, can't track active package\n if (!ctx.conversationService || !ctx.conversationId) {\n return JSON.stringify({\n activePackageId: null,\n message: 'No conversation context available to track active package',\n });\n }\n\n try {\n const metadata = await ctx.conversationService.getMetadata?.(ctx.conversationId);\n const activePackageId = metadata?.activePackageId as string | undefined;\n\n if (!activePackageId) {\n return JSON.stringify({\n activePackageId: null,\n message: 'No active package set. Use set_active_package or create a new package.',\n });\n }\n\n // Get package details\n const pkg = await ctx.packageRegistry.get(activePackageId);\n\n if (!pkg) {\n return JSON.stringify({\n activePackageId,\n error: `Active package \"${activePackageId}\" not found. It may have been uninstalled.`,\n });\n }\n\n return JSON.stringify({\n activePackageId: pkg.manifest.id,\n name: pkg.manifest.name,\n version: pkg.manifest.version,\n namespace: pkg.manifest.namespace,\n type: pkg.manifest.type,\n });\n } catch (err) {\n return JSON.stringify({\n error: `Failed to get active package: ${(err as Error).message}`,\n });\n }\n };\n}\n\nfunction createSetActivePackageHandler(ctx: PackageToolContext): ToolHandler {\n return async (args) => {\n const { packageId } = args as { packageId: string };\n\n if (!packageId) {\n return JSON.stringify({ error: 'packageId is required' });\n }\n\n // Verify package exists\n const pkg = await ctx.packageRegistry.get(packageId);\n if (!pkg) {\n return JSON.stringify({ error: `Package \"${packageId}\" not found` });\n }\n\n // If no conversation service, return error\n if (!ctx.conversationService || !ctx.conversationId) {\n return JSON.stringify({\n error: 'No conversation context available. Cannot set active package.',\n });\n }\n\n try {\n await ctx.conversationService.updateMetadata?.(ctx.conversationId, {\n activePackageId: packageId,\n });\n\n return JSON.stringify({\n activePackageId: packageId,\n name: pkg.manifest.name,\n namespace: pkg.manifest.namespace,\n message: `Active package set to \"${pkg.manifest.name}\"`,\n });\n } catch (err) {\n return JSON.stringify({\n error: `Failed to set active package: ${(err as Error).message}`,\n });\n }\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public Registration Helper\n// ---------------------------------------------------------------------------\n\n/**\n * Register all built-in package management tools on the given {@link ToolRegistry}.\n *\n * Typically called from the `ai:ready` hook after the package registry is available.\n *\n * @example\n * ```ts\n * ctx.hook('ai:ready', async (aiService) => {\n * const packageRegistry = ctx.getService<IPackageRegistry>('packageRegistry');\n * const conversationService = ctx.getService<IConversationService>('conversation');\n * registerPackageTools(aiService.toolRegistry, {\n * packageRegistry,\n * conversationService,\n * });\n * });\n * ```\n */\nexport function registerPackageTools(\n registry: ToolRegistry,\n context: PackageToolContext,\n): void {\n registry.register(listPackagesTool, createListPackagesHandler(context));\n registry.register(getPackageTool, createGetPackageHandler(context));\n registry.register(createPackageTool, createCreatePackageHandler(context));\n registry.register(getActivePackageTool, createGetActivePackageHandler(context));\n registry.register(setActivePackageTool, createSetActivePackageHandler(context));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuCA,SAAS,mBAAmB,KAA8C;AACxE,MAAI,KAAK,OAAO;AACd,WAAO;AAAA,MACL,QAAQ,IAAI,MAAM;AAAA,MAClB,OAAO,IAAI,MAAM,SAAS,CAAC;AAAA,MAC3B,aAAa,IAAI,MAAM,eAAe,CAAC;AAAA,MACvC,UAAU;AAAA,MACV,GAAI,IAAI,gBAAgB,EAAE,UAAU,IAAI,cAAc,IAAI,CAAC;AAAA,MAC3D,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;AAAA,IAChD;AAAA,EACF;AACA,SAAO,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,GAAG,UAAU,KAAK;AACtD;AAqJA,SAAS,0BAA0B,KAAmC;AACpE,SAAO,OAAO,MAAM,YAAY;AAC9B,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AAUJ,UAAM,WAAW,SAAS;AAC1B,UAAM,YAAY,OAAO,SAAS,QAAQ,KAAK,WAAW,IACtD,KAAK,IAAI,KAAK,MAAM,QAAQ,GAAG,eAAe,IAC9C;AAGJ,UAAM,aAAc,OAAO,SAAS,MAAM,KAAM,UAAqB,IACjE,KAAK,MAAM,MAAgB,IAC3B;AAEJ,UAAM,UAAU,MAAM,IAAI,WAAW,KAAK,YAAY;AAAA,MACpD;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS,mBAAmB,OAAO;AAAA,IACrC,CAAC;AAED,WAAO,KAAK,UAAU,EAAE,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,EAC1D;AACF;AAEA,SAAS,uBAAuB,KAAmC;AACjE,SAAO,OAAO,MAAM,YAAY;AAC9B,UAAM,EAAE,YAAY,UAAU,OAAO,IAAI;AAMzC,UAAM,SAAS,MAAM,IAAI,WAAW,QAAQ,YAAY;AAAA,MACtD,OAAO,EAAE,IAAI,SAAS;AAAA,MACtB;AAAA,MACA,SAAS,mBAAmB,OAAO;AAAA,IACrC,CAAC;AAED,QAAI,CAAC,QAAQ;AACX,aAAO,KAAK,UAAU,EAAE,OAAO,WAAW,QAAQ,mBAAmB,UAAU,IAAI,CAAC;AAAA,IACtF;AAEA,WAAO,KAAK,UAAU,MAAM;AAAA,EAC9B;AACF;AAUA,SAAS,2BAA2B,KAAmC;AACrE,SAAO,OAAO,MAAM,YAAY;AAC9B,UAAM,EAAE,YAAY,cAAc,SAAS,MAAM,IAAI;AAQrD,eAAW,KAAK,cAAc;AAC5B,UAAI,CAAC,oBAAoB,IAAI,EAAE,QAAQ,GAAG;AACxC,eAAO,KAAK,UAAU;AAAA,UACpB,OAAO,iCAAiC,EAAE,QAAQ,eACpC,CAAC,GAAG,mBAAmB,EAAE,KAAK,IAAI,CAAC;AAAA,QACnD,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,IAAI,WAAW,UAAU,YAAY;AAAA,MACxD;AAAA,MACA;AAAA,MACA,cAAc,aAAa,IAAI,QAAM;AAAA,QACnC,UAAU,EAAE;AAAA,QACZ,OAAO,EAAE;AAAA,QACT,OAAO,EAAE;AAAA,MACX,EAAE;AAAA,MACF,SAAS,mBAAmB,OAAO;AAAA,IACrC,CAAC;AAED,WAAO,KAAK,UAAU,MAAM;AAAA,EAC9B;AACF;AAmBO,SAAS,kBACd,UACA,SACM;AACN,WAAS,SAAS,oBAAoB,0BAA0B,OAAO,CAAC;AACxE,WAAS,SAAS,iBAAiB,uBAAuB,OAAO,CAAC;AAClE,WAAS,SAAS,qBAAqB,2BAA2B,OAAO,CAAC;AAC5E;AA1UA,IA0DM,iBAGA,qBAEO,oBAkDA,iBAyBA,qBAoDA,uBA8EP;AA5QN;AAAA;AAAA;AA0DA,IAAM,kBAAkB;AAGxB,IAAM,sBAAsB;AAErB,IAAM,qBAAuC;AAAA,MAClD,MAAM;AAAA,MACN,aACE;AAAA,MAEF,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,OAAO;AAAA,YACL,MAAM;AAAA,YACN,aACE;AAAA,UAEJ;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aAAa;AAAA,UACf;AAAA,UACA,SAAS;AAAA,YACP,MAAM;AAAA,YACN,OAAO;AAAA,cACL,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,OAAO,EAAE,MAAM,SAAS;AAAA,gBACxB,OAAO,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,MAAM,EAAE;AAAA,cACjD;AAAA,cACA,UAAU,CAAC,SAAS,OAAO;AAAA,cAC3B,sBAAsB;AAAA,YACxB;AAAA,YACA,aAAa;AAAA,UACf;AAAA,UACA,OAAO;AAAA,YACL,MAAM;AAAA,YACN,aAAa,gDAAgD,mBAAmB,SAAS,eAAe;AAAA,UAC1G;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,UAAU,CAAC,YAAY;AAAA,QACvB,sBAAsB;AAAA,MACxB;AAAA,IACF;AAEO,IAAM,kBAAoC;AAAA,MAC/C,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,UAAU;AAAA,YACR,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,UAAU,CAAC,cAAc,UAAU;AAAA,QACnC,sBAAsB;AAAA,MACxB;AAAA,IACF;AAEO,IAAM,sBAAwC;AAAA,MACnD,MAAM;AAAA,MACN,aACE;AAAA,MAEF,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,cAAc;AAAA,YACZ,MAAM;AAAA,YACN,OAAO;AAAA,cACL,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,UAAU;AAAA,kBACR,MAAM;AAAA,kBACN,MAAM,CAAC,SAAS,OAAO,OAAO,OAAO,OAAO,gBAAgB;AAAA,kBAC5D,aAAa;AAAA,gBACf;AAAA,gBACA,OAAO;AAAA,kBACL,MAAM;AAAA,kBACN,aAAa;AAAA,gBACf;AAAA,gBACA,OAAO;AAAA,kBACL,MAAM;AAAA,kBACN,aAAa;AAAA,gBACf;AAAA,cACF;AAAA,cACA,UAAU,CAAC,YAAY,OAAO;AAAA,cAC9B,sBAAsB;AAAA,YACxB;AAAA,YACA,aAAa;AAAA,UACf;AAAA,UACA,SAAS;AAAA,YACP,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aAAa;AAAA,UACf;AAAA,UACA,OAAO;AAAA,YACL,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,UAAU,CAAC,cAAc,cAAc;AAAA,QACvC,sBAAsB;AAAA,MACxB;AAAA,IACF;AAGO,IAAM,wBAA4C;AAAA,MACvD;AAAA,MACA;AAAA,MACA;AAAA,IACF;AA0EA,IAAM,sBAAsB,oBAAI,IAAY;AAAA,MAC1C;AAAA,MAAS;AAAA,MAAO;AAAA,MAAO;AAAA,MAAO;AAAA,MAAO;AAAA,IACvC,CAAC;AAAA;AAAA;;;AC9QD,IAEA,WASa;AAXb;AAAA;AAAA;AAEA,gBAA2B;AASpB,IAAM,uBAAmB,sBAAW;AAAA,MACzC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,MAEF,UAAU;AAAA,MACV,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMT,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,MAAM;AAAA,YACJ,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,OAAO;AAAA,YACL,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,WAAW;AAAA,YACT,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,aAAa;AAAA,YACb,OAAO;AAAA,cACL,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,MAAM,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,gBACvE,OAAO,EAAE,MAAM,UAAU,aAAa,qBAAqB;AAAA,gBAC3D,MAAM;AAAA,kBACJ,MAAM;AAAA,kBACN,aAAa;AAAA,kBACb,MAAM,CAAC,QAAQ,YAAY,UAAU,WAAW,QAAQ,YAAY,UAAU,UAAU,WAAW,YAAY;AAAA,gBACjH;AAAA,gBACA,UAAU,EAAE,MAAM,WAAW,aAAa,gCAAgC;AAAA,cAC5E;AAAA,cACA,UAAU,CAAC,QAAQ,MAAM;AAAA,YAC3B;AAAA,UACF;AAAA,UACA,gBAAgB;AAAA,YACd,MAAM;AAAA,YACN,aAAa;AAAA,YACb,YAAY;AAAA,cACV,cAAc,EAAE,MAAM,UAAU;AAAA,cAChC,YAAY,EAAE,MAAM,UAAU;AAAA,YAChC;AAAA,UACF;AAAA,QACF;AAAA,QACA,UAAU,CAAC,QAAQ,OAAO;AAAA,QAC1B,sBAAsB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA;AAAA;;;ACrED,IAEAA,YASa;AAXb;AAAA;AAAA;AAEA,IAAAA,aAA2B;AASpB,IAAM,mBAAe,uBAAW;AAAA,MACrC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,MAEF,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,WAAW;AAAA,YACT,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,MAAM;AAAA,YACJ,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,OAAO;AAAA,YACL,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,MAAM;AAAA,YACJ,MAAM;AAAA,YACN,aAAa;AAAA,YACb,MAAM,CAAC,QAAQ,YAAY,UAAU,WAAW,QAAQ,YAAY,UAAU,UAAU,WAAW,YAAY;AAAA,UACjH;AAAA,UACA,UAAU;AAAA,YACR,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,cAAc;AAAA,YACZ,aAAa;AAAA,UACf;AAAA,UACA,SAAS;AAAA,YACP,MAAM;AAAA,YACN,aAAa;AAAA,YACb,OAAO;AAAA,cACL,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,OAAO,EAAE,MAAM,SAAS;AAAA,gBACxB,OAAO;AAAA,kBACL,MAAM;AAAA,kBACN,aAAa;AAAA,kBACb,SAAS;AAAA,gBACX;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,UACA,WAAW;AAAA,YACT,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,UAAU,CAAC,cAAc,QAAQ,MAAM;AAAA,QACvC,sBAAsB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA;AAAA;;;ACzED,IAEAC,YAQa;AAVb;AAAA;AAAA;AAEA,IAAAA,aAA2B;AAQpB,IAAM,sBAAkB,uBAAW;AAAA,MACxC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,MAEF,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,WAAW;AAAA,YACT,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,WAAW;AAAA,YACT,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,SAAS;AAAA,YACP,MAAM;AAAA,YACN,aAAa;AAAA,YACb,YAAY;AAAA,cACV,OAAO,EAAE,MAAM,UAAU,aAAa,oBAAoB;AAAA,cAC1D,MAAM,EAAE,MAAM,UAAU,aAAa,iBAAiB;AAAA,cACtD,UAAU,EAAE,MAAM,WAAW,aAAa,6BAA6B;AAAA,cACvE,cAAc,EAAE,aAAa,oBAAoB;AAAA,YACnD;AAAA,UACF;AAAA,QACF;AAAA,QACA,UAAU,CAAC,cAAc,aAAa,SAAS;AAAA,QAC/C,sBAAsB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA;AAAA;;;AC/CD,IAEAC,YAQa;AAVb;AAAA;AAAA;AAEA,IAAAA,aAA2B;AAQpB,IAAM,sBAAkB,uBAAW;AAAA,MACxC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,MAEF,UAAU;AAAA,MACV,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,MAKT,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,WAAW;AAAA,YACT,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,WAAW;AAAA,YACT,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,UAAU,CAAC,cAAc,WAAW;AAAA,QACpC,sBAAsB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA;AAAA;;;ACzCD,IAEAC,YASa;AAXb;AAAA;AAAA;AAEA,IAAAA,aAA2B;AASpB,IAAM,sBAAkB,uBAAW;AAAA,MACxC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,MAEF,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,eAAe;AAAA,YACb,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA;AAAA;;;ACjCD,IAEAC,YASa;AAXb;AAAA;AAAA;AAEA,IAAAA,aAA2B;AASpB,IAAM,yBAAqB,uBAAW;AAAA,MAC3C,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,MAEF,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,UAAU,CAAC,YAAY;AAAA,QACvB,sBAAsB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA;AAAA;;;AC9BD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmEA,SAAS,YAAY,OAAwB;AAC3C,SAAO,cAAc,KAAK,KAAK;AACjC;AAUA,eAAe,mBAAmB,KAAkD;AAClF,MAAI,CAAC,IAAI,qBAAqB,eAAe,CAAC,IAAI,gBAAgB;AAChE,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,IAAI,oBAAoB,YAAY,IAAI,cAAc;AAC7E,SAAQ,UAAU,mBAA8B;AAClD;AAUA,eAAe,iBACb,KACA,mBACyE;AACzE,MAAI,YAA2B;AAG/B,MAAI,mBAAmB;AACrB,gBAAY;AAAA,EACd,OAAO;AAEL,gBAAY,MAAM,mBAAmB,GAAG;AAAA,EAC1C;AAIA,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,WAAW;AAAA,MACX,SAAS;AAAA,IACX;AAAA,EACF;AAGA,MAAI,IAAI,iBAAiB;AACvB,UAAM,SAAS,MAAM,IAAI,gBAAgB,OAAO,SAAS;AACzD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,WAAW;AAAA,QACX,OAAO,YAAY,SAAS;AAAA,MAC9B;AAAA,IACF;AAGA,UAAM,MAAM,MAAM,IAAI,gBAAgB,IAAI,SAAS;AACnD,QAAI,KAAK,SAAS,WAAW,cAAc;AACzC,aAAO;AAAA,QACL,WAAW;AAAA,QACX,OAAO,YAAY,SAAS;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,UAAU;AACrB;AAmCA,SAAS,0BAA0B,KAAuC;AACxE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,MAAM,OAAO,WAAW,mBAAmB,QAAQ,eAAe,IAAI;AAQ9E,QAAI,CAAC,QAAQ,CAAC,OAAO;AACnB,aAAO,KAAK,UAAU,EAAE,OAAO,uCAAuC,CAAC;AAAA,IACzE;AAGA,UAAM,WAAW,MAAM,iBAAiB,KAAK,iBAAiB;AAC9D,QAAI,SAAS,OAAO;AAClB,aAAO,KAAK,UAAU,EAAE,OAAO,SAAS,MAAM,CAAC;AAAA,IACjD;AACA,UAAM,YAAY,SAAS;AAG3B,QAAI,CAAC,YAAY,IAAI,GAAG;AACtB,aAAO,KAAK,UAAU,EAAE,OAAO,wBAAwB,IAAI,yBAAyB,CAAC;AAAA,IACvF;AAGA,UAAM,WAAW,MAAM,IAAI,gBAAgB,UAAU,IAAI;AACzD,QAAI,UAAU;AACZ,aAAO,KAAK,UAAU,EAAE,OAAO,WAAW,IAAI,mBAAmB,CAAC;AAAA,IACpE;AAGA,UAAM,WAAoD,CAAC;AAC3D,QAAI,UAAU,MAAM,QAAQ,MAAM,GAAG;AACnC,YAAM,YAAY,oBAAI,IAAY;AAClC,iBAAW,KAAK,QAAQ;AACtB,YAAI,CAAC,EAAE,MAAM;AACX,iBAAO,KAAK,UAAU,EAAE,OAAO,yCAAyC,CAAC;AAAA,QAC3E;AACA,YAAI,CAAC,YAAY,EAAE,IAAI,GAAG;AACxB,iBAAO,KAAK,UAAU,EAAE,OAAO,uBAAuB,EAAE,IAAI,yBAAyB,CAAC;AAAA,QACxF;AACA,YAAI,UAAU,IAAI,EAAE,IAAI,GAAG;AACzB,iBAAO,KAAK,UAAU,EAAE,OAAO,yBAAyB,EAAE,IAAI,sBAAsB,CAAC;AAAA,QACvF;AACA,kBAAU,IAAI,EAAE,IAAI;AACpB,iBAAS,EAAE,IAAI,IAAI;AAAA,UACjB,MAAM,EAAE;AAAA,UACR,GAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAAA,UACpC,GAAI,EAAE,aAAa,SAAY,EAAE,UAAU,EAAE,SAAS,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAEA,UAAM,YAAqC;AAAA,MACzC;AAAA,MACA;AAAA,MACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,GAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,MAC/D,GAAI,iBAAiB,EAAE,QAAQ,eAAe,IAAI,CAAC;AAAA,IACrD;AAEA,UAAM,IAAI,gBAAgB,SAAS,UAAU,MAAM,SAAS;AAE5D,WAAO,KAAK,UAAU;AAAA,MACpB;AAAA,MACA;AAAA,MACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,YAAY,OAAO,KAAK,QAAQ,EAAE;AAAA,IACpC,CAAC;AAAA,EACH;AACF;AAEA,SAAS,sBAAsB,KAAuC;AACpE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,YAAY,MAAM,OAAO,MAAM,UAAU,cAAc,SAAS,WAAW,WAAW,kBAAkB,IAAI;AAYpH,QAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM;AACjC,aAAO,KAAK,UAAU,EAAE,OAAO,gDAAgD,CAAC;AAAA,IAClF;AAGA,UAAM,WAAW,MAAM,iBAAiB,KAAK,iBAAiB;AAC9D,QAAI,SAAS,OAAO;AAClB,aAAO,KAAK,UAAU,EAAE,OAAO,SAAS,MAAM,CAAC;AAAA,IACjD;AAGA,QAAI,CAAC,YAAY,UAAU,GAAG;AAC5B,aAAO,KAAK,UAAU,EAAE,OAAO,wBAAwB,UAAU,yBAAyB,CAAC;AAAA,IAC7F;AACA,QAAI,CAAC,YAAY,IAAI,GAAG;AACtB,aAAO,KAAK,UAAU,EAAE,OAAO,uBAAuB,IAAI,yBAAyB,CAAC;AAAA,IACtF;AAGA,QAAI,aAAa,CAAC,YAAY,SAAS,GAAG;AACxC,aAAO,KAAK,UAAU,EAAE,OAAO,sBAAsB,SAAS,uCAAuC,CAAC;AAAA,IACxG;AAGA,QAAI,WAAW,MAAM,QAAQ,OAAO,GAAG;AACrC,iBAAW,OAAO,SAAS;AACzB,YAAI,IAAI,SAAS,CAAC,YAAY,IAAI,KAAK,GAAG;AACxC,iBAAO,KAAK,UAAU,EAAE,OAAO,yBAAyB,IAAI,KAAK,mCAAmC,CAAC;AAAA,QACvG;AAAA,MACF;AAAA,IACF;AAGA,UAAM,YAAY,MAAM,IAAI,gBAAgB,UAAU,UAAU;AAChE,QAAI,CAAC,WAAW;AACd,aAAO,KAAK,UAAU,EAAE,OAAO,WAAW,UAAU,cAAc,CAAC;AAAA,IACrE;AAGA,UAAM,MAAM;AACZ,QAAI,IAAI,UAAU,IAAI,OAAO,IAAI,GAAG;AAClC,aAAO,KAAK,UAAU,EAAE,OAAO,UAAU,IAAI,+BAA+B,UAAU,IAAI,CAAC;AAAA,IAC7F;AAGA,UAAM,WAAoC;AAAA,MACxC;AAAA,MACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,MACzB,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C,GAAI,iBAAiB,SAAY,EAAE,aAAa,IAAI,CAAC;AAAA,MACrD,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC7B,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IACnC;AAGA,UAAM,gBAAgB,EAAE,GAAI,IAAI,UAAU,CAAC,GAAI,CAAC,IAAI,GAAG,SAAS;AAChE,UAAM,IAAI,gBAAgB,SAAS,UAAU,YAAY;AAAA,MACvD,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC;AAED,WAAO,KAAK,UAAU;AAAA,MACpB;AAAA,MACA,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW,SAAS;AAAA,IACtB,CAAC;AAAA,EACH;AACF;AAEA,SAAS,yBAAyB,KAAuC;AACvE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,YAAY,WAAW,SAAS,WAAW,kBAAkB,IAAI;AAOzE,QAAI,CAAC,cAAc,CAAC,aAAa,CAAC,SAAS;AACzC,aAAO,KAAK,UAAU,EAAE,OAAO,wDAAwD,CAAC;AAAA,IAC1F;AAGA,UAAM,WAAW,MAAM,iBAAiB,KAAK,iBAAiB;AAC9D,QAAI,SAAS,OAAO;AAClB,aAAO,KAAK,UAAU,EAAE,OAAO,SAAS,MAAM,CAAC;AAAA,IACjD;AAGA,QAAI,CAAC,YAAY,UAAU,GAAG;AAC5B,aAAO,KAAK,UAAU,EAAE,OAAO,wBAAwB,UAAU,yBAAyB,CAAC;AAAA,IAC7F;AACA,QAAI,CAAC,YAAY,SAAS,GAAG;AAC3B,aAAO,KAAK,UAAU,EAAE,OAAO,uBAAuB,SAAS,yBAAyB,CAAC;AAAA,IAC3F;AAGA,UAAM,YAAY,MAAM,IAAI,gBAAgB,UAAU,UAAU;AAChE,QAAI,CAAC,WAAW;AACd,aAAO,KAAK,UAAU,EAAE,OAAO,WAAW,UAAU,cAAc,CAAC;AAAA,IACrE;AAEA,UAAM,MAAM;AACZ,QAAI,CAAC,IAAI,UAAU,CAAC,IAAI,OAAO,SAAS,GAAG;AACzC,aAAO,KAAK,UAAU,EAAE,OAAO,UAAU,SAAS,0BAA0B,UAAU,IAAI,CAAC;AAAA,IAC7F;AAGA,UAAM,gBAAgB,IAAI,OAAO,SAAS;AAC1C,UAAM,eAAe,EAAE,GAAG,eAAe,GAAG,QAAQ;AACpD,UAAM,gBAAgB,EAAE,GAAG,IAAI,QAAQ,CAAC,SAAS,GAAG,aAAa;AAEjE,UAAM,IAAI,gBAAgB,SAAS,UAAU,YAAY;AAAA,MACvD,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC;AAED,WAAO,KAAK,UAAU;AAAA,MACpB;AAAA,MACA;AAAA,MACA,mBAAmB,OAAO,KAAK,OAAO;AAAA,MACtC,WAAW,SAAS;AAAA,IACtB,CAAC;AAAA,EACH;AACF;AAEA,SAAS,yBAAyB,KAAuC;AACvE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,YAAY,WAAW,WAAW,kBAAkB,IAAI;AAMhE,QAAI,CAAC,cAAc,CAAC,WAAW;AAC7B,aAAO,KAAK,UAAU,EAAE,OAAO,4CAA4C,CAAC;AAAA,IAC9E;AAGA,UAAM,WAAW,MAAM,iBAAiB,KAAK,iBAAiB;AAC9D,QAAI,SAAS,OAAO;AAClB,aAAO,KAAK,UAAU,EAAE,OAAO,SAAS,MAAM,CAAC;AAAA,IACjD;AAGA,QAAI,CAAC,YAAY,UAAU,GAAG;AAC5B,aAAO,KAAK,UAAU,EAAE,OAAO,wBAAwB,UAAU,yBAAyB,CAAC;AAAA,IAC7F;AACA,QAAI,CAAC,YAAY,SAAS,GAAG;AAC3B,aAAO,KAAK,UAAU,EAAE,OAAO,uBAAuB,SAAS,yBAAyB,CAAC;AAAA,IAC3F;AAGA,UAAM,YAAY,MAAM,IAAI,gBAAgB,UAAU,UAAU;AAChE,QAAI,CAAC,WAAW;AACd,aAAO,KAAK,UAAU,EAAE,OAAO,WAAW,UAAU,cAAc,CAAC;AAAA,IACrE;AAEA,UAAM,MAAM;AACZ,QAAI,CAAC,IAAI,UAAU,CAAC,IAAI,OAAO,SAAS,GAAG;AACzC,aAAO,KAAK,UAAU,EAAE,OAAO,UAAU,SAAS,0BAA0B,UAAU,IAAI,CAAC;AAAA,IAC7F;AAGA,UAAM,EAAE,CAAC,SAAS,GAAG,UAAU,GAAG,gBAAgB,IAAI,IAAI;AAC1D,UAAM,IAAI,gBAAgB,SAAS,UAAU,YAAY;AAAA,MACvD,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC;AAED,WAAO,KAAK,UAAU;AAAA,MACpB;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,WAAW,SAAS;AAAA,IACtB,CAAC;AAAA,EACH;AACF;AAEA,SAAS,yBAAyB,KAAuC;AACvE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,QAAQ,cAAc,IAAK,QAAQ,CAAC;AAK5C,UAAM,UAAU,MAAM,IAAI,gBAAgB,YAAY;AACtD,QAAI,SAAU,QAAwB,IAAI,OAAK;AAC7C,YAAM,OAAgC;AAAA,QACpC,MAAM,EAAE;AAAA,QACR,OAAO,EAAE,SAAS,EAAE;AAAA,QACpB,YAAY,EAAE,SAAS,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS;AAAA,MACxD;AACA,UAAI,iBAAiB,EAAE,QAAQ;AAC7B,aAAK,SAAS,OAAO,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO;AAAA,UACxD,MAAM;AAAA,UACN,MAAM,EAAE;AAAA,UACR,OAAO,EAAE,SAAS;AAAA,QACpB,EAAE;AAAA,MACJ;AACA,aAAO;AAAA,IACT,CAAC;AAGD,QAAI,QAAQ;AACV,YAAM,QAAQ,OAAO,YAAY;AACjC,eAAS,OAAO;AAAA,QAAO,OACpB,EAAE,KAAgB,YAAY,EAAE,SAAS,KAAK,KAC9C,EAAE,MAAiB,YAAY,EAAE,SAAS,KAAK;AAAA,MAClD;AAAA,IACF;AAEA,WAAO,KAAK,UAAU;AAAA,MACpB,SAAS;AAAA,MACT,YAAY,OAAO;AAAA,IACrB,CAAC;AAAA,EACH;AACF;AAEA,SAAS,4BAA4B,KAAuC;AAC1E,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,WAAW,IAAI;AAEvB,QAAI,CAAC,YAAY;AACf,aAAO,KAAK,UAAU,EAAE,OAAO,2BAA2B,CAAC;AAAA,IAC7D;AAGA,QAAI,CAAC,YAAY,UAAU,GAAG;AAC5B,aAAO,KAAK,UAAU,EAAE,OAAO,wBAAwB,UAAU,yBAAyB,CAAC;AAAA,IAC7F;AAEA,UAAM,YAAY,MAAM,IAAI,gBAAgB,UAAU,UAAU;AAChE,QAAI,CAAC,WAAW;AACd,aAAO,KAAK,UAAU,EAAE,OAAO,WAAW,UAAU,cAAc,CAAC;AAAA,IACrE;AAEA,UAAM,MAAM;AACZ,UAAM,SAAS,IAAI,UAAU,CAAC;AAC9B,UAAM,eAAe,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO;AAAA,MAC7D,MAAM;AAAA,MACN,MAAM,EAAE;AAAA,MACR,OAAO,EAAE,SAAS;AAAA,MAClB,UAAU,EAAE,YAAY;AAAA,MACxB,GAAI,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,IAAI,CAAC;AAAA,MAChD,GAAI,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC5C,EAAE;AAEF,WAAO,KAAK,UAAU;AAAA,MACpB,MAAM,IAAI;AAAA,MACV,OAAO,IAAI,SAAS,IAAI;AAAA,MACxB,QAAQ;AAAA,MACR,gBAAgB,IAAI,UAAU,CAAC;AAAA,IACjC,CAAC;AAAA,EACH;AACF;AAmBO,SAAS,sBACd,UACA,SACM;AACN,WAAS,SAAS,kBAAkB,0BAA0B,OAAO,CAAC;AACtE,WAAS,SAAS,cAAc,sBAAsB,OAAO,CAAC;AAC9D,WAAS,SAAS,iBAAiB,yBAAyB,OAAO,CAAC;AACpE,WAAS,SAAS,iBAAiB,yBAAyB,OAAO,CAAC;AACpE,WAAS,SAAS,iBAAiB,yBAAyB,OAAO,CAAC;AACpE,WAAS,SAAS,oBAAoB,4BAA4B,OAAO,CAAC;AAC5E;AApiBA,IA0Ba,2BAsCP;AAhEN;AAAA;AAAA;AAWA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGO,IAAM,4BAAoC;AAAA,MAC/C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AA+BA,IAAM,gBAAgB;AAAA;AAAA;;;AChEtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBA,kBAA6B;;;ACFtB,IAAM,mBAAN,MAA6C;AAAA,EAA7C;AACL,SAAS,OAAO;AAAA;AAAA,EAEhB,MAAM,KAAK,UAA0B,SAA+C;AAClF,UAAM,kBAAkB,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,OAAK,EAAE,SAAS,MAAM;AAC3E,UAAM,cAAc,iBAAiB;AACrC,UAAM,WAAW,OAAO,gBAAgB,WAAW,cAAc;AAcjE,UAAM,QAAQ,SAAS;AACvB,UAAM,mBAAmB,MAAM,QAAQ,KAAK,KAAK,MAAM,KAAK,OAAK,GAAG,SAAS,YAAY;AACzF,UAAM,yBAAyB,SAAS;AAAA,MACtC,OACE,EAAE,SAAS,UACX,MAAM,QAAQ,EAAE,OAAO,KACtB,EAAE,QAAyC,KAAK,OAAK,GAAG,aAAa,YAAY;AAAA,IACtF;AACA,UAAM,sBAAsB,SAAS;AAAA,MACnC,OACE,EAAE,SAAS,UACX,MAAM,QAAQ,EAAE,OAAO,KACtB,EAAE,QAAyC;AAAA,QAC1C,OAAK,OAAO,GAAG,aAAa,YAAY,EAAE,SAAS,WAAW,SAAS;AAAA,MACzE;AAAA,IACJ;AAGA,QAAI,MAAM,QAAQ,KAAK,KAAK,CAAC,uBAAuB,iBAAiB;AACnE,YAAM,cAAc,MAAM,OAAO,OAAK,OAAO,GAAG,SAAS,YAAY,EAAE,KAAK,WAAW,SAAS,CAAC;AACjG,YAAM,SAAS,eAAe,UAAU,WAAW;AACnD,UAAI,QAAQ;AACV,cAAM,WAAW,4BAA4B,UAAU,QAAQ;AAC/D,YAAI,UAAU;AACZ,gBAAM,aAAa,aAAa,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AACvD,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,OAAO,SAAS,SAAS;AAAA,YACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,YAC9D,WAAW;AAAA,cACT;AAAA,gBACE,MAAM;AAAA,gBACN;AAAA,gBACA,UAAU,OAAO;AAAA,gBACjB,OAAO,EAAE,SAAS;AAAA,cACpB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MAGF;AAAA,IACF;AAIA,QAAI,oBAAoB,CAAC,0BAA0B,iBAAiB;AAClE,YAAM,aAAa,aAAa,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AACvD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,SAAS,SAAS;AAAA,QACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,QAC9D,WAAW;AAAA,UACT;AAAA,YACE,MAAM;AAAA,YACN;AAAA,YACA,UAAU;AAAA,YACV,OAAO,EAAE,SAAS,SAAS;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAIA,QAAI,qBAAqB;AACvB,YAAM,WAAW,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,OAAK,EAAE,SAAS,MAAM;AACpE,YAAM,OAAO,MAAM,QAAQ,UAAU,OAAO,IACvC,SAAU,QAIP,KAAK,OAAK,OAAO,GAAG,aAAa,YAAY,EAAE,SAAS,WAAW,SAAS,CAAC,IACjF;AACJ,YAAM,MACJ,MAAM,UAAU,OAAO,KAAK,WAAW,YAAY,WAAW,KAAK,SAC/D,KAAK,OAAO,QACZ,MAAM;AACZ,UAAI,UAA+E,CAAC;AACpF,UAAI,OAAO,QAAQ,UAAU;AAC3B,YAAI;AAAE,oBAAU,KAAK,MAAM,GAAG;AAAA,QAAG,QAAQ;AAAA,QAAoB;AAAA,MAC/D,WAAW,OAAO,OAAO,QAAQ,UAAU;AACzC,kBAAU;AAAA,MACZ;AACA,UAAI,QAAQ,OAAO;AACjB,eAAO;AAAA,UACL,SAAS,mBAAmB,QAAQ,UAAU,EAAE,YAAY,QAAQ,KAAK;AAAA,UACzE,OAAO,SAAS,SAAS;AAAA,UACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,QAChE;AAAA,MACF;AACA,aAAO;AAAA,QACL,SAAS,YAAY,QAAQ,WAAW,kBAAkB,KAAK,QAAQ,UAAU,QAAQ;AAAA,QACzF,OAAO,SAAS,SAAS;AAAA,QACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,MAChE;AAAA,IACF;AAEA,QAAI,wBAAwB;AAC1B,YAAM,WAAW,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,OAAK,EAAE,SAAS,MAAM;AACpE,YAAM,OAAO,MAAM,QAAQ,UAAU,OAAO,IACvC,SAAU,QAIP,KAAK,OAAK,GAAG,aAAa,YAAY,IAC1C;AACJ,UAAI,UAAmE,CAAC;AACxE,YAAM,MACJ,MAAM,UAAU,OAAO,KAAK,WAAW,YAAY,WAAW,KAAK,SAC/D,KAAK,OAAO,QACZ,MAAM;AACZ,UAAI,OAAO,QAAQ,UAAU;AAC3B,YAAI;AACF,oBAAU,KAAK,MAAM,GAAG;AAAA,QAC1B,QAAQ;AACN,oBAAU,CAAC;AAAA,QACb;AAAA,MACF,WAAW,OAAO,OAAO,QAAQ,UAAU;AACzC,kBAAU;AAAA,MACZ;AACA,UAAI,QAAQ,OAAO;AACjB,eAAO;AAAA,UACL,SAAS,+BAA+B,QAAQ,KAAK;AAAA,UACrD,OAAO,SAAS,SAAS;AAAA,UACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,QAChE;AAAA,MACF;AACA,YAAM,UAAU,QAAQ,WAAW,CAAC;AACpC,YAAM,QAAQ,QAAQ,SAAS,QAAQ;AACvC,aAAO;AAAA,QACL,SAAS,kBAAkB,KAAK,UAAU,UAAU,IAAI,KAAK,GAAG,SAAS,QAAQ;AAAA,QACjF,OAAO,SAAS,SAAS;AAAA,QACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,MAChE;AAAA,IACF;AAEA,UAAM,UAAU,kBACZ,YAAY,QAAQ,KACpB;AAEJ,WAAO;AAAA,MACL;AAAA,MACA,OAAO,SAAS,SAAS;AAAA,MACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,QAAgB,SAA+C;AAC5E,WAAO;AAAA,MACL,SAAS,YAAY,MAAM;AAAA,MAC3B,OAAO,SAAS,SAAS;AAAA,MACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,OAAO,WACL,UACA,UACwC;AACxC,UAAM,SAAS,MAAM,KAAK,KAAK,QAAQ;AAEvC,UAAM,QAAQ,OAAO,QAAQ,MAAM,GAAG;AACtC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,WAAW,MAAM,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC;AAClD,YAAM,EAAE,MAAM,cAAc,IAAI,SAAS,CAAC,IAAI,MAAM,SAAS;AAAA,IAC/D;AACA,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,cAAc;AAAA,MACd,YAAY,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,MACnE,iBAAiB;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,OAA+C;AACzD,UAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAEnD,WAAO,MAAM,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;AAAA,EAClC;AAAA,EAEA,MAAM,aAAgC;AACpC,WAAO,CAAC,QAAQ;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,eACJ,UACA,QACA,SAC4B;AAC5B,UAAM,MAAM,SACT,OAAO,OAAK,EAAE,SAAS,QAAQ,EAC/B,IAAI,OAAM,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,EAAG,EACzD,KAAK,IAAI;AAKZ,UAAM,WAAW;AAEjB,UAAM,aAA0B,CAAC;AACjC,eAAW,SAAS,IAAI,SAAS,QAAQ,GAAG;AAC1C,YAAM,cAAc,MAAM,CAAC;AAC3B,UAAI,CAAC,YAAa;AAClB,YAAM,YAAY,MAAM,CAAC,KAAK;AAC9B,YAAM,cAAc,oBAAI,IAAY;AAEpC,iBAAW,KAAK,YAAY,MAAM,YAAY,GAAG;AAC/C,YAAI,EAAG,aAAY,IAAI,CAAC;AAAA,MAC1B;AAEA,iBAAW,KAAK,UAAU,YAAY,EAAE,MAAM,YAAY,GAAG;AAC3D,YAAI,EAAG,aAAY,IAAI,CAAC;AAAA,MAC1B;AAEA,iBAAW,KAAK,CAAC,GAAG,WAAW,GAAG;AAChC,YAAI,EAAE,SAAS,KAAK,EAAE,SAAS,GAAG,EAAG,aAAY,IAAI,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,MACrE;AACA,iBAAW,KAAK,EAAE,MAAM,aAAa,YAAY,CAAC;AAAA,IACpD;AAEA,UAAM,WAAW,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,OAAK,EAAE,SAAS,MAAM;AACpE,UAAM,WAAW,OAAO,UAAU,YAAY,WAC1C,SAAS,QAAQ,YAAY,IAC7B;AACJ,UAAM,aAAa,IAAI;AAAA,MACrB,SAAS,MAAM,aAAa,EAAE,OAAO,OAAK,EAAE,SAAS,CAAC;AAAA,IACxD;AAGA,eAAW,KAAK,CAAC,GAAG,UAAU,GAAG;AAC/B,UAAI,EAAE,SAAS,KAAK,EAAE,SAAS,GAAG,EAAG,YAAW,IAAI,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IACpE;AAEA,QAAI,SAAS,WAAW,CAAC,GAAG;AAC5B,QAAI,YAAY;AAChB,eAAW,QAAQ,YAAY;AAC7B,UAAI,QAAQ;AACZ,iBAAW,OAAO,KAAK,aAAa;AAClC,YAAI,WAAW,IAAI,GAAG,EAAG,UAAS;AAAA,MACpC;AACA,UAAI,QAAQ,WAAW;AACrB,oBAAY;AACZ,iBAAS,KAAK;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,WAA2C,CAAC;AAClD,QAAI,OAAQ,UAAS,KAAK,EAAE,YAAY,QAAQ,OAAO,GAAG,CAAC;AAC3D,aAAS,KAAK,CAAC,CAAC;AAEhB,eAAW,WAAW,UAAU;AAC9B,YAAM,SAAS,OAAO,UAAU,OAAO;AACvC,UAAI,OAAO,SAAS;AAClB,eAAO;AAAA,UACL,QAAQ,OAAO;AAAA,UACf,OAAO,SAAS,SAAS;AAAA,UACzB,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,IAAI;AAAA,MACR;AAAA,IAIF;AAAA,EACF;AACF;AAcA,SAAS,eACP,UACA,aAC+C;AAC/C,MAAI,YAAY,WAAW,KAAK,CAAC,SAAU,QAAO;AAClD,QAAM,aAAa,IAAI;AAAA,IACrB,SACG,YAAY,EACZ,MAAM,YAAY,EAClB,OAAO,OAAK,EAAE,SAAS,CAAC;AAAA,EAC7B;AAEA,QAAM,eAAe,oBAAI,IAAI;AAAA,IAC3B;AAAA,IAAY;AAAA,IAAU;AAAA,IAAQ;AAAA,IAC9B;AAAA,IAAS;AAAA,IAAS;AAAA,IAClB;AAAA,IAAS;AAAA,IAAQ;AAAA,IACjB;AAAA,IAAU;AAAA,IACV;AAAA,IAAW;AAAA,IACX;AAAA,IAAW;AAAA,IACX;AAAA,IAAU;AAAA,IACV;AAAA,IAAU;AAAA,IACV;AAAA,IAAQ;AAAA,IACR;AAAA,IAAW;AAAA,IACX;AAAA,IACA;AAAA,IAAU;AAAA,IAAU;AAAA,IAAS;AAAA,IAAW;AAAA,EAC1C,CAAC;AACD,QAAM,gBAAgB,CAAC,GAAG,UAAU,EAAE,KAAK,OAAK,aAAa,IAAI,CAAC,CAAC;AACnE,MAAI,CAAC,cAAe,QAAO;AAE3B,MAAI,OAAsD;AAC1D,MAAI,YAAY;AAChB,aAAW,QAAQ,aAAa;AAK9B,UAAM,aAAa,KAAK,KACrB,QAAQ,YAAY,EAAE,EACtB,YAAY,EACZ,MAAM,YAAY,EAClB,OAAO,OAAK,EAAE,SAAS,CAAC;AAC3B,QAAI,QAAQ;AACZ,eAAW,OAAO,YAAY;AAC5B,UAAI,CAAC,WAAW,IAAI,GAAG,EAAG;AAC1B,eAAS,aAAa,IAAI,GAAG,IAAI,IAAI;AAAA,IACvC;AACA,QAAI,QAAQ,WAAW;AACrB,kBAAY;AACZ,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,aAAa,IAAI,OAAO;AACjC;AAQA,SAAS,4BACP,UACA,UACoB;AACpB,QAAM,aAAa,SAChB,YAAY,EACZ,MAAM,YAAY,EAClB,OAAO,OAAK,EAAE,SAAS,CAAC;AAE3B,WAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,UAAM,IAAI,SAAS,CAAC;AACpB,QAAI,EAAE,SAAS,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,EAAG;AACpD,UAAM,QAAQ,EAAE;AAKhB,eAAW,QAAQ,OAAO;AACxB,UAAI,MAAM,aAAa,aAAc;AACrC,YAAM,MACJ,KAAK,UAAU,OAAO,KAAK,WAAW,YAAY,WAAW,KAAK,SAC9D,KAAK,OAAO,QACZ,KAAK;AACX,UAAI,UAAwD,CAAC;AAC7D,UAAI,OAAO,QAAQ,UAAU;AAC3B,YAAI;AAAE,oBAAU,KAAK,MAAM,GAAG;AAAA,QAAG,QAAQ;AAAA,QAAe;AAAA,MAC1D,WAAW,OAAO,OAAO,QAAQ,UAAU;AACzC,kBAAU;AAAA,MACZ;AACA,YAAM,UAAU,QAAQ,WAAW,CAAC;AACpC,UAAI,QAAQ,WAAW,EAAG;AAG1B,UAAI;AACJ,UAAI,YAAY;AAChB,iBAAW,OAAO,SAAS;AACzB,YAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AACrC,cAAM,KAAK,IAAI;AACf,YAAI,OAAO,OAAO,YAAY,OAAO,OAAO,SAAU;AACtD,cAAM,MAAM,OAAO,OAAO,GAAG,EAC1B,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,KAAK,GAAG,EACR,YAAY;AACf,cAAM,YAAY,IAAI,MAAM,YAAY,EAAE,OAAO,OAAO;AACxD,YAAI,QAAQ;AACZ,mBAAW,MAAM,YAAY;AAC3B,cAAI,UAAU,SAAS,EAAE,EAAG,UAAS;AAAA,QACvC;AACA,YAAI,QAAQ,WAAW;AACrB,sBAAY;AACZ,mBAAS,OAAO,EAAE;AAAA,QACpB;AAAA,MACF;AAEA,aAAO,UAAU,OAAO,QAAQ,CAAC,EAAE,EAAE;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;;;ACzZO,IAAM,eAAN,MAAmB;AAAA,EAAnB;AACL,SAAiB,cAAc,oBAAI,IAA8B;AACjE,SAAiB,WAAW,oBAAI,IAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzD,SAAS,YAA8B,SAA4B;AACjE,SAAK,YAAY,IAAI,WAAW,MAAM,UAAU;AAChD,SAAK,SAAS,IAAI,WAAW,MAAM,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,MAAoB;AAC7B,SAAK,YAAY,OAAO,IAAI;AAC5B,SAAK,SAAS,OAAO,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAuB;AACzB,WAAO,KAAK,YAAY,IAAI,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,MAA4C;AACxD,WAAO,KAAK,YAAY,IAAI,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,SAA6B;AAC3B,WAAO,MAAM,KAAK,KAAK,YAAY,OAAO,CAAC;AAAA,EAC7C;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA,EAGA,QAAkB;AAChB,WAAO,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,QACJ,UACA,KAC8B;AAC9B,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS,QAAQ;AACnD,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY,SAAS;AAAA,QACrB,UAAU,SAAS;AAAA,QACnB,QAAQ,EAAE,MAAM,QAAQ,OAAO,SAAS,SAAS,QAAQ,sBAAsB;AAAA,QAC/E,SAAS;AAAA,MACX;AAAA,IACF;AAEA,QAAI;AACF,YAAM,OAAO,OAAO,SAAS,UAAU,WACnC,KAAK,MAAM,SAAS,KAAK,IACxB,SAAS,SAAqC,CAAC;AACpD,YAAM,UAAU,MAAM,QAAQ,MAAM,GAAG;AACvC,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY,SAAS;AAAA,QACrB,UAAU,SAAS;AAAA,QACnB,QAAQ,EAAE,MAAM,QAAQ,OAAO,QAAQ;AAAA,MACzC;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY,SAAS;AAAA,QACrB,UAAU,SAAS;AAAA,QACnB,QAAQ,EAAE,MAAM,QAAQ,OAAO,QAAQ;AAAA,QACvC,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WACJ,WACA,KACgC;AAChC,WAAO,QAAQ,IAAI,UAAU,IAAI,QAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,CAAC;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,YAAY,MAAM;AACvB,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;ACxJO,IAAM,8BAAN,MAAoE;AAAA,EAApE;AACL,SAAiB,QAAQ,oBAAI,IAA4B;AACzD,SAAQ,UAAU;AAAA;AAAA,EAElB,MAAM,OAAO,UAKT,CAAC,GAA4B;AAC/B,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,KAAK,QAAQ,EAAE,KAAK,OAAO;AAEjC,UAAM,eAA+B;AAAA,MACnC;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,SAAS,QAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,UAAU,CAAC;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,MACX,UAAU,QAAQ;AAAA,IACpB;AAEA,SAAK,MAAM,IAAI,IAAI,YAAY;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAI,gBAAwD;AAChE,WAAO,KAAK,MAAM,IAAI,cAAc,KAAK;AAAA,EAC3C;AAAA,EAEA,MAAM,KAAK,UAKP,CAAC,GAA8B;AACjC,QAAI,UAAU,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAE5C,QAAI,QAAQ,QAAQ;AAClB,gBAAU,QAAQ,OAAO,OAAK,EAAE,WAAW,QAAQ,MAAM;AAAA,IAC3D;AACA,QAAI,QAAQ,SAAS;AACnB,gBAAU,QAAQ,OAAO,OAAK,EAAE,YAAY,QAAQ,OAAO;AAAA,IAC7D;AAGA,QAAI,QAAQ,QAAQ;AAClB,YAAM,MAAM,QAAQ,UAAU,OAAK,EAAE,OAAO,QAAQ,MAAM;AAC1D,UAAI,OAAO,GAAG;AACZ,kBAAU,QAAQ,MAAM,MAAM,CAAC;AAAA,MACjC;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,QAAQ,QAAQ,GAAG;AACtC,gBAAU,QAAQ,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC1C;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,gBAAwB,SAAgD;AACvF,UAAM,eAAe,KAAK,MAAM,IAAI,cAAc;AAClD,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,iBAAiB,cAAc,aAAa;AAAA,IAC9D;AAEA,iBAAa,SAAS,KAAK,OAAO;AAClC,iBAAa,aAAY,oBAAI,KAAK,GAAE,YAAY;AAChD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,gBAAuC;AAClD,SAAK,MAAM,OAAO,cAAc;AAAA,EAClC;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,MAAM,MAAM;AACjB,SAAK,UAAU;AAAA,EACjB;AACF;;;ACpGA,yBAA2B;AAK3B,IAAM,eAAe;AAgDd,IAAM,oBAAN,MAAiD;AAAA;AAAA,EAEtD,OAAO,QAA0B;AAAA,EAEjC;AACF;AAaO,IAAM,wBAAN,MAAqD;AAAA,EAI1D,YAAY,QAAqB,UAA+B,CAAC,GAAG;AAClE,SAAK,SAAS;AACd,SAAK,SAAS,QAAQ;AAAA,EACxB;AAAA,EAEA,MAAM,OAAO,OAAkC;AAC7C,UAAM,MAAM;AAAA,MACV,IAAI,aAAS,+BAAW,CAAC;AAAA,MACzB,iBAAiB,MAAM,kBAAkB;AAAA,MACzC,UAAU,MAAM,WAAW;AAAA,MAC3B,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM,SAAS;AAAA,MACtB,SAAS,MAAM;AAAA,MACf,eAAe,MAAM;AAAA,MACrB,mBAAmB,MAAM;AAAA,MACzB,cAAc,MAAM;AAAA,MACpB,YAAY,MAAM,MAAM,aAAa;AAAA,MACrC,aAAa,MAAM,MAAM,cAAc;AAAA,MACvC,YAAY,MAAM,MAAM,aAAa;AAAA,MACrC,UAAU,MAAM,MAAM,YAAY;AAAA,MAClC,YAAY,MAAM;AAAA,MAClB,QAAQ,MAAM;AAAA,MACd,OAAO,MAAM,SAAS;AAAA,MACtB,UAAU,MAAM,WAAW,KAAK,UAAU,MAAM,QAAQ,IAAI;AAAA,MAC5D,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC;AAEA,QAAI;AACF,YAAM,KAAK,OAAO,OAAO,cAAc,GAAG;AAAA,IAC5C,SAAS,KAAK;AACZ,WAAK,QAAQ;AAAA,QAAK;AAAA,QAChB,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI,EAAE,OAAO,OAAO,GAAG,EAAE;AAAA,MAAC;AAAA,IAC1E;AAAA,EACF;AACF;AAQO,SAAS,gBAAgB,OAYjB;AACb,QAAM,QAAQ,MAAM,SAAS,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AACpF,QAAM,OAAO,MAAM,SAAS,MAAM,WAC9B,MAAM,SAAS,aAAa,MAAM,OAAO,KAAK,IAC9C;AACJ,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,IACf,gBAAgB,MAAM;AAAA,IACtB,cAAc,MAAM;AAAA,IACpB,kBAAkB,MAAM;AAAA,IACxB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB,QAAQ,MAAM;AAAA,IACd,OAAO,MAAM;AAAA,IACb;AAAA,IACA,UAAU,MAAM;AAAA,EAClB;AACF;;;AJ/GA,SAAS,cAAc,IAAY,MAAuC;AACxE,SAAO,EAAE,MAAM,cAAc,IAAI,KAAK;AACxC;AAGA,SAAS,WAAW,QAA4C;AAC9D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,cAAc;AAAA,IACd,YAAY,QAAQ,SAAS,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,IACpF,iBAAiB;AAAA,EACnB;AACF;AA0CO,IAAM,aAAN,MAAM,WAAgC;AAAA,EAoB3C,YAAY,SAA0B,CAAC,GAAG;AAP1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAiB,qBAAqB,oBAAI,IAGxC;AAKA,SAAK,UAAU,OAAO,WAAW,IAAI,iBAAiB;AACtD,SAAK,SAAS,OAAO,cAAU,0BAAa,EAAE,OAAO,QAAQ,QAAQ,SAAS,CAAC;AAC/E,SAAK,eAAe,OAAO,gBAAgB,IAAI,aAAa;AAC5D,SAAK,sBAAsB,OAAO,uBAAuB,IAAI,4BAA4B;AACzF,SAAK,gBAAgB,OAAO;AAC5B,SAAK,gBAAgB,OAAO,iBAAiB,IAAI,kBAAkB;AACnE,SAAK,aAAa,OAAO;AAEzB,SAAK,OAAO;AAAA,MACV,0CAA0C,KAAK,QAAQ,IAAI,YAClD,KAAK,aAAa,IAAI,YAAY,KAAK,eAAe,QAAQ,CAAC;AAAA,IAC1E;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,cAAsB;AACxB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,MAAwB;AACjC,UAAM,OAAO,KAAK,QAAQ;AAC1B,SAAK,UAAU;AACf,QAAI,SAAS,KAAK,MAAM;AACtB,WAAK,OAAO,KAAK,6BAA6B,IAAI,WAAM,KAAK,IAAI,EAAE;AAAA,IACrE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,eAAe,gBAAwB,SAAsC;AACzF,QAAI;AACF,YAAM,KAAK,oBAAoB,WAAW,gBAAgB,OAAO;AAAA,IACnE,SAAS,KAAK;AACZ,WAAK,OAAO,KAAK,+BAA+B;AAAA,QAC9C;AAAA,QACA,MAAO,QAA8B;AAAA,QACrC,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,WACZ,WACA,SACA,IACY;AACZ,UAAM,UAAU,KAAK,IAAI;AACzB,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,KAAK,cAAc,OAAO,gBAAgB;AAAA,QAC7C;AAAA,QACA,SAAS,KAAK,QAAQ;AAAA,QACtB,OAAO,OAAO,SAAS,SAAS;AAAA,QAChC,OAAO,OAAO;AAAA,QACd,WAAW,KAAK,IAAI,IAAI;AAAA,QACxB,QAAQ;AAAA,QACR,UAAU,KAAK;AAAA,MACjB,CAAC,CAAC;AACF,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,KAAK,cAAc,OAAO,gBAAgB;AAAA,QAC7C;AAAA,QACA,SAAS,KAAK,QAAQ;AAAA,QACtB,OAAO,SAAS;AAAA,QAChB,WAAW,KAAK,IAAI,IAAI;AAAA,QACxB,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,KAAK;AAAA,MACjB,CAAC,CAAC;AACF,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,KAAK,UAA0B,SAA+C;AAClF,SAAK,OAAO,MAAM,aAAa,EAAE,cAAc,SAAS,QAAQ,OAAO,SAAS,MAAM,CAAC;AACvF,WAAO,KAAK,WAAW,QAAQ,SAAS,MAAM,KAAK,QAAQ,KAAK,UAAU,OAAO,CAAC;AAAA,EACpF;AAAA,EAEA,MAAM,SAAS,QAAgB,SAA+C;AAC5E,SAAK,OAAO,MAAM,iBAAiB,EAAE,cAAc,OAAO,QAAQ,OAAO,SAAS,MAAM,CAAC;AACzF,WAAO,KAAK,WAAW,YAAY,SAAS,MAAM,KAAK,QAAQ,SAAS,QAAQ,OAAO,CAAC;AAAA,EAC1F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,eACJ,UACA,QACA,SAC4B;AAC5B,SAAK,OAAO,MAAM,uBAAuB,EAAE,cAAc,SAAS,QAAQ,OAAO,SAAS,MAAM,CAAC;AACjG,QAAI,CAAC,KAAK,QAAQ,gBAAgB;AAChC,YAAM,IAAI;AAAA,QACR,iBAAiB,KAAK,QAAQ,IAAI;AAAA,MAEpC;AAAA,IACF;AACA,WAAO,KAAK;AAAA,MAAW;AAAA,MAAmB;AAAA,MAAS,MACjD,KAAK,QAAQ,eAAgB,UAAU,QAAQ,OAAO;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,OAAO,WACL,UACA,SACwC;AACxC,SAAK,OAAO,MAAM,mBAAmB,EAAE,cAAc,SAAS,QAAQ,OAAO,SAAS,MAAM,CAAC;AAE7F,QAAI,CAAC,KAAK,QAAQ,YAAY;AAE5B,YAAM,SAAS,MAAM,KAAK,QAAQ,KAAK,UAAU,OAAO;AACxD,YAAM,cAAc,YAAY,OAAO,OAAO;AAC9C,YAAM,WAAW,MAAM;AACvB;AAAA,IACF;AAEA,WAAO,KAAK,QAAQ,WAAW,UAAU,OAAO;AAAA,EAClD;AAAA,EAEA,MAAM,MAAM,OAA0B,OAAqC;AACzE,QAAI,CAAC,KAAK,QAAQ,OAAO;AACvB,YAAM,IAAI,MAAM,iBAAiB,KAAK,QAAQ,IAAI,+BAA+B;AAAA,IACnF;AACA,WAAO,KAAK,QAAQ,MAAM,OAAO,KAAK;AAAA,EACxC;AAAA,EAEA,MAAM,aAAgC;AACpC,QAAI,CAAC,KAAK,QAAQ,YAAY;AAC5B,aAAO,CAAC;AAAA,IACV;AACA,WAAO,KAAK,QAAQ,WAAW;AAAA,EACjC;AAAA;AAAA,EAQA,OAAe,kBAAkB,IAAiC;AAChE,WAAO,GAAG,UAAU,OAAO,GAAG,WAAW,YAAY,WAAW,GAAG,SAC/D,OAAO,GAAG,OAAO,KAAK,IAAI;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,cACJ,UACA,SACmB;AACnB,WAAO,KAAK;AAAA,MAAW;AAAA,MAAmB;AAAA,MAAS,MACjD,KAAK,kBAAkB,UAAU,OAAO;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,UACA,SACmB;AAEnB,UAAM;AAAA,MACJ,eAAe;AAAA,MACf;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,IAAI,WAAW,CAAC;AAChB,UAAM,gBAAgB,WAAW,WAAU;AAC3C,UAAM,kBAAkB,KAAK,aAAa,OAAO;AACjD,UAAM,iBAAiB,sBAAsB;AAG7C,UAAM,cAAc;AAAA,MAClB,GAAG;AAAA,MACH,GAAI,YAAY,SAAS,CAAC;AAAA,IAC5B;AAGA,UAAM,cAAgC;AAAA,MACpC,GAAG;AAAA,MACH,OAAO,YAAY,SAAS,IAAI,cAAc;AAAA,MAC9C,YAAY,YAAY,SAAS,IAAK,YAAY,cAAc,SAAU;AAAA,IAC5E;AAGA,UAAM,eAAe,CAAC,GAAG,QAAQ;AAKjC,QAAI,kBAAkB,SAAS,SAAS,GAAG;AACzC,YAAM,OAAO,SAAS,SAAS,SAAS,CAAC;AACzC,UAAI,QAAS,KAA2B,SAAS,QAAQ;AACvD,cAAM,KAAK,eAAe,gBAAgB,IAAI;AAAA,MAChD;AAAA,IACF;AAGA,UAAM,aAA4E,CAAC;AAEnF,SAAK,OAAO,MAAM,4BAA4B;AAAA,MAC5C,cAAc,aAAa;AAAA,MAC3B,WAAW,YAAY;AAAA,MACvB;AAAA,IACF,CAAC;AAED,QAAI,oBAAoB;AAExB,aAAS,YAAY,GAAG,YAAY,eAAe,aAAa;AAC9D,YAAM,SAAS,MAAM,KAAK,QAAQ,KAAK,cAAc,WAAW;AAGhE,UAAI,CAAC,OAAO,aAAa,OAAO,UAAU,WAAW,GAAG;AACtD,aAAK,OAAO,MAAM,+BAA+B,EAAE,WAAW,SAAS,OAAO,QAAQ,MAAM,GAAG,EAAE,EAAE,CAAC;AACpG,YAAI,gBAAgB;AAClB,gBAAM,KAAK,eAAe,gBAAgB;AAAA,YACxC,MAAM;AAAA,YACN,SAAS,OAAO;AAAA,UAClB,CAAiB;AAAA,QACnB;AACA,eAAO;AAAA,MACT;AAEA,WAAK,OAAO,MAAM,iCAAiC;AAAA,QACjD;AAAA,QACA,OAAO,OAAO,UAAU,IAAI,QAAM,GAAG,QAAQ;AAAA,MAC/C,CAAC;AAGD,YAAM,mBAAyE,CAAC;AAChF,UAAI,OAAO,QAAS,kBAAiB,KAAK,EAAE,MAAM,QAAQ,MAAM,OAAO,QAAQ,CAAC;AAChF,uBAAiB,KAAK,GAAG,OAAO,SAAS;AACzC,YAAM,gBAAgB;AAAA,QACpB,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AACA,mBAAa,KAAK,aAAa;AAC/B,UAAI,gBAAgB;AAClB,cAAM,KAAK,eAAe,gBAAgB,aAAa;AAAA,MACzD;AAKA,YAAM,cAAqC,MAAM,KAAK,aAAa;AAAA,QACjE,OAAO;AAAA,QACP;AAAA,MACF;AAKA,iBAAW,MAAM,aAAa;AAC5B,YAAI,GAAG,SAAS;AACd,gBAAM,cAAc,OAAO,UAAW,KAAK,QAAM,GAAG,eAAe,GAAG,UAAU;AAChF,gBAAM,WAAW,aAAa,YAAY;AAC1C,gBAAM,YAAY,WAAU,kBAAkB,EAAE;AAChD,gBAAM,aAAa,EAAE,WAAW,UAAU,OAAO,UAAU;AAC3D,qBAAW,KAAK,UAAU;AAC1B,eAAK,OAAO,KAAK,iCAAiC,UAAU;AAE5D,cAAI,eAAe,aAAa;AAC9B,kBAAM,SAAS,YAAY,aAAa,SAAS;AACjD,gBAAI,WAAW,SAAS;AACtB,kCAAoB;AAAA,YACtB;AAAA,UACF;AAAA,QACF;AAGA,cAAM,WAAW;AAAA,UACf,MAAM;AAAA,UACN,SAAS,CAAC,EAAE;AAAA,QACd;AACA,qBAAa,KAAK,QAAQ;AAC1B,YAAI,gBAAgB;AAClB,gBAAM,KAAK,eAAe,gBAAgB,QAAQ;AAAA,QACpD;AAAA,MACF;AAEA,UAAI,mBAAmB;AACrB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,mBAAmB;AACrB,WAAK,OAAO,KAAK,sDAAsD,EAAE,WAAW,CAAC;AAAA,IACvF,OAAO;AACL,WAAK,OAAO,KAAK,qEAAqE;AAAA,QACpF,YAAY,WAAW,SAAS,IAAI,aAAa;AAAA,MACnD,CAAC;AAAA,IACH;AAGA,UAAM,cAAc,MAAM,KAAK,QAAQ,KAAK,cAAc;AAAA,MACxD,GAAG;AAAA,MACH,OAAO;AAAA,MACP,YAAY;AAAA,IACd,CAAC;AACD,QAAI,gBAAgB;AAClB,YAAM,KAAK,eAAe,gBAAgB;AAAA,QACxC,MAAM;AAAA,QACN,SAAS,YAAY;AAAA,MACvB,CAAiB;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,oBACL,UACA,SACwC;AACxC,UAAM;AAAA,MACJ,eAAe;AAAA,MACf;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,IAAI,WAAW,CAAC;AAChB,UAAM,gBAAgB,WAAW,WAAU;AAC3C,UAAM,kBAAkB,KAAK,aAAa,OAAO;AACjD,UAAM,iBAAiB,sBAAsB;AAE7C,UAAM,cAAc;AAAA,MAClB,GAAG;AAAA,MACH,GAAI,YAAY,SAAS,CAAC;AAAA,IAC5B;AAEA,UAAM,cAAgC;AAAA,MACpC,GAAG;AAAA,MACH,OAAO,YAAY,SAAS,IAAI,cAAc;AAAA,MAC9C,YAAY,YAAY,SAAS,IAAK,YAAY,cAAc,SAAU;AAAA,IAC5E;AAEA,UAAM,eAAe,CAAC,GAAG,QAAQ;AACjC,QAAI,oBAAoB;AAExB,QAAI,kBAAkB,SAAS,SAAS,GAAG;AACzC,YAAM,OAAO,SAAS,SAAS,SAAS,CAAC;AACzC,UAAI,QAAS,KAA2B,SAAS,QAAQ;AACvD,cAAM,KAAK,eAAe,gBAAgB,IAAI;AAAA,MAChD;AAAA,IACF;AAEA,aAAS,YAAY,GAAG,YAAY,eAAe,aAAa;AAE9D,YAAMC,UAAS,MAAM,KAAK,QAAQ,KAAK,cAAc,WAAW;AAEhE,UAAI,CAACA,QAAO,aAAaA,QAAO,UAAU,WAAW,GAAG;AAEtD,YAAI,gBAAgB;AAClB,gBAAM,KAAK,eAAe,gBAAgB;AAAA,YACxC,MAAM;AAAA,YACN,SAASA,QAAO;AAAA,UAClB,CAAiB;AAAA,QACnB;AACA,cAAM,cAAc,UAAUA,QAAO,OAAO;AAC5C,cAAM,WAAWA,OAAM;AACvB;AAAA,MACF;AAGA,iBAAW,MAAMA,QAAO,WAAW;AACjC,cAAM,EAAE,MAAM,aAAa,YAAY,GAAG,YAAY,UAAU,GAAG,UAAU,OAAO,GAAG,MAAM;AAAA,MAC/F;AAEA,YAAM,mBAAyE,CAAC;AAChF,UAAIA,QAAO,QAAS,kBAAiB,KAAK,EAAE,MAAM,QAAQ,MAAMA,QAAO,QAAQ,CAAC;AAChF,uBAAiB,KAAK,GAAGA,QAAO,SAAS;AACzC,YAAM,gBAAgB;AAAA,QACpB,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AACA,mBAAa,KAAK,aAAa;AAC/B,UAAI,gBAAgB;AAClB,cAAM,KAAK,eAAe,gBAAgB,aAAa;AAAA,MACzD;AAEA,YAAM,cAAqC,MAAM,KAAK,aAAa;AAAA,QACjEA,QAAO;AAAA,QACP;AAAA,MACF;AAEA,iBAAW,MAAM,aAAa;AAC5B,YAAI,GAAG,WAAW,aAAa;AAC7B,gBAAM,cAAcA,QAAO,UAAW,KAAK,QAAM,GAAG,eAAe,GAAG,UAAU;AAChF,cAAI,aAAa;AACf,kBAAM,YAAY,WAAU,kBAAkB,EAAE;AAChD,kBAAM,SAAS,YAAY,aAAa,SAAS;AACjD,gBAAI,WAAW,SAAS;AACtB,kCAAoB;AAAA,YACtB;AAAA,UACF;AAAA,QACF;AAEA,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,YAAY,GAAG;AAAA,UACf,UAAU,GAAG;AAAA,UACb,QAAQ,GAAG;AAAA,QACb;AACA,cAAM,WAAW;AAAA,UACf,MAAM;AAAA,UACN,SAAS,CAAC,EAAE;AAAA,QACd;AACA,qBAAa,KAAK,QAAQ;AAC1B,YAAI,gBAAgB;AAClB,gBAAM,KAAK,eAAe,gBAAgB,QAAQ;AAAA,QACpD;AAAA,MACF;AAEA,UAAI,mBAAmB;AACrB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,mBAAmB;AACrB,WAAK,OAAO,KAAK,0DAA0D;AAAA,IAC7E,OAAO;AACL,WAAK,OAAO,KAAK,iDAAiD;AAAA,IACpE;AACA,UAAM,eAAe,EAAE,GAAG,aAAa,OAAO,QAAW,YAAY,OAAU;AAC/E,UAAM,SAAS,MAAM,KAAK,QAAQ,KAAK,cAAc,YAAY;AACjE,QAAI,gBAAgB;AAClB,YAAM,KAAK,eAAe,gBAAgB;AAAA,QACxC,MAAM;AAAA,QACN,SAAS,OAAO;AAAA,MAClB,CAAiB;AAAA,IACnB;AACA,UAAM,cAAc,UAAU,OAAO,OAAO;AAC5C,UAAM,WAAW,MAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,gCACE,UACA,UACM;AACN,SAAK,mBAAmB,IAAI,UAAU,QAAQ;AAAA,EAChD;AAAA,EAEA,MAAM,qBAAqB,OAA2D;AACpF,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,gFAA2E;AAAA,IAC7F;AACA,UAAM,KAAK,MAAM,eAAe,CAAC;AACjC,UAAM,MAAM;AAAA,MACV;AAAA,MACA,iBAAiB,MAAM,kBAAkB;AAAA,MACzC,YAAY,MAAM,aAAa;AAAA,MAC/B,aAAa,MAAM;AAAA,MACnB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,MACjB,YAAY,KAAK,UAAU,MAAM,aAAa,CAAC,CAAC;AAAA,MAChD,QAAQ;AAAA,MACR,aAAa,MAAM,cAAc;AAAA,MACjC,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACtC;AACA,UAAM,KAAK,WAAW,OAAO,sBAAsB,GAAG;AACtD,SAAK,OAAO;AAAA,MACV,iCAAiC,EAAE,KAAK,MAAM,QAAQ,OAAO,MAAM,UAAU;AAAA,IAC/E;AACA,WAAO,EAAE,GAAG;AAAA,EACd;AAAA,EAEA,MAAM,qBACJ,IACA,SAC8E;AAC9E,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,UAAM,MAAM,MAAM,KAAK,eAAe,EAAE;AACxC,QAAI,IAAI,WAAW,WAAW;AAC5B,YAAM,IAAI,MAAM,kBAAkB,EAAE,eAAe,IAAI,MAAM,EAAE;AAAA,IACjE;AACA,UAAM,WAAW,KAAK,mBAAmB,IAAI,IAAI,SAAS;AAC1D,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR,sCAAsC,IAAI,SAAS;AAAA,MACrD;AAAA,IACF;AACA,UAAM,KAAK,WAAW;AAAA,MACpB;AAAA,MACA;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC;AAAA,MACA,EAAE,OAAO,EAAE,GAAG,EAAE;AAAA,IAClB;AACA,QAAI,SAAkC,CAAC;AACvC,QAAI;AACF,eAAS,IAAI,aAAc,KAAK,MAAM,IAAI,UAAU,IAAgC,CAAC;AAAA,IACvF,QAAQ;AACN,eAAS,CAAC;AAAA,IACZ;AACA,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,MAAM;AACjC,YAAM,KAAK,WAAW;AAAA,QACpB;AAAA,QACA,EAAE,IAAI,QAAQ,YAAY,QAAQ,KAAK,UAAU,OAAO,IAAI,EAAE;AAAA,QAC9D,EAAE,OAAO,EAAE,GAAG,EAAE;AAAA,MAClB;AACA,WAAK,OAAO,KAAK,uBAAuB,EAAE,gBAAgB,OAAO,EAAE;AACnE,aAAO,EAAE,QAAQ,YAAY,QAAQ,IAAI;AAAA,IAC3C,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAM,KAAK,WAAW;AAAA,QACpB;AAAA,QACA,EAAE,IAAI,QAAQ,UAAU,OAAO,IAAI;AAAA,QACnC,EAAE,OAAO,EAAE,GAAG,EAAE;AAAA,MAClB;AACA,WAAK,OAAO,KAAK,uBAAuB,EAAE,2BAA2B,GAAG,EAAE;AAC1E,aAAO,EAAE,QAAQ,UAAU,OAAO,IAAI;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,MAAM,oBAAoB,IAAY,SAAiB,QAAgC;AACrF,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,UAAM,MAAM,MAAM,KAAK,eAAe,EAAE;AACxC,QAAI,IAAI,WAAW,WAAW;AAC5B,YAAM,IAAI,MAAM,kBAAkB,EAAE,eAAe,IAAI,MAAM,EAAE;AAAA,IACjE;AACA,UAAM,KAAK,WAAW;AAAA,MACpB;AAAA,MACA;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,kBAAkB,UAAU;AAAA,MAC9B;AAAA,MACA,EAAE,OAAO,EAAE,GAAG,EAAE;AAAA,IAClB;AACA,SAAK,OAAO,KAAK,uBAAuB,EAAE,gBAAgB,OAAO,EAAE;AAAA,EACrE;AAAA,EAEA,MAAM,mBAAmB,QAKO;AAC9B,QAAI,CAAC,KAAK,WAAY,QAAO,CAAC;AAC9B,UAAM,QAAiC,CAAC;AACxC,QAAI,QAAQ,QAAQ;AAClB,YAAM,SAAS,MAAM,QAAQ,OAAO,MAAM,IAAI,EAAE,IAAI,OAAO,OAAO,IAAI,OAAO;AAAA,IAC/E;AACA,QAAI,QAAQ,eAAgB,OAAM,kBAAkB,OAAO;AAC3D,QAAI,QAAQ,WAAY,OAAM,cAAc,OAAO;AACnD,UAAM,OAAQ,MAAM,KAAK,WAAW,KAAK,sBAAsB;AAAA,MAC7D;AAAA,MACA,OAAO,QAAQ,SAAS;AAAA,MACxB,SAAS,CAAC,EAAE,OAAO,eAAe,OAAO,OAAO,CAAC;AAAA,IACnD,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,eAAe,IAAuC;AAClE,UAAM,OAAQ,MAAM,KAAK,WAAY,KAAK,sBAAsB;AAAA,MAC9D,OAAO,EAAE,GAAG;AAAA,MACZ,OAAO;AAAA,IACT,CAAC;AACD,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,kBAAkB,EAAE,YAAY;AAC1D,WAAO;AAAA,EACT;AACF;AAAA;AAAA;AApoBa,WA0LK,yBAAyB;AA1LpC,IAAM,YAAN;AAsoBP,SAAS,iBAAyB;AAGhC,QAAM,IAAI;AACV,MAAI,EAAE,QAAQ,WAAY,QAAO,EAAE,OAAO,WAAW;AACrD,SAAO,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAC9E;;;AKtuBA,uBAAiC;;;ACiBjC,SAAS,IAAI,MAAsB;AACjC,SAAO,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA;AAAA;AACtC;AAMA,SAAS,eAAe,QAAgB,MAAsB;AAC5D,SAAO,GAAG,MAAM,IAAI,KAAK,UAAU,IAAI,CAAC;AAAA;AAC1C;AAUO,SAAS,iBAAiB,MAAuC;AACtE,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,IAAI,EAAE,MAAM,cAAc,IAAI,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,IAE9D,KAAK;AACH,aAAO,IAAI;AAAA,QACT,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IAEH,KAAK;AACH,aAAO,IAAI;AAAA,QACT,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,gBAAgB,KAAK;AAAA,MACvB,CAAC;AAAA,IAEH,KAAK;AACH,aAAO,IAAI;AAAA,QACT,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,UAAU,KAAK;AAAA,QACf,OAAO,KAAK;AAAA,MACd,CAAC;AAAA,IAEH,KAAK;AACH,aAAO,IAAI;AAAA,QACT,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,QAAQ,KAAK;AAAA,MACf,CAAC;AAAA,IAEH,KAAK;AACH,aAAO,IAAI;AAAA,QACT,MAAM;AAAA,QACN,WAAW,OAAO,KAAK,KAAK;AAAA,MAC9B,CAAC;AAAA;AAAA;AAAA,IAIH,KAAK;AACH,aAAO,eAAe,KAAK,EAAE,MAAM,GAAG,CAAC;AAAA,IAEzC,KAAK;AACH,aAAO,eAAe,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;AAAA,IAEhD,KAAK;AACH,aAAO;AAAA;AAAA;AAAA,IAGT;AAGE,UAAK,KAAa,MAAM,WAAW,OAAO,GAAG;AAC3C,eAAO,IAAI,IAAW;AAAA,MACxB;AACA,aAAO;AAAA,EACX;AACF;AASA,gBAAuB,uBACrB,QACuB;AAEvB,QAAM,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC3B,QAAM,IAAI,EAAE,MAAM,aAAa,CAAC;AAChC,QAAM,IAAI,EAAE,MAAM,cAAc,IAAI,IAAI,CAAC;AAEzC,MAAI,WAAW;AACf,MAAI,eAAe;AACnB,MAAI;AAEJ,MAAI;AACF,qBAAiB,QAAQ,QAAQ;AAE/B,UAAK,KAA0B,SAAS,SAAS;AAC/C,cAAM,UAAU;AAChB,cAAM,MAAM,QAAQ;AACpB,uBACG,OAAO,OAAO,QAAQ,YAAY,aAAa,MAC5C,OAAQ,IAA6B,OAAO,IAC5C,OAAO,QAAQ,WACb,MACA;AACR,uBAAe;AACf;AAAA,MACF;AAGA,UAAI,KAAK,SAAS,UAAU;AAC1B,uBAAe,KAAK,gBAAgB;AAAA,MACtC;AAGA,UAAI,KAAK,SAAS,iBAAiB,KAAK,SAAS,UAAU;AACzD,YAAI,UAAU;AACZ,gBAAM,IAAI,EAAE,MAAM,YAAY,IAAI,IAAI,CAAC;AACvC,qBAAW;AAAA,QACb;AAEA;AAAA,MACF;AAEA,YAAM,QAAQ,iBAAiB,IAAI;AACnC,UAAI,OAAO;AACT,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AAIZ,mBAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,mBAAe;AAAA,EACjB;AAGA,MAAI,UAAU;AACZ,UAAM,IAAI,EAAE,MAAM,YAAY,IAAI,IAAI,CAAC;AAAA,EACzC;AAIA,MAAI,cAAc;AAChB,UAAM,IAAI,EAAE,MAAM,SAAS,WAAW,aAAa,CAAC;AAAA,EACtD;AAGA,QAAM,IAAI,EAAE,MAAM,cAAc,CAAC;AACjC,QAAM,IAAI,EAAE,MAAM,UAAU,aAAa,CAAC;AAC1C,QAAM;AACR;;;AC3KO,SAAS,iBAAiB,KAA4C;AAC3E,QAAM,OAAO,IAAI;AAGjB,MAAI,OAAO,IAAI,YAAY,UAAU;AACnC,WAAO,EAAE,MAAM,SAAS,IAAI,QAAQ;AAAA,EACtC;AAGA,MAAI,MAAM,QAAQ,IAAI,OAAO,GAAG;AAC9B,WAAO,EAAE,MAAM,SAAS,IAAI,QAAQ;AAAA,EACtC;AAGA,MAAI,MAAM,QAAQ,IAAI,KAAK,GAAG;AAC5B,UAAM,YAAa,IAAI,MACpB,OAAO,OAAK,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS,QAAQ,EAC3D,IAAI,OAAK,EAAE,IAAc;AAC5B,QAAI,UAAU,SAAS,GAAG;AACxB,aAAO,EAAE,MAAM,SAAS,UAAU,KAAK,EAAE,EAAE;AAAA,IAC7C;AAAA,EACF;AAGA,SAAO,EAAE,MAAM,SAAS,GAAG;AAC7B;AAcO,SAAS,uBACd,KACA,MACe;AACf,QAAM,UAAU,IAAI;AAIpB,MAAI,MAAM,QAAQ,IAAI,KAAK,GAAG;AAC5B,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO;AAAA,EACT;AAGA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,eAAW,QAAQ,SAAsB;AACvC,UAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,eAAO;AAAA,MACT;AACA,YAAM,UAAU;AAChB,UAAI,OAAO,QAAQ,SAAS,UAAU;AACpC,eAAO;AAAA,MACT;AACA,UAAI,QAAQ,SAAS,UAAU,OAAO,QAAQ,SAAS,UAAU;AAC/D,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAGA,OAAK,YAAY,QAAQ,YAAY,WAAc,MAAM,mBAAmB;AAC1E,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ACXA,IAAM,cAAc,oBAAI,IAAY,CAAC,UAAU,QAAQ,aAAa,MAAM,CAAC;AAW3E,SAAS,gBAAgB,KAA6B;AACpD,MAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,WAAO;AAAA,EACT;AACA,QAAM,MAAM;AACZ,MAAI,OAAO,IAAI,SAAS,YAAY,CAAC,YAAY,IAAI,IAAI,IAAI,GAAG;AAC9D,WAAO,+BAA+B,CAAC,GAAG,WAAW,EAAE,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,EACtF;AAGA,QAAM,aAAa,IAAI,SAAS,eAAe,IAAI,SAAS;AAC5D,SAAO,uBAAuB,KAAK,EAAE,mBAAmB,WAAW,CAAC;AACtE;AAqBO,SAAS,cACd,WACA,qBACA,QACmB;AACnB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,OAAO,QAAQ;AACtB,cAAM,OAAQ,IAAI,QAAQ,CAAC;AAG3B,cAAM,WAAW,KAAK;AACtB,YAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,GAAG;AACrD,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,6BAA6B,EAAE;AAAA,QACtE;AAEA,mBAAW,OAAO,UAAU;AAC1B,gBAAM,MAAM,gBAAgB,GAAG;AAC/B,cAAI,IAAK,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,QACtD;AAKA,cAAM,SAAU,KAAK,WAAW,CAAC;AACjC,cAAM,kBAA2C;AAAA,UAC/C,GAAG;AAAA,UACH,GAAI,KAAK,SAAS,QAAQ,EAAE,OAAO,KAAK,MAAM;AAAA,UAC9C,GAAI,KAAK,eAAe,QAAQ,EAAE,aAAa,KAAK,YAAY;AAAA,UAChE,GAAI,KAAK,aAAa,QAAQ,EAAE,WAAW,KAAK,UAAU;AAAA,QAC5D;AAKA,cAAM,kBAAkB,KAAK,UAAU,KAAK;AAC5C,YAAI,mBAAmB,QAAQ,OAAO,oBAAoB,UAAU;AAClE,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,uCAAuC,EAAE;AAAA,QAChF;AACA,cAAM,eAAe;AACrB,cAAM,gBAAgC;AAAA,UACpC,GAAI,eACA,CAAC,EAAE,MAAM,UAAmB,SAAS,aAAa,CAAC,IACnD,CAAC;AAAA,UACL,GAAG,SAAS,IAAI,OAAK,iBAAiB,CAA4B,CAAC;AAAA,QACrE;AAGA,cAAM,aAAa,KAAK,WAAW;AAEnC,YAAI,YAAY;AAEd,cAAI;AACF,gBAAI,CAAE,UAAkB,qBAAqB;AAC3C,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,0DAA0D,EAAE;AAAA,YACnG;AACA,kBAAM,SAAU,UAAkB,oBAAoB,eAAe,eAAsB;AAC3F,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,QAAQ;AAAA,cACR,kBAAkB;AAAA,cAClB,aAAa;AAAA,cACb,SAAS;AAAA,gBACP,gBAAgB;AAAA,gBAChB,iBAAiB;AAAA,gBACjB,cAAc;AAAA,gBACd,iCAAiC;AAAA,cACnC;AAAA,cACA,QAAQ,uBAAuB,MAAM;AAAA,YACvC;AAAA,UACF,SAAS,KAAK;AACZ,mBAAO,MAAM,iCAAiC,eAAe,QAAQ,MAAM,MAAS;AACpF,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,UACrE;AAAA,QACF;AAGA,YAAI;AACF,gBAAM,SAAS,MAAO,UAAkB,cAAc,eAAe,eAAsB;AAC3F,iBAAO,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,QACrC,SAAS,KAAK;AACZ,iBAAO,MAAM,0BAA0B,eAAe,QAAQ,MAAM,MAAS;AAC7E,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,OAAO,QAAQ;AACtB,cAAM,EAAE,UAAU,QAAQ,IAAK,IAAI,QAAQ,CAAC;AAK5C,YAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,GAAG;AACrD,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,6BAA6B,EAAE;AAAA,QACtE;AAEA,mBAAW,OAAO,UAAU;AAC1B,gBAAM,MAAM,gBAAgB,GAAG;AAC/B,cAAI,IAAK,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,QACtD;AAEA,YAAI;AACF,cAAI,CAAC,UAAU,YAAY;AACzB,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,0DAA0D,EAAE;AAAA,UACnG;AACA,gBAAM,SAAS,UAAU,WAAW,SAAS,IAAI,OAAK,iBAAiB,CAA4B,CAAC,GAAG,OAAc;AACrH,iBAAO,EAAE,QAAQ,KAAK,QAAQ,MAAM,OAAO;AAAA,QAC7C,SAAS,KAAK;AACZ,iBAAO,MAAM,iCAAiC,eAAe,QAAQ,MAAM,MAAS;AACpF,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,aAAa;AAAA,MAC3B,SAAS,OAAO,QAAQ;AACtB,cAAM,EAAE,QAAQ,QAAQ,IAAK,IAAI,QAAQ,CAAC;AAK1C,YAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAEA,YAAI;AACF,gBAAM,SAAS,MAAM,UAAU,SAAS,QAAQ,OAAc;AAC9D,iBAAO,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,QACrC,SAAS,KAAK;AACZ,iBAAO,MAAM,8BAA8B,eAAe,QAAQ,MAAM,MAAS;AACjF,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,YAAY;AACnB,YAAI;AACF,gBAAM,SAAS,UAAU,aAAa,MAAM,UAAU,WAAW,IAAI,CAAC;AACtE,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,EAAE;AAAA,QACzC,SAAS,KAAK;AACZ,iBAAO,MAAM,4BAA4B,eAAe,QAAQ,MAAM,MAAS;AAC/E,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,kBAAkB;AAAA,MAChC,SAAS,OAAO,QAAQ;AACtB,YAAI;AAEF,cAAI,IAAI,SAAS,UAAa,IAAI,SAAS,SAAS,OAAO,IAAI,SAAS,YAAY,MAAM,QAAQ,IAAI,IAAI,IAAI;AAC5G,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,0BAA0B,EAAE;AAAA,UACnE;AAEA,gBAAM,UAAmC,EAAE,GAAK,IAAI,QAAQ,CAAC,EAA+B;AAE5F,cAAI,IAAI,MAAM,QAAQ;AACpB,oBAAQ,SAAS,IAAI,KAAK;AAAA,UAC5B;AACA,gBAAM,eAAe,MAAM,oBAAoB,OAAO,OAAc;AACpE,iBAAO,EAAE,QAAQ,KAAK,MAAM,aAAa;AAAA,QAC3C,SAAS,KAAK;AACZ,iBAAO,MAAM,wCAAwC,eAAe,QAAQ,MAAM,MAAS;AAC3F,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,kBAAkB;AAAA,MAChC,SAAS,OAAO,QAAQ;AACtB,YAAI;AACF,gBAAM,WAAW,IAAI,SAAS,CAAC;AAC/B,gBAAM,UAAmC,EAAE,GAAG,SAAS;AAEvD,cAAI,OAAO,SAAS,UAAU,UAAU;AACtC,kBAAM,cAAc,OAAO,SAAS,KAAK;AACzC,gBAAI,CAAC,OAAO,SAAS,WAAW,KAAK,eAAe,KAAK,CAAC,OAAO,UAAU,WAAW,GAAG;AACvF,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,0BAA0B,EAAE;AAAA,YACnE;AACA,oBAAQ,QAAQ;AAAA,UAClB;AAGA,cAAI,IAAI,MAAM,QAAQ;AACpB,oBAAQ,SAAS,IAAI,KAAK;AAAA,UAC5B;AAEA,gBAAM,gBAAgB,MAAM,oBAAoB,KAAK,OAAc;AACnE,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,cAAc,EAAE;AAAA,QAChD,SAAS,KAAK;AACZ,iBAAO,MAAM,uCAAuC,eAAe,QAAQ,MAAM,MAAS;AAC1F,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,kBAAkB;AAAA,MAChC,SAAS,OAAO,QAAQ;AACtB,cAAM,KAAK,IAAI,QAAQ;AACvB,YAAI,CAAC,IAAI;AACP,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,8BAA8B,EAAE;AAAA,QACvE;AACA,YAAI;AACF,gBAAM,eAAe,MAAM,oBAAoB,IAAI,EAAE;AACrD,cAAI,CAAC,cAAc;AACjB,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iBAAiB,EAAE,cAAc,EAAE;AAAA,UAC1E;AACA,cAAI,IAAI,MAAM,UAAU,aAAa,UAAU,aAAa,WAAW,IAAI,KAAK,QAAQ;AACtF,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,8CAA8C,EAAE;AAAA,UACvF;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,aAAa;AAAA,QAC3C,SAAS,KAAK;AACZ,iBAAO,MAAM,2CAA2C,eAAe,QAAQ,MAAM,MAAS;AAC9F,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,kBAAkB;AAAA,MAChC,SAAS,OAAO,QAAQ;AACtB,cAAM,KAAK,IAAI,QAAQ;AACvB,YAAI,CAAC,IAAI;AACP,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,8BAA8B,EAAE;AAAA,QACvE;AAEA,cAAM,UAAU,IAAI;AACpB,cAAM,kBAAkB,gBAAgB,OAAO;AAC/C,YAAI,iBAAiB;AACnB,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,gBAAgB,EAAE;AAAA,QACzD;AAEA,YAAI;AAEF,cAAI,IAAI,MAAM,QAAQ;AACpB,kBAAM,WAAW,MAAM,oBAAoB,IAAI,EAAE;AACjD,gBAAI,CAAC,UAAU;AACb,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iBAAiB,EAAE,cAAc,EAAE;AAAA,YAC1E;AACA,gBAAI,SAAS,UAAU,SAAS,WAAW,IAAI,KAAK,QAAQ;AAC1D,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,8CAA8C,EAAE;AAAA,YACvF;AAAA,UACF;AAEA,gBAAM,eAAe,MAAM,oBAAoB,WAAW,IAAI,OAAuB;AACrF,iBAAO,EAAE,QAAQ,KAAK,MAAM,aAAa;AAAA,QAC3C,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAI,IAAI,SAAS,WAAW,GAAG;AAC7B,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,UAC7C;AACA,iBAAO,MAAM,qDAAqD,eAAe,QAAQ,MAAM,MAAS;AACxG,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,kBAAkB;AAAA,MAChC,SAAS,OAAO,QAAQ;AACtB,cAAM,KAAK,IAAI,QAAQ;AACvB,YAAI,CAAC,IAAI;AACP,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,8BAA8B,EAAE;AAAA,QACvE;AAEA,YAAI;AAEF,cAAI,IAAI,MAAM,QAAQ;AACpB,kBAAM,WAAW,MAAM,oBAAoB,IAAI,EAAE;AACjD,gBAAI,CAAC,UAAU;AACb,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iBAAiB,EAAE,cAAc,EAAE;AAAA,YAC1E;AACA,gBAAI,SAAS,UAAU,SAAS,WAAW,IAAI,KAAK,QAAQ;AAC1D,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,8CAA8C,EAAE;AAAA,YACvF;AAAA,UACF;AAEA,gBAAM,oBAAoB,OAAO,EAAE;AACnC,iBAAO,EAAE,QAAQ,IAAI;AAAA,QACvB,SAAS,KAAK;AACZ,iBAAO,MAAM,8CAA8C,eAAe,QAAQ,MAAM,MAAS;AACjG,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC7bA,IAAM,sBAAsB,oBAAI,IAAY,CAAC,QAAQ,WAAW,CAAC;AAEjE,SAAS,qBAAqB,KAA6B;AACzD,MAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,WAAO;AAAA,EACT;AACA,QAAM,MAAM;AACZ,MAAI,OAAO,IAAI,SAAS,YAAY,CAAC,oBAAoB,IAAI,IAAI,IAAI,GAAG;AACtE,WAAO,+BAA+B,CAAC,GAAG,mBAAmB,EAAE,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,EAC9F;AAGA,QAAM,aAAa,IAAI,SAAS;AAChC,SAAO,uBAAuB,KAAK,EAAE,mBAAmB,WAAW,CAAC;AACtE;AAUO,SAAS,iBACd,WACA,cACA,QACmB;AACnB,SAAO;AAAA;AAAA,IAEL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,YAAY;AACnB,YAAI;AACF,gBAAM,SAAS,MAAM,aAAa,WAAW;AAC7C,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,EAAE;AAAA,QACzC,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,QAAQ,MAAM;AAAA,UAC/B;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,WAAW,WAAW;AAAA,MACpC,SAAS,OAAO,QAAQ;AACtB,cAAM,YAAY,IAAI,QAAQ;AAC9B,YAAI,CAAC,WAAW;AACd,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,kCAAkC,EAAE;AAAA,QAC3E;AAGA,cAAM,OAAQ,IAAI,QAAQ,CAAC;AAC3B,cAAM;AAAA,UACJ,UAAU;AAAA,UACV,SAAS;AAAA,UACT,SAAS;AAAA,QACX,IAAI;AAMJ,YAAI,CAAC,MAAM,QAAQ,WAAW,KAAK,YAAY,WAAW,GAAG;AAC3D,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,6BAA6B,EAAE;AAAA,QACtE;AAEA,mBAAW,OAAO,aAAa;AAC7B,gBAAM,MAAM,qBAAqB,GAAG;AACpC,cAAI,IAAK,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,QACtD;AAGA,cAAM,QAAQ,MAAM,aAAa,UAAU,SAAS;AACpD,YAAI,CAAC,OAAO;AACV,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,UAAU,SAAS,cAAc,EAAE;AAAA,QAC1E;AACA,YAAI,CAAC,MAAM,QAAQ;AACjB,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,UAAU,SAAS,kBAAkB,EAAE;AAAA,QAC9E;AAEA,YAAI;AAEF,gBAAM,eAAe,MAAM,aAAa,oBAAoB,OAAO,WAAW;AAG9E,gBAAM,iBAAiB,aAAa,oBAAoB,OAAO,aAAa,YAAY;AAGxF,gBAAM,eAAe,aAAa;AAAA,YAChC;AAAA,YACA,UAAU,aAAa,OAAO;AAAA,YAC9B;AAAA,UACF;AAIA,gBAAM,gBAAyC,CAAC;AAChD,cAAI,cAAc;AAChB,kBAAM,eAAe,oBAAI,IAAI,CAAC,eAAe,aAAa,MAAM,CAAC;AACjE,uBAAW,OAAO,OAAO,KAAK,YAAY,GAAG;AAC3C,kBAAI,aAAa,IAAI,GAAG,GAAG;AACzB,8BAAc,GAAG,IAAI,aAAa,GAAG;AAAA,cACvC;AAAA,YACF;AAAA,UACF;AACA,gBAAM,gBAAgB,EAAE,GAAG,cAAc,GAAG,cAAc;AAG1D,gBAAM,eAA+B;AAAA,YACnC,GAAG;AAAA,YACH,GAAG,YAAY,IAAI,OAAK,iBAAiB,CAA4B,CAAC;AAAA,UACxE;AAEA,gBAAM,uBAAuB;AAAA,YAC3B,GAAG;AAAA,YACH,eAAe,MAAM,UAAU;AAAA;AAAA;AAAA,YAG/B,sBAAsB,IAAI,OACtB;AAAA,cACE,OAAO;AAAA,gBACL,IAAI,IAAI,KAAK;AAAA,gBACb,MAAM,IAAI,KAAK;AAAA,gBACf,OAAO,IAAI,KAAK;AAAA,gBAChB,aAAa,IAAI,KAAK;AAAA,cACxB;AAAA,cACA,gBACE,OAAO,KAAK,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,cAClE,eACE,OAAO,aAAa,kBAAkB,WAClC,YAAY,gBACZ;AAAA,YACR,IACA;AAAA,UACN;AAGA,gBAAM,aAAa,KAAK,WAAW;AAEnC,cAAI,YAAY;AAEd,gBAAI,CAAC,UAAU,qBAAqB;AAClC,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,0DAA0D,EAAE;AAAA,YACnG;AACA,kBAAM,SAAS,UAAU,oBAAoB,cAAc,oBAAoB;AAC/E,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,QAAQ;AAAA,cACR,kBAAkB;AAAA,cAClB,aAAa;AAAA,cACb,SAAS;AAAA,gBACP,gBAAgB;AAAA,gBAChB,iBAAiB;AAAA,gBACjB,cAAc;AAAA,gBACd,iCAAiC;AAAA,cACnC;AAAA,cACA,QAAQ,uBAAuB,MAAM;AAAA,YACvC;AAAA,UACF;AAGA,gBAAM,SAAS,MAAM,UAAU,cAAc,cAAc,oBAAoB;AAC/E,iBAAO,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,QACrC,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,QAAQ,MAAM;AAAA,UAC/B;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACxMA,IAAM,gBAAgB,oBAAI,IAAY,CAAC,QAAQ,WAAW,CAAC;AAE3D,SAAS,yBAAyB,KAA6B;AAC7D,MAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,WAAO;AAAA,EACT;AACA,QAAM,MAAM;AACZ,MAAI,OAAO,IAAI,SAAS,YAAY,CAAC,cAAc,IAAI,IAAI,IAAI,GAAG;AAChE,WAAO,+BAA+B,CAAC,GAAG,aAAa,EAAE,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,EACxF;AACA,QAAM,aAAa,IAAI,SAAS;AAChC,SAAO,uBAAuB,KAAK,EAAE,mBAAmB,WAAW,CAAC;AACtE;AAEA,SAAS,aAAa,KAAgC;AACpD,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO,CAAC;AACrD,QAAM,MAAM;AACZ,QAAM,MAAwB,CAAC;AAC/B,aAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAClC,QAAI,GAAG,IAAI,IAAI,GAAG;AAAA,EACpB;AACA,SAAO;AACT;AAmBO,SAAS,qBACd,WACA,cACA,eACA,QACmB;AACnB,SAAO;AAAA;AAAA,IAEL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,OAAO,QAAQ;AACtB,YAAI;AACF,gBAAM,UAAU,sBAAsB,IAAI,KAAK;AAI/C,gBAAM,oBAAoB,OAAO,IAAI,OAAO,UAAU,WAAW,IAAI,MAAM,QAAQ;AACnF,gBAAM,QAAQ,oBACV,MAAM,aAAa,UAAU,iBAAiB,IAC9C,MAAM,aAAa,oBAAoB,OAAO;AAClD,cAAI,CAAC,OAAO;AACV,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,MAAM,EAAE,OAAO,MAAM,QAAQ,CAAC,EAAE;AAAA,YAClC;AAAA,UACF;AACA,gBAAM,SAAS,MAAM,aAAa,oBAAoB,OAAO,OAAO;AACpE,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,MAAM;AAAA,cACJ,OAAO;AAAA,gBACL,MAAM,MAAM;AAAA,gBACZ,OAAO,MAAM;AAAA,gBACb,MAAM,MAAM;AAAA,gBACZ,QAAQ,MAAM;AAAA,gBACd,cAAc,MAAM;AAAA,cACtB;AAAA,cACA,QAAQ,OAAO,IAAI,CAAC,MAAM,cAAc,UAAU,CAAC,CAAC;AAAA,cACpD;AAAA,YACF;AAAA,UACF;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO,MAAM,+BAA+B,eAAe,QAAQ,MAAM,MAAS;AAClF,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,OAAO,QAAQ;AACtB,YAAI;AACF,gBAAM,UAAU,sBAAsB,IAAI,KAAK;AAE/C,gBAAM,YAAY,OAAO,IAAI,OAAO,UAAU,WAAW,IAAI,MAAM,QAAQ;AAC3E,cAAI;AACJ,cAAI,WAAW;AACb,kBAAM,QAAQ,MAAM,aAAa,UAAU,SAAS;AACpD,gBAAI,OAAO,OAAQ,cAAa,MAAM;AAAA,UACxC;AACA,gBAAM,SAAS,MAAM,cAAc,iBAAiB,SAAS,UAAU;AACvE,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,MAAM,EAAE,QAAQ,OAAO,IAAI,CAAC,MAAM,cAAc,UAAU,CAAC,CAAC,EAAE;AAAA,UAChE;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO,MAAM,sCAAsC,eAAe,QAAQ,MAAM,MAAS;AACzF,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,OAAO,QAAQ;AACtB,cAAM,OAAQ,IAAI,QAAQ,CAAC;AAC3B,cAAM;AAAA,UACJ,UAAU;AAAA,UACV,SAAS;AAAA,UACT,SAAS;AAAA,UACT,OAAO;AAAA,UACP,OAAO;AAAA,QACT,IAAI;AAQJ,YAAI,CAAC,MAAM,QAAQ,WAAW,KAAK,YAAY,WAAW,GAAG;AAC3D,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,6BAA6B,EAAE;AAAA,QACtE;AACA,mBAAW,OAAO,aAAa;AAC7B,gBAAM,MAAM,yBAAyB,GAAG;AACxC,cAAI,IAAK,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,QACtD;AAEA,cAAM,UAAU,aAAa,UAAU;AAGvC,cAAM,QAAQ,oBACV,MAAM,aAAa,UAAU,iBAAiB,IAC9C,MAAM,aAAa,oBAAoB,OAAO;AAElD,YAAI,CAAC,OAAO;AACV,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,MAAM,EAAE,OAAO,2GAAsG;AAAA,UACvH;AAAA,QACF;AACA,YAAI,MAAM,WAAW,OAAO;AAC1B,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,UAAU,MAAM,IAAI,kBAAkB,EAAE;AAAA,QAC/E;AAEA,YAAI;AAIF,cAAI,eAAe,MAAM,aAAa,oBAAoB,OAAO,OAAO;AACxE,cAAI,mBAAmB;AACrB,2BAAe,aAAa,OAAO,CAAC,MAAM,EAAE,SAAS,iBAAiB;AACtE,gBAAI,aAAa,WAAW,GAAG;AAC7B,oBAAM,SAAS,MAAM,cAAc,UAAU,iBAAiB;AAC9D,kBAAI,UAAU,OAAO,WAAW,MAAO,gBAAe,CAAC,MAAM;AAAA,YAC/D;AAAA,UACF;AAEA,gBAAM,iBAAiB,aAAa,oBAAoB,OAAO,SAAS,YAAY;AACpF,gBAAM,eAAe,aAAa;AAAA,YAChC;AAAA,YACA,UAAU,aAAa,OAAO;AAAA,YAC9B;AAAA,UACF;AAGA,gBAAM,gBAAyC,CAAC;AAChD,cAAI,cAAc;AAChB,kBAAM,eAAe,oBAAI,IAAI,CAAC,eAAe,aAAa,MAAM,CAAC;AACjE,uBAAW,OAAO,OAAO,KAAK,YAAY,GAAG;AAC3C,kBAAI,aAAa,IAAI,GAAG,EAAG,eAAc,GAAG,IAAI,aAAa,GAAG;AAAA,YAClE;AAAA,UACF;AACA,gBAAM,gBAAgB,EAAE,GAAG,cAAc,GAAG,cAAc;AAE1D,gBAAM,eAA+B;AAAA,YACnC,GAAG;AAAA,YACH,GAAG,YAAY,IAAI,CAAC,MAAM,iBAAiB,CAA4B,CAAC;AAAA,UAC1E;AAEA,gBAAM,uBAAuB;AAAA,YAC3B,GAAG;AAAA,YACH,eAAe,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,YAK/B,sBAAsB,IAAI,OACtB;AAAA,cACE,OAAO;AAAA,gBACL,IAAI,IAAI,KAAK;AAAA,gBACb,MAAM,IAAI,KAAK;AAAA,gBACf,OAAO,IAAI,KAAK;AAAA,gBAChB,aAAa,IAAI,KAAK;AAAA,cACxB;AAAA,cACA,gBACE,OAAO,KAAK,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,cAClE,eACE,OAAO,QAAQ,kBAAkB,WAAW,QAAQ,gBAAgB;AAAA,YACxE,IACA;AAAA,UACN;AAEA,gBAAM,aAAa,KAAK,WAAW;AAEnC,cAAI,YAAY;AACd,gBAAI,CAAC,UAAU,qBAAqB;AAClC,qBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,0DAA0D,EAAE;AAAA,YACnG;AACA,kBAAM,SAAS,UAAU,oBAAoB,cAAc,oBAAoB;AAC/E,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,QAAQ;AAAA,cACR,kBAAkB;AAAA,cAClB,aAAa;AAAA,cACb,SAAS;AAAA,gBACP,gBAAgB;AAAA,gBAChB,iBAAiB;AAAA,gBACjB,cAAc;AAAA,gBACd,iCAAiC;AAAA,gBACjC,uBAAuB,MAAM;AAAA,gBAC7B,wBAAwB,aAAa,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAAA,cAClE;AAAA,cACA,QAAQ,uBAAuB,MAAM;AAAA,YACvC;AAAA,UACF;AAEA,gBAAM,SAAS,MAAM,UAAU,cAAc,cAAc,oBAAoB;AAE/E,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,MAAM;AAAA,cACJ,GAAK,UAAqB,CAAC;AAAA,cAC3B,QAAQ,MAAM;AAAA,cACd,SAAS,aAAa,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,YACzC;AAAA,UACF;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,QAAQ,MAAM;AAAA,UAC/B;AAIA,gBAAM,cAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACnE,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,MAAM,EAAE,OAAO,6BAA6B,QAAQ,YAAY;AAAA,UAClE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAUA,SAAS,sBAAsB,OAA6D;AAC1F,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,MAAwB,CAAC;AAC/B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,SAAS,KAAM;AACnB,QAAI,GAAG,IAAI;AAAA,EACb;AACA,SAAO;AACT;;;AC3SA,SAAS,mBAAmB,QAAqB;AAC/C,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,WAAW,SAAU,QAAO;AACvC,MAAI,OAAO,WAAW,YAAY,WAAW,QAAQ;AACnD,WAAO,OAAO,OAAO,SAAS,EAAE;AAAA,EAClC;AACA,SAAO,KAAK,UAAU,MAAM;AAC9B;AAUO,SAAS,gBACd,WACA,QACmB;AACnB,SAAO;AAAA;AAAA,IAEL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,UAAU;AAAA,MACxB,SAAS,YAAY;AACnB,YAAI;AACF,gBAAM,QAAQ,UAAU,aAAa,OAAO;AAC5C,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,MAAM;AAAA,cACJ,OAAO,MAAM,IAAI,QAAM;AAAA,gBACrB,MAAM,EAAE;AAAA,gBACR,aAAa,EAAE;AAAA,gBACf,UAAW,EAAU;AAAA,cACvB,EAAE;AAAA,YACJ;AAAA,UACF;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,QAAQ,MAAM;AAAA,UAC/B;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,YAAY,YAAY;AAAA,MACtC,SAAS,OAAO,QAAQ;AACtB,cAAM,WAAW,IAAI,QAAQ;AAC7B,YAAI,CAAC,UAAU;AACb,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iCAAiC,EAAE;AAAA,QAC1E;AAGA,cAAM,OAAQ,IAAI,QAAQ,CAAC;AAC3B,cAAM,EAAE,WAAW,IAAI;AAIvB,YAAI,CAAC,cAAc,OAAO,eAAe,UAAU;AACjD,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,gCAAgC,EAAE;AAAA,QACzE;AAEA,YAAI;AAEF,cAAI,CAAC,UAAU,aAAa,IAAI,QAAQ,GAAG;AACzC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,SAAS,QAAQ,cAAc,EAAE;AAAA,UACxE;AAGA,gBAAM,YAAY,KAAK,IAAI;AAE3B,gBAAM,eAAe;AAAA,YACnB,MAAM;AAAA,YACN,YAAY,cAAc,KAAK,IAAI,CAAC;AAAA,YACpC;AAAA,YACA,OAAO;AAAA,UACT;AAEA,gBAAM,SAAS,MAAM,UAAU,aAAa,QAAQ,YAAY;AAChE,gBAAM,WAAW,KAAK,IAAI,IAAI;AAG9B,cAAI,OAAO,SAAS;AAClB,kBAAM,WAAW,mBAAmB,OAAO,MAAM;AACjD,mBAAO;AAAA,cACL,oCAAoC,QAAQ;AAAA,cAC5C,IAAI,MAAM,QAAQ;AAAA,YACpB;AACA,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,MAAM;AAAA,gBACJ,OAAO;AAAA,gBACP;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAEA,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,MAAM;AAAA,cACJ,QAAQ,mBAAmB,OAAO,MAAM;AAAA,cACxC;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,QAAQ,MAAM;AAAA,UAC/B;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,4BAA4B,EAAE;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACzHO,SAAS,yBACd,WACA,QACmB;AAGnB,QAAM,YACJ,OAAO,UAAU,uBAAuB,cACxC,OAAO,UAAU,yBAAyB,cAC1C,OAAO,UAAU,wBAAwB;AAE3C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,OAAO;AAAA,IACrB,QAAQ;AAAA,IACR,MAAM,EAAE,OAAO,4DAA4D;AAAA,EAC7E;AAEA,SAAO;AAAA;AAAA,IAEL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,OAAO,QAAQ;AACtB,YAAI,CAAC,UAAW,QAAO,QAAQ;AAC/B,YAAI;AACF,gBAAM,QAAS,IAAI,SAAS,CAAC;AAC7B,gBAAM,SAAS,OAAO,MAAM,WAAW,WAAY,MAAM,SAAiB;AAC1E,gBAAM,iBACJ,OAAO,MAAM,mBAAmB,WAAW,MAAM,iBAAiB;AACpE,gBAAM,WAAW,MAAM;AACvB,gBAAM,QAAQ,OAAO,aAAa,WAAW,OAAO,QAAQ,IAAI;AAChE,gBAAM,OAAO,MAAM,UAAU,mBAAoB;AAAA,YAC/C;AAAA,YACA;AAAA,YACA,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AAAA,UAC1C,CAAC;AACD,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,MAAM,OAAO,KAAK,OAAO,EAAE;AAAA,QAClE,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,QAAQ,MAAM;AAAA,UAC/B;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iCAAiC,EAAE;AAAA,QAC1E;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,SAAS;AAAA,MACvB,SAAS,OAAO,QAAQ;AACtB,YAAI,CAAC,UAAW,QAAO,QAAQ;AAC/B,cAAM,KAAK,IAAI,QAAQ;AACvB,YAAI,CAAC,GAAI,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iBAAiB,EAAE;AACjE,YAAI;AACF,gBAAM,OAAO,MAAM,UAAU,mBAAoB,CAAC,CAAC;AACnD,gBAAM,QAAQ,KAAK,KAAK,OAAK,EAAE,OAAO,EAAE;AACxC,cAAI,CAAC,MAAO,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,kBAAkB,EAAE,aAAa,EAAE;AACpF,iBAAO,EAAE,QAAQ,KAAK,MAAM,MAAM;AAAA,QACpC,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,QAAQ,MAAM;AAAA,UAC/B;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,gCAAgC,EAAE;AAAA,QACzE;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,YAAY;AAAA,MAC1B,SAAS,OAAO,QAAQ;AACtB,YAAI,CAAC,UAAW,QAAO,QAAQ;AAC/B,cAAM,KAAK,IAAI,QAAQ;AACvB,YAAI,CAAC,GAAI,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iBAAiB,EAAE;AACjE,cAAM,UAAU,IAAI,MAAM,MAAM;AAChC,YAAI;AACF,gBAAM,UAAU,MAAM,UAAU,qBAAsB,IAAI,OAAO;AAEjE,gBAAM,aAAa,QAAQ,WAAW,aAAa,MAAM;AACzD,iBAAO,EAAE,QAAQ,YAAY,MAAM,QAAQ;AAAA,QAC7C,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,iBAAO,MAAM,iDAAiD,eAAe,QAAQ,MAAM,MAAS;AAEpG,cAAI,aAAa,KAAK,GAAG,EAAG,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AACvE,cAAI,qCAAqC,KAAK,GAAG,GAAG;AAClD,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,UAC7C;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,aAAa,CAAC,YAAY;AAAA,MAC1B,SAAS,OAAO,QAAQ;AACtB,YAAI,CAAC,UAAW,QAAO,QAAQ;AAC/B,cAAM,KAAK,IAAI,QAAQ;AACvB,YAAI,CAAC,GAAI,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,iBAAiB,EAAE;AACjE,cAAM,UAAU,IAAI,MAAM,MAAM;AAChC,cAAM,OAAQ,IAAI,QAAQ,CAAC;AAC3B,cAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAC/D,YAAI;AACF,gBAAM,UAAU,oBAAqB,IAAI,SAAS,MAAM;AACxD,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,QAAQ,YAAY,GAAG,EAAE;AAAA,QACzD,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,iBAAO,MAAM,gDAAgD,eAAe,QAAQ,MAAM,MAAS;AACnG,cAAI,aAAa,KAAK,GAAG,EAAG,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AACvE,cAAI,uBAAuB,KAAK,GAAG,GAAG;AACpC,mBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,UAC7C;AACA,iBAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC9JA,IAAAC,sBAA2B;AAW3B,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AAyBxB,IAAM,qBAAqB;AAAA,EACzB,EAAE,OAAO,cAAc,OAAO,MAAe;AAAA,EAC7C,EAAE,OAAO,MAAM,OAAO,MAAe;AACvC;AAGA,IAAM,gBAAgB;AAAA,EACpB,EAAE,OAAO,cAAc,OAAO,MAAe;AAAA,EAC7C,EAAE,OAAO,MAAM,OAAO,MAAe;AACvC;AAYO,IAAM,8BAAN,MAAoE;AAAA,EAGzE,YAAY,QAAqB;AAC/B,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,OAAO,UAKT,CAAC,GAA4B;AAC/B,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,KAAK,YAAQ,gCAAW,CAAC;AAE/B,UAAM,SAAS;AAAA,MACb;AAAA,MACA,OAAO,QAAQ,SAAS;AAAA,MACxB,UAAU,QAAQ,WAAW;AAAA,MAC7B,SAAS,QAAQ,UAAU;AAAA,MAC3B,UAAU,QAAQ,WAAW,KAAK,UAAU,QAAQ,QAAQ,IAAI;AAAA,MAChE,YAAY;AAAA,MACZ,YAAY;AAAA,IACd;AAEA,UAAM,KAAK,OAAO,OAAO,sBAAsB,MAAM;AAErD,WAAO;AAAA,MACL;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,SAAS,QAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,UAAU,CAAC;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,MACX,UAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,gBAAwD;AAChE,UAAM,MAAgC,MAAM,KAAK,OAAO,QAAQ,sBAAsB;AAAA,MACpF,OAAO,EAAE,IAAI,eAAe;AAAA,IAC9B,CAAC;AAED,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,WAA2B,MAAM,KAAK,OAAO,KAAK,iBAAiB;AAAA,MACvE,OAAO,EAAE,iBAAiB,eAAe;AAAA,MACzC,SAAS;AAAA,IACX,CAAC;AAED,WAAO,KAAK,eAAe,KAAK,QAAQ;AAAA,EAC1C;AAAA,EAEA,MAAM,KAAK,UAKP,CAAC,GAA8B;AACjC,UAAM,QAAiC,CAAC;AACxC,QAAI,QAAQ,OAAQ,OAAM,UAAU,QAAQ;AAC5C,QAAI,QAAQ,QAAS,OAAM,WAAW,QAAQ;AAI9C,QAAI,QAAQ,QAAQ;AAClB,YAAM,YAAY,MAAM,KAAK,OAAO,QAAQ,sBAAsB;AAAA,QAChE,OAAO,EAAE,IAAI,QAAQ,OAAO;AAAA,QAC5B,QAAQ,CAAC,cAAc,IAAI;AAAA,MAC7B,CAAC;AACD,UAAI,WAAW;AACb,cAAM,MAAM;AAAA,UACV,EAAE,YAAY,EAAE,KAAK,UAAU,WAAW,EAAE;AAAA,UAC5C,EAAE,YAAY,UAAU,YAAY,IAAI,EAAE,KAAK,UAAU,GAAG,EAAE;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAA4B,MAAM,KAAK,OAAO,KAAK,sBAAsB;AAAA,MAC7E,OAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AAAA,MAC/C,SAAS;AAAA,MACT,OAAO,QAAQ,SAAS,QAAQ,QAAQ,IAAI,QAAQ,QAAQ;AAAA,IAC9D,CAAC;AAID,UAAM,gBAAkC,MAAM,QAAQ;AAAA,MACpD,KAAK,IAAI,OAAO,QAAQ;AACtB,cAAM,WAA2B,MAAM,KAAK,OAAO,KAAK,iBAAiB;AAAA,UACvE,OAAO,EAAE,iBAAiB,IAAI,GAAG;AAAA,UACjC,SAAS;AAAA,QACX,CAAC;AACD,eAAO,KAAK,eAAe,KAAK,QAAQ;AAAA,MAC1C,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,gBAAwB,SAAgD;AAEvF,UAAM,MAAgC,MAAM,KAAK,OAAO,QAAQ,sBAAsB;AAAA,MACpF,OAAO,EAAE,IAAI,eAAe;AAAA,IAC9B,CAAC;AACD,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,iBAAiB,cAAc,aAAa;AAAA,IAC9D;AAEA,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,QAAQ,WAAO,gCAAW,CAAC;AAGjC,QAAI;AACJ,QAAI,gBAA+B;AACnC,QAAI,aAA4B;AAEhC,QAAI,QAAQ,SAAS,YAAY,QAAQ,SAAS,QAAQ;AACxD,mBAAa,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAK,UAAU,QAAQ,OAAO;AAAA,IACrG,WAAW,QAAQ,SAAS,aAAa;AACvC,UAAI,OAAO,QAAQ,YAAY,UAAU;AACvC,qBAAa,QAAQ;AAAA,MACvB,OAAO;AACL,cAAM,QAAQ,QAAQ;AACtB,cAAM,YAAY,MAAM,OAAO,CAAC,MAA2C,EAAE,SAAS,MAAM,EAAE,IAAI,OAAK,EAAE,IAAI;AAC7G,cAAM,YAAY,MAAM,OAAO,OAAK,EAAE,SAAS,WAAW;AAC1D,qBAAa,UAAU,KAAK,EAAE;AAC9B,YAAI,UAAU,SAAS,EAAG,iBAAgB,KAAK,UAAU,SAAS;AAAA,MACpE;AAAA,IACF,WAAW,QAAQ,SAAS,QAAQ;AAClC,mBAAa,KAAK,UAAU,QAAQ,OAAO;AAC3C,YAAM,cAAc,MAAM,QAAQ,QAAQ,OAAO,IAAI,QAAQ,QAAQ,CAAC,IAAI;AAC1E,UAAI,eAAe,gBAAgB,YAAa,cAAa,YAAY;AAAA,IAC3E,OAAO;AACL,mBAAa;AAAA,IACf;AAGA,UAAM,KAAK,OAAO,OAAO,iBAAiB;AAAA,MACxC,IAAI;AAAA,MACJ,iBAAiB;AAAA,MACjB,MAAM,QAAQ;AAAA,MACd,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,YAAY;AAAA,IACd,CAAC;AAGD,UAAM,KAAK,OAAO,OAAO,sBAAsB,EAAE,IAAI,gBAAgB,YAAY,IAAI,GAAG;AAAA,MACtF,OAAO,EAAE,IAAI,eAAe;AAAA,IAC9B,CAAC;AAGD,WAAQ,MAAM,KAAK,IAAI,cAAc;AAAA,EACvC;AAAA,EAEA,MAAM,OAAO,gBAAuC;AAElD,UAAM,KAAK,OAAO,OAAO,iBAAiB;AAAA,MACxC,OAAO,EAAE,iBAAiB,eAAe;AAAA,MACzC,OAAO;AAAA,IACT,CAAC;AAGD,UAAM,KAAK,OAAO,OAAO,sBAAsB;AAAA,MAC7C,OAAO,EAAE,IAAI,eAAe;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,UAAa,OAAsB,UAA6B;AACtE,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI;AACF,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,KAAwB,aAA6C;AAC1F,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,OAAO,IAAI,SAAS;AAAA,MACpB,SAAS,IAAI,YAAY;AAAA,MACzB,QAAQ,IAAI,WAAW;AAAA,MACvB,UAAU,YAAY,IAAI,OAAK,KAAK,UAAU,CAAC,CAAC;AAAA,MAChD,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,UAAU,KAAK,UAAmC,IAAI,QAAQ;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,KAAiC;AACjD,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK;AACH,eAAO,EAAE,MAAM,UAAU,SAAS,IAAI,QAAQ;AAAA,MAChD,KAAK;AACH,eAAO,EAAE,MAAM,QAAQ,SAAS,IAAI,QAAQ;AAAA,MAC9C,KAAK,aAAa;AAChB,cAAM,YAAY,KAAK,UAA0B,IAAI,UAAU;AAC/D,YAAI,aAAa,UAAU,SAAS,GAAG;AACrC,gBAAM,UAAgE,CAAC;AACvE,cAAI,IAAI,QAAS,SAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,IAAI,QAAQ,CAAC;AACjE,kBAAQ,KAAK,GAAG,SAAS;AACzB,iBAAO,EAAE,MAAM,aAAa,QAAQ;AAAA,QACtC;AACA,eAAO,EAAE,MAAM,aAAa,SAAS,IAAI,QAAQ;AAAA,MACnD;AAAA,MACA,KAAK,QAAQ;AACX,cAAM,cAAc,KAAK,UAA4B,IAAI,OAAO;AAChE,YAAI,eAAe,YAAY,SAAS,KAAK,YAAY,CAAC,GAAG,SAAS,eAAe;AACnF,iBAAO,EAAE,MAAM,QAAQ,SAAS,YAAY;AAAA,QAC9C;AAEA,eAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS,CAAC;AAAA,YACR,MAAM;AAAA,YACN,YAAY,IAAI,gBAAgB;AAAA,YAChC,UAAU;AAAA,YACV,QAAQ,EAAE,MAAM,QAAiB,OAAO,IAAI,QAAQ;AAAA,UACtD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA;AACE,eAAO,EAAE,MAAM,QAAQ,SAAS,IAAI,QAAQ;AAAA,IAChD;AAAA,EACF;AACF;;;AC1SA,kBAAoC;AAW7B,IAAM,uBAAuB,yBAAa,OAAO;AAAA,EACtD,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EAEb,QAAQ;AAAA,IACN,IAAI,kBAAM,KAAK;AAAA,MACb,OAAO;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,OAAO,kBAAM,KAAK;AAAA,MAChB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,UAAU,kBAAM,KAAK;AAAA,MACnB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,SAAS,kBAAM,OAAO,YAAY;AAAA,MAChC,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,UAAU,kBAAM,SAAS;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,kBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,YAAY,kBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,SAAS;AAAA,IACP,EAAE,QAAQ,CAAC,SAAS,EAAE;AAAA,IACtB,EAAE,QAAQ,CAAC,UAAU,EAAE;AAAA,IACvB,EAAE,QAAQ,CAAC,YAAY,EAAE;AAAA,EAC3B;AAAA,EAEA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,CAAC,OAAO,QAAQ,UAAU,UAAU,QAAQ;AAAA,IACxD,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AACF,CAAC;;;ACjFD,IAAAC,eAAoC;AAU7B,IAAM,kBAAkB,0BAAa,OAAO;AAAA,EACjD,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EAEb,QAAQ;AAAA,IACN,IAAI,mBAAM,KAAK;AAAA,MACb,OAAO;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,iBAAiB,mBAAM,OAAO,oBAAoB;AAAA,MAChD,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,MAAM,mBAAM,OAAO;AAAA,MACjB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,SAAS;AAAA,QACP,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,QACnC,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,QAC/B,EAAE,OAAO,aAAa,OAAO,YAAY;AAAA,QACzC,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,IAED,SAAS,mBAAM,SAAS;AAAA,MACtB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,mBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,cAAc,mBAAM,KAAK;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,mBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,SAAS;AAAA,IACP,EAAE,QAAQ,CAAC,iBAAiB,EAAE;AAAA,IAC9B,EAAE,QAAQ,CAAC,mBAAmB,YAAY,EAAE;AAAA,EAC9C;AAAA,EAEA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,CAAC,OAAO,QAAQ,QAAQ;AAAA,IACpC,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AACF,CAAC;;;AClFD,IAAAC,eAAoC;AAc7B,IAAM,gBAAgB,0BAAa,OAAO;AAAA,EAC/C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EAEb,QAAQ;AAAA,IACN,IAAI,mBAAM,KAAK;AAAA,MACb,OAAO;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,iBAAiB,mBAAM,OAAO,oBAAoB;AAAA,MAChD,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,UAAU,mBAAM,KAAK;AAAA,MACnB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,mBAAM,OAAO;AAAA,MACtB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,SAAS;AAAA,QACP,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,QAC/B,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,QACvC,EAAE,OAAO,eAAe,OAAO,cAAc;AAAA,QAC7C,EAAE,OAAO,mBAAmB,OAAO,kBAAkB;AAAA,QACrD,EAAE,OAAO,mBAAmB,OAAO,kBAAkB;AAAA,QACrD,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,MACnC;AAAA,IACF,CAAC;AAAA,IAED,OAAO,mBAAM,KAAK;AAAA,MAChB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,SAAS,mBAAM,KAAK;AAAA,MAClB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,eAAe,mBAAM,OAAO;AAAA,MAC1B,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,IAED,mBAAmB,mBAAM,OAAO;AAAA,MAC9B,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,IAED,cAAc,mBAAM,OAAO;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,IAED,YAAY,mBAAM,OAAO;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,aAAa,mBAAM,OAAO;AAAA,MACxB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,mBAAM,OAAO;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,UAAU,mBAAM,KAAK;AAAA,MACnB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc;AAAA,IAChB,CAAC;AAAA,IAED,YAAY,mBAAM,OAAO;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,aAAa;AAAA,IACf,CAAC;AAAA,IAED,QAAQ,mBAAM,OAAO;AAAA,MACnB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,SAAS;AAAA,QACP,EAAE,OAAO,WAAW,OAAO,UAAU;AAAA,QACrC,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,MACnC;AAAA,IACF,CAAC;AAAA,IAED,OAAO,mBAAM,SAAS;AAAA,MACpB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,UAAU,mBAAM,SAAS;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,mBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,SAAS;AAAA,IACP,EAAE,QAAQ,CAAC,iBAAiB,EAAE;AAAA,IAC9B,EAAE,QAAQ,CAAC,UAAU,EAAE;AAAA,IACvB,EAAE,QAAQ,CAAC,OAAO,EAAE;AAAA,IACpB,EAAE,QAAQ,CAAC,QAAQ,EAAE;AAAA,IACrB,EAAE,QAAQ,CAAC,YAAY,EAAE;AAAA,EAC3B;AAAA,EAEA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,CAAC,OAAO,MAAM;AAAA,IAC1B,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AACF,CAAC;;;ACpKD,IAAAC,eAAoC;AAoB7B,IAAM,wBAAwB,0BAAa,OAAO;AAAA,EACvD,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EAEb,QAAQ;AAAA,IACN,IAAI,mBAAM,KAAK;AAAA,MACb,OAAO;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,iBAAiB,mBAAM,OAAO,oBAAoB;AAAA,MAChD,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,mBAAM,OAAO,eAAe;AAAA,MACtC,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,aAAa,mBAAM,KAAK;AAAA,MACtB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,aAAa,mBAAM,KAAK;AAAA,MACtB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,WAAW,mBAAM,KAAK;AAAA,MACpB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,mBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,QAAQ,mBAAM,OAAO;AAAA,MACnB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,SAAS;AAAA,QACP,EAAE,OAAO,oBAAoB,OAAO,UAAU;AAAA,QAC9C,EAAE,OAAO,qBAAqB,OAAO,WAAW;AAAA,QAChD,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,QACvC,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,QACnC,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,MACzC;AAAA,IACF,CAAC;AAAA,IAED,QAAQ,mBAAM,SAAS;AAAA,MACrB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,OAAO,mBAAM,SAAS;AAAA,MACpB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,kBAAkB,mBAAM,SAAS;AAAA,MAC/B,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,IAED,aAAa,mBAAM,KAAK;AAAA,MACtB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,YAAY,mBAAM,KAAK;AAAA,MACrB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,WAAW;AAAA,MACX,aAAa;AAAA,IACf,CAAC;AAAA,IAED,aAAa,mBAAM,SAAS;AAAA,MAC1B,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,YAAY,mBAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,SAAS;AAAA,IACP,EAAE,QAAQ,CAAC,QAAQ,EAAE;AAAA,IACrB,EAAE,QAAQ,CAAC,iBAAiB,EAAE;AAAA,IAC9B,EAAE,QAAQ,CAAC,aAAa,EAAE;AAAA,IAC1B,EAAE,QAAQ,CAAC,aAAa,EAAE;AAAA,EAC5B;AAAA,EAEA,SAAS;AAAA,IACP;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW,CAAC,aAAa,eAAe;AAAA,MACxC,SAAS;AAAA,MACT,aAAa;AAAA,MACb,gBAAgB;AAAA;AAAA;AAAA,MAGhB,WAAW;AAAA,IACb;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW,CAAC,aAAa,eAAe;AAAA,MACxC,SAAS;AAAA,MACT,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAEA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,CAAC,OAAO,MAAM;AAAA,IAC1B,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AACF,CAAC;;;ACjLD,kBAA2B;AAkBpB,IAAM,kBAAc,wBAAW;AAAA,EACpC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM,EAAE,UAAU,UAAU,QAAQ,YAAY;AAAA,IAChD,SAAS;AAAA,MACP,EAAE,OAAO,cAAc,OAAO,OAAO;AAAA,MACrC,EAAE,OAAO,YAAY;AAAA,MACrB,EAAE,OAAO,QAAQ;AAAA,MACjB,EAAE,OAAO,YAAY,OAAO,QAAQ;AAAA,MACpC,EAAE,OAAO,cAAc,OAAO,eAAe;AAAA,MAC7C,EAAE,OAAO,gBAAgB,OAAO,SAAS;AAAA,MACzC,EAAE,OAAO,cAAc,OAAO,OAAO;AAAA,MACrC,EAAE,OAAO,SAAS;AAAA,IACpB;AAAA,IACA,MAAM,CAAC,EAAE,OAAO,cAAc,OAAO,OAAO,CAAC;AAAA,IAC7C,YAAY,EAAE,UAAU,GAAG;AAAA,IAC3B,kBAAkB,CAAC,mBAAmB,YAAY,SAAS,OAAO;AAAA,IAClE,kBAAkB,CAAC,aAAa,SAAS,QAAQ;AAAA,EACnD;AAAA,EACA,WAAW;AAAA,IACT,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM,EAAE,UAAU,UAAU,QAAQ,YAAY;AAAA,MAChD,SAAS;AAAA,QACP,EAAE,OAAO,cAAc,OAAO,OAAO;AAAA,QACrC,EAAE,OAAO,YAAY;AAAA,QACrB,EAAE,OAAO,QAAQ;AAAA,QACjB,EAAE,OAAO,cAAc,OAAO,eAAe;AAAA,QAC7C,EAAE,OAAO,QAAQ;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,OAAO,UAAU,UAAU,KAAK,OAAO,QAAQ;AAAA,MACnD;AAAA,MACA,MAAM,CAAC,EAAE,OAAO,cAAc,OAAO,OAAO,CAAC;AAAA,IAC/C;AAAA,IACA,UAAU;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM,EAAE,UAAU,UAAU,QAAQ,YAAY;AAAA,MAChD,SAAS;AAAA,QACP,EAAE,OAAO,QAAQ;AAAA,QACjB,EAAE,OAAO,YAAY;AAAA,QACrB,EAAE,OAAO,cAAc,OAAO,eAAe;AAAA,QAC7C,EAAE,OAAO,gBAAgB,OAAO,SAAS;AAAA,QACzC,EAAE,OAAO,cAAc,OAAO,OAAO;AAAA,QACrC,EAAE,OAAO,SAAS;AAAA,QAClB,EAAE,OAAO,cAAc,OAAO,OAAO;AAAA,MACvC;AAAA,MACA,UAAU,EAAE,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,EAAE;AAAA,MACzC,MAAM,CAAC,EAAE,OAAO,cAAc,OAAO,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF;AACF,CAAC;;;ACvED,IAAAC,eAA2B;AAmCpB,IAAM,0BAAsB,yBAAW;AAAA,EAC5C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM,EAAE,UAAU,UAAU,QAAQ,qBAAqB;AAAA,IACzD,SAAS;AAAA,MACP,EAAE,OAAO,eAAe,OAAO,YAAY,MAAM,qBAAqB,OAAO,IAAI;AAAA,MACjF,EAAE,OAAO,UAAU,OAAO,IAAI;AAAA,MAC9B,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,MACpD,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,MACpD,EAAE,OAAO,eAAe,OAAO,eAAe,OAAO,IAAI;AAAA,MACzD,EAAE,OAAO,cAAc,OAAO,cAAc,OAAO,IAAI;AAAA,MACvD,EAAE,OAAO,cAAc,OAAO,WAAW,MAAM,qBAAqB,OAAO,IAAI;AAAA,IACjF;AAAA,IACA,MAAM,CAAC,EAAE,OAAO,eAAe,OAAO,OAAO,CAAC;AAAA,IAC9C,YAAY,EAAE,UAAU,GAAG;AAAA,IAC3B,kBAAkB,CAAC,eAAe,eAAe,aAAa,aAAa;AAAA,IAC3E,kBAAkB,CAAC,UAAU,eAAe,aAAa;AAAA,IACzD,YAAY,CAAC,0BAA0B,uBAAuB;AAAA;AAAA,IAE9D,YAAY,EAAE,MAAM,UAAU,MAAM,UAAU,OAAO,QAAQ;AAAA,IAC7D,UAAU;AAAA,MACR,OAAO;AAAA,MACP,SAAS;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,QACV,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM,EAAE,UAAU,UAAU,QAAQ,qBAAqB;AAAA,IACzD,UAAU;AAAA,MACR;AAAA,QACE,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,UACN,EAAE,OAAO,UAAU,UAAU,KAAK;AAAA,UAClC,EAAE,OAAO,eAAe,UAAU,MAAM,QAAQ,oBAAoB;AAAA,UACpE,EAAE,OAAO,eAAe,OAAO,iBAAiB,UAAU,KAAK;AAAA,UAC/D,EAAE,OAAO,eAAe,OAAO,UAAU,UAAU,KAAK;AAAA,UACxD,EAAE,OAAO,aAAa,OAAO,uBAAuB,UAAU,MAAM,SAAS,EAAE;AAAA,UAC/E,EAAE,OAAO,eAAe,OAAO,0BAA0B,UAAU,MAAM,SAAS,EAAE;AAAA,QACtF;AAAA,MACF;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,aAAa;AAAA,QACb,SAAS;AAAA,QACT,QAAQ;AAAA,UACN;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,aAAa;AAAA,QACb,WAAW;AAAA,QACX,SAAS;AAAA,QACT,QAAQ;AAAA;AAAA;AAAA;AAAA,UAIN,EAAE,OAAO,mBAAmB,OAAO,gBAAgB,UAAU,KAAK;AAAA,UAClE,EAAE,OAAO,cAAc,OAAO,qBAAqB,UAAU,KAAK;AAAA,QACpE;AAAA,MACF;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,aAAa;AAAA;AAAA;AAAA,QAGb,WAAW;AAAA,QACX,SAAS;AAAA,QACT,QAAQ;AAAA,UACN,EAAE,OAAO,cAAc,OAAO,cAAc,UAAU,KAAK;AAAA,UAC3D,EAAE,OAAO,cAAc,OAAO,WAAW,UAAU,MAAM,QAAQ,oBAAoB;AAAA,UACrF;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,UAAU;AAAA,YACV,SAAS;AAAA,YACT,WAAW;AAAA,UACb;AAAA,UACA;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,WAAW;AAAA,UACb;AAAA,UACA;AAAA,YACE,OAAO;AAAA,YACP,OAAO;AAAA,YACP,UAAU;AAAA,YACV,SAAS;AAAA,YACT,WAAW;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,WAAW;AAAA,IACT,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,MAAM,EAAE,UAAU,UAAU,QAAQ,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,MAKzD,UAAU;AAAA,QACR;AAAA,UACE,OAAO;AAAA,UACP,SAAS;AAAA,UACT,QAAQ;AAAA,YACN,EAAE,OAAO,UAAU,UAAU,KAAK;AAAA,YAClC,EAAE,OAAO,eAAe,UAAU,MAAM,QAAQ,oBAAoB;AAAA,YACpE,EAAE,OAAO,eAAe,OAAO,iBAAiB,UAAU,KAAK;AAAA,YAC/D,EAAE,OAAO,eAAe,OAAO,UAAU,UAAU,KAAK;AAAA,YACxD,EAAE,OAAO,aAAa,OAAO,uBAAuB,UAAU,MAAM,SAAS,EAAE;AAAA,YAC/E,EAAE,OAAO,eAAe,OAAO,0BAA0B,UAAU,MAAM,SAAS,EAAE;AAAA,UACtF;AAAA,QACF;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,SAAS;AAAA,UACT,QAAQ;AAAA,YACN,EAAE,OAAO,cAAc,OAAO,0BAA0B,UAAU,MAAM,QAAQ,OAAO;AAAA,UACzF;AAAA,QACF;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,WAAW;AAAA,UACX,SAAS;AAAA,UACT,QAAQ;AAAA,YACN,EAAE,OAAO,mBAAmB,OAAO,gBAAgB,UAAU,KAAK;AAAA,YAClE,EAAE,OAAO,cAAc,OAAO,qBAAqB,UAAU,KAAK;AAAA,UACpE;AAAA,QACF;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,WAAW;AAAA,UACX,SAAS;AAAA,UACT,QAAQ;AAAA,YACN,EAAE,OAAO,cAAc,OAAO,cAAc,UAAU,KAAK;AAAA,YAC3D,EAAE,OAAO,cAAc,OAAO,WAAW,UAAU,MAAM,QAAQ,oBAAoB;AAAA,YACrF,EAAE,OAAO,oBAAoB,OAAO,oBAAoB,UAAU,MAAM,SAAS,GAAG,WAAW,8BAA8B;AAAA,YAC7H,EAAE,OAAO,UAAU,OAAO,oBAAoB,UAAU,MAAM,QAAQ,QAAQ,SAAS,GAAG,WAAW,8BAA8B;AAAA,YACnI,EAAE,OAAO,SAAS,OAAO,SAAS,UAAU,MAAM,SAAS,GAAG,WAAW,4BAA4B;AAAA,UACvG;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,WAAW;AAAA,IACT,SAAS;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM,EAAE,UAAU,UAAU,QAAQ,qBAAqB;AAAA,MACzD,SAAS;AAAA,QACP,EAAE,OAAO,eAAe,OAAO,YAAY,MAAM,qBAAqB,OAAO,IAAI;AAAA,QACjF,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,eAAe,OAAO,eAAe,OAAO,IAAI;AAAA,QACzD,EAAE,OAAO,aAAa,OAAO,QAAQ,OAAO,IAAI;AAAA,MAClD;AAAA,MACA,QAAQ,CAAC,EAAE,OAAO,UAAU,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,MAC7D,MAAM,CAAC,EAAE,OAAO,eAAe,OAAO,OAAO,CAAC;AAAA,MAC9C,YAAY,CAAC,0BAA0B,uBAAuB;AAAA,MAC9D,YAAY,EAAE,MAAM,UAAU,MAAM,UAAU,OAAO,QAAQ;AAAA,IAC/D;AAAA,IACA,UAAU;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM,EAAE,UAAU,UAAU,QAAQ,qBAAqB;AAAA,MACzD,SAAS;AAAA,QACP,EAAE,OAAO,cAAc,OAAO,YAAY,MAAM,qBAAqB,OAAO,IAAI;AAAA,QAChF,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,cAAc,OAAO,eAAe,OAAO,IAAI;AAAA,QACxD,EAAE,OAAO,eAAe,OAAO,eAAe,OAAO,IAAI;AAAA,MAC3D;AAAA,MACA,QAAQ,CAAC,EAAE,OAAO,UAAU,UAAU,KAAK,OAAO,WAAW,CAAC;AAAA,MAC9D,MAAM,CAAC,EAAE,OAAO,cAAc,OAAO,OAAO,CAAC;AAAA,MAC7C,YAAY,EAAE,MAAM,UAAU,MAAM,UAAU,OAAO,QAAQ;AAAA,IAC/D;AAAA,IACA,UAAU;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM,EAAE,UAAU,UAAU,QAAQ,qBAAqB;AAAA,MACzD,SAAS;AAAA,QACP,EAAE,OAAO,cAAc,OAAO,YAAY,MAAM,qBAAqB,OAAO,IAAI;AAAA,QAChF,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,cAAc,OAAO,eAAe,OAAO,IAAI;AAAA,QACxD,EAAE,OAAO,oBAAoB,OAAO,UAAU,MAAM,KAAK;AAAA,MAC3D;AAAA,MACA,QAAQ,CAAC,EAAE,OAAO,UAAU,UAAU,KAAK,OAAO,WAAW,CAAC;AAAA,MAC9D,MAAM,CAAC,EAAE,OAAO,cAAc,OAAO,OAAO,CAAC;AAAA,MAC7C,YAAY,EAAE,MAAM,UAAU,MAAM,UAAU,OAAO,QAAQ;AAAA,IAC/D;AAAA,IACA,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM,EAAE,UAAU,UAAU,QAAQ,qBAAqB;AAAA,MACzD,SAAS;AAAA,QACP,EAAE,OAAO,cAAc,OAAO,QAAQ,MAAM,qBAAqB,OAAO,IAAI;AAAA,QAC5E,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,eAAe,OAAO,UAAU,OAAO,IAAI;AAAA,QACpD,EAAE,OAAO,SAAS,MAAM,KAAK;AAAA,MAC/B;AAAA,MACA,QAAQ,CAAC,EAAE,OAAO,UAAU,UAAU,KAAK,OAAO,SAAS,CAAC;AAAA,MAC5D,MAAM,CAAC,EAAE,OAAO,cAAc,OAAO,OAAO,CAAC;AAAA,MAC7C,YAAY,EAAE,MAAM,UAAU,MAAM,UAAU,OAAO,QAAQ;AAAA,IAC/D;AAAA,EACF;AACF,CAAC;;;Ad5PD;AACA;;;AefA,iBAAkB;;;ACqCX,IAAM,kBAAN,MAAsB;AAAA,EAI3B,YAAY,UAA4B,UAAkC,CAAC,GAAG;AAC5E,SAAK,WAAW;AAChB,SAAK,UAAU;AAAA,MACb,OAAO,QAAQ,SAAS;AAAA,MACxB,UAAU,QAAQ,YAAY;AAAA,MAC9B,oBAAoB,QAAQ,sBAAsB;AAAA,IACpD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,SAAS,OAAqC;AAClD,UAAM,QAAQ,SAAS,KAAK;AAC5B,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAEhC,UAAM,UAAU,MAAM,KAAK,SAAS,YAAY;AAChD,UAAM,OAAoB,CAAC;AAE3B,eAAW,OAAO,SAAS;AACzB,YAAM,MAAM;AACZ,UAAI,CAAC,KAAK,KAAM;AAChB,YAAM,QAAQ,YAAY,KAAK,KAAK;AACpC,UAAI,SAAS,KAAK,QAAQ,UAAU;AAClC,aAAK,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC;AAAA,MAClC;AAAA,IACF;AAEA,SAAK,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACrC,WAAO,KAAK,MAAM,GAAG,KAAK,QAAQ,KAAK;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,cAAc,MAAmB,qBAAqB,IAAY;AACvE,QAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,UAAM,QAAkB,CAAC,mCAAmC;AAC5D,eAAW,OAAO,MAAM;AACtB,YAAM,MAAM,IAAI;AAKhB,YAAM,QAAkB,CAAC;AACzB,UAAI,IAAI,MAAO,OAAM,KAAK,IAAI,KAAK;AACnC,UAAI,IAAI,eAAe,IAAI,gBAAgB,IAAI,MAAO,OAAM,KAAK,IAAI,IAAI,WAAW,GAAG;AACvF,YAAM,SAAS,MAAM,SAAS,IAAI,WAAM,MAAM,KAAK,GAAG,CAAC,KAAK;AAC5D,YAAM,KAAK,OAAO,IAAI,IAAI,GAAG,MAAM,EAAE;AACrC,YAAM,SAAS,OAAO,QAAQ,IAAI,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,kBAAkB;AAC3E,iBAAW,CAAC,MAAM,KAAK,KAAK,QAAQ;AAClC,cAAM,KAAK,OAAO,IAAI,KAAK,cAAc,KAAK,CAAC,EAAE;AAAA,MACnD;AACA,YAAM,QAAQ,OAAO,KAAK,IAAI,UAAU,CAAC,CAAC,EAAE;AAC5C,UAAI,QAAQ,OAAO,QAAQ;AACzB,cAAM,KAAK,aAAQ,QAAQ,OAAO,MAAM,gBAAgB;AAAA,MAC1D;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACF;AAsCA,SAAS,SAAS,OAAyB;AAGzC,QAAM,MAAM,MAAM,YAAY,EAAE,MAAM,YAAY,KAAK,CAAC;AACxD,SAAO,IAAI,OAAO,OAAK,EAAE,UAAU,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC;AAC3D;AAEA,IAAM,YAAY,oBAAI,IAAI;AAAA,EACxB;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAO;AAAA,EACzE;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACvE;AAAA,EAAO;AAAA,EAAO;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAS;AAAA,EAAM;AAAA,EAAM;AAAA,EAC3E;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AACxD,CAAC;AASD,SAAS,YAAY,KAAkB,OAAyB;AAC9D,MAAI,QAAQ;AACZ,QAAM,aAAa,WAAW,IAAI,IAAI;AACtC,QAAM,cAAc,IAAI,QAAQ,SAAS,IAAI,KAAK,IAAI,CAAC;AACvD,QAAM,eAAe,IAAI,cAAc,SAAS,IAAI,WAAW,IAAI,CAAC;AACpE,QAAM,aAAa,IAAI,cAAc,SAAS,IAAI,WAAW,IAAI,CAAC;AAElE,aAAW,QAAQ,OAAO;AACxB,QAAI,WAAW,SAAS,IAAI,EAAG,UAAS;AAAA,aAC/B,YAAY,SAAS,IAAI,KAAK,aAAa,SAAS,IAAI,EAAG,UAAS;AAAA,aACpE,WAAW,SAAS,IAAI,EAAG,UAAS;AAAA,EAC/C;AAEA,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,IAAI,UAAU,CAAC,CAAC,GAAG;AACjE,UAAM,WAAW,WAAW,SAAS;AACrC,UAAM,WAAW,MAAM,QAAQ,SAAS,MAAM,KAAK,IAAI,CAAC;AACxD,eAAW,QAAQ,OAAO;AACxB,UAAI,SAAS,SAAS,IAAI,EAAG,UAAS;AAAA,eAC7B,SAAS,SAAS,IAAI,EAAG,UAAS;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AACT;AAGA,SAAS,WAAW,MAAwB;AAC1C,SAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AACrD;AAGA,SAAS,cAAc,OAA2B;AAChD,QAAM,IAAI,MAAM,QAAQ;AACxB,MAAI,MAAM,YAAY,MAAM,UAAW,QAAO,iBAAY,MAAM,SAAS;AACzE,MAAI,MAAM,YAAY,MAAM,QAAQ,MAAM,OAAO,GAAG;AAClD,UAAM,SAAS,MAAM,QAClB;AAAA,MAAI,CAAC,MACJ,OAAO,MAAM,WAAW,IAAK,EAAyB;AAAA,IACxD,EACC,OAAO,OAAO,EACd,MAAM,GAAG,CAAC;AACb,WAAO,UAAU,OAAO,KAAK,GAAG,CAAC;AAAA,EACnC;AACA,SAAO;AACT;;;ADtMA,SAAS,qBAAqB,KAA8C;AAC1E,MAAI,KAAK,OAAO;AACd,WAAO;AAAA,MACL,QAAQ,IAAI,MAAM;AAAA,MAClB,OAAO,IAAI,MAAM,SAAS,CAAC;AAAA,MAC3B,aAAa,IAAI,MAAM,eAAe,CAAC;AAAA,MACvC,UAAU;AAAA,MACV,GAAI,IAAI,gBAAgB,EAAE,UAAU,IAAI,cAAc,IAAI,CAAC;AAAA,MAC3D,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;AAAA,IAChD;AAAA,EACF;AACA,SAAO,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,GAAG,UAAU,KAAK;AACtD;AAgCA,IAAM,kBAAkB,aAAE,OAAO;AAAA,EAC/B,YAAY,aACT,OAAO,EACP,IAAI,CAAC,EACL,SAAS,+DAA+D;AAAA,EAC3E,WAAW,aACR,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EAGF;AAAA,EACF,QAAQ,aACL,MAAM,aAAE,OAAO,CAAC,EAChB,SAAS,EACT,SAAS,wDAAwD;AAAA,EACpE,SAAS,aACN;AAAA,IACC,aAAE,OAAO;AAAA,MACP,OAAO,aAAE,OAAO;AAAA,MAChB,OAAO,aAAE,KAAK,CAAC,OAAO,MAAM,CAAC;AAAA,IAC/B,CAAC;AAAA,EACH,EACC,SAAS,EACT,SAAS,qEAAqE;AAAA,EACjF,OAAO,aACJ,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,GAAG,EACP,SAAS,EACT,SAAS,yEAAyE;AACvF,CAAC;AAkBM,IAAM,kBAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,aACE;AAAA,EAKF,YAAY;AAAA,IACV,MAAM;AAAA,IACN,YAAY;AAAA,MACV,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aACE;AAAA,MAEJ;AAAA,IACF;AAAA,IACA,UAAU,CAAC,SAAS;AAAA,IACpB,sBAAsB;AAAA,EACxB;AACF;AAQO,SAAS,uBAAuB,KAAwC;AAC7E,QAAM,YAAY,IAAI,gBAAgB,IAAI,QAAQ;AAClD,QAAM,WAAW,IAAI,YAAY;AAEjC,SAAO,OAAO,MAAM,YAAY;AAC9B,UAAM,EAAE,QAAQ,IAAI;AAEpB,QAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,aAAO,KAAK,UAAU,EAAE,OAAO,oCAAoC,CAAC;AAAA,IACtE;AAEA,QAAI,CAAC,IAAI,GAAG,gBAAgB;AAC1B,aAAO,KAAK,UAAU;AAAA,QACpB,OACE;AAAA,MAEJ,CAAC;AAAA,IACH;AAGA,UAAM,OAAO,MAAM,UAAU,SAAS,OAAO;AAC7C,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO,KAAK,UAAU;AAAA,QACpB,OACE;AAAA,MAEJ,CAAC;AAAA,IACH;AACA,UAAM,UAAU,gBAAgB,cAAc,IAAI;AAGlD,UAAM,eAA+B;AAAA,MACnC;AAAA,QACE,MAAM;AAAA,QACN,SACE,wtBAYA;AAAA,MACJ;AAAA,MACA,EAAE,MAAM,QAAQ,SAAS,QAAQ;AAAA,IACnC;AAEA,QAAI;AACJ,QAAI;AACF,YAAM,YAAY,MAAM,IAAI,GAAG,eAAe,cAAc,iBAAiB;AAAA,QAC3E,YAAY;AAAA,QACZ,mBAAmB;AAAA,MACrB,CAAC;AACD,aAAO,UAAU;AAAA,IACnB,SAAS,KAAK;AACZ,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,yBAAyB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAClF,CAAC;AAAA,IACH;AAGA,UAAM,gBAAgB,KAAK,KAAK,OAAK,EAAE,OAAO,SAAS,KAAK,UAAU,GAAG,UACpE,KAAK,CAAC,EAAE;AACb,QAAI,cAAc,SAAS,KAAK,YAAY;AAC1C,aAAO,KAAK,UAAU;AAAA,QACpB,OACE,mBAAmB,KAAK,UAAU,gDACpB,KAAK,IAAI,OAAK,EAAE,OAAO,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,MACzD,CAAC;AAAA,IACH;AAGA,UAAM,QAAQ,KAAK,IAAI,KAAK,SAAS,IAAI,QAAQ;AACjD,QAAI;AACJ,QAAI,KAAK,WAAW;AAClB,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,KAAK,SAAS;AACxC,YAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,kBAAQ;AAAA,QACV,OAAO;AACL,iBAAO,KAAK,UAAU;AAAA,YACpB;AAAA,YACA,OAAO,6CAA6C,KAAK,SAAS;AAAA,UACpE,CAAC;AAAA,QACH;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,KAAK,UAAU;AAAA,UACpB;AAAA,UACA,OAAO,gCAAgC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACzF,CAAC;AAAA,MACH;AAAA,IACF;AACA,QAAI;AACF,YAAM,UAAU,MAAM,IAAI,WAAW,KAAK,KAAK,YAAY;AAAA,QACzD;AAAA,QACA,QAAQ,KAAK,UAAU;AAAA,QACvB,SAAS,KAAK,WAAW;AAAA,QACzB;AAAA,QACA,SAAS,qBAAqB,OAAO;AAAA,MACvC,CAAC;AACD,aAAO,KAAK,UAAU;AAAA,QACpB,MAAM,EAAE,GAAG,MAAM,MAAM;AAAA,QACvB,OAAO,QAAQ;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,aAAO,KAAK,UAAU;AAAA,QACpB;AAAA,QACA,OAAO,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACpF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAQO,SAAS,sBACd,UACA,SACM;AACN,WAAS,SAAS,iBAAiB,uBAAuB,OAAO,CAAC;AACpE;;;AEzGO,SAAS,uBAAuB,QAAyB;AAC9D,SAAO;AAAA,IACL,OAAO,eAAe,OAAO,SAAS,YAAY,OAAO,YAAY;AAAA,EACvE;AACF;AAEO,SAAS,iBACd,QACA,KAOe;AACf,MAAI,OAAO,cAAc,OAAO;AAC9B,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,SAAS,SAAS,OAAO,SAAS,WAAW,OAAO,SAAS,QAAQ;AAC9E,WAAO,SAAS,OAAO,IAAI;AAAA,EAC7B;AACA,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,SAAS,OAAO,SAAS,QAAQ;AAC/E,WAAO,SAAS,OAAO,IAAI;AAAA,EAC7B;AACA,MAAI,OAAO,SAAS,YAAY,CAAC,OAAO,UAAU,CAAC,OAAO,MAAM;AAC9D,WAAO;AAAA,EACT;AACA,OAAK,OAAO,SAAS,SAAS,OAAO,SAAS,WAAW,CAAC,OAAO,QAAQ;AACvE,WAAO,SAAS,OAAO,IAAI;AAAA,EAC7B;AAEA,MAAI,KAAK;AACP,QAAI,OAAO,SAAS,UAAU,CAAC,IAAI,YAAY;AAC7C,aAAO;AAAA,IACT;AACA,QAAI,OAAO,SAAS,SAAS,CAAC,IAAI,aAAa,CAAC,IAAI,YAAY;AAC9D,aAAO;AAAA,IACT;AAAA,EACF;AAIA,MAAI,uBAAuB,MAAM,GAAG;AAClC,UAAM,gBACJ,KAAK,yBAAyB,QAAQ,QAAQ,KAAK,WAAW,oBAAoB;AACpF,QAAI,CAAC,eAAe;AAClB,UAAI,OAAO,YAAa,QAAO;AAC/B,UAAI,OAAO,SAAS,SAAU,QAAO;AACrC,UAAI,OAAO,YAAY,SAAU,QAAO;AAAA,IAC1C;AAAA,EACF;AACA,SAAO;AACT;AAWA,SAAS,oBAAoB,GAAkE;AAC7F,UAAQ,GAAG;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAOA,SAAS,aACP,OACA,aACA,YAC6E;AAC7E,QAAM,WAAW,MAAM;AACvB,QAAM,QACJ,MAAM,kBAAkB,WAAW,IAAI,MAAM,cAAc,IACvD,WAAW,IAAI,MAAM,cAAc,IACnC;AACN,QAAM,QAAQ,WAAW,OAAO,SAAS,QAAQ,IAAI;AAErD,QAAM,OAAO,MAAM,QAAQ;AAC3B,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,OAAO,MAAM,QAAQ,OAAO;AAClC,QAAM,WAAW,oBAAoB,IAAI;AACzC,QAAM,SAAkC,EAAE,MAAM,SAAS;AAEzD,QAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,OAAO;AACrE,QAAM,OAAO,MAAM,YAAY,OAAO;AACtC,QAAM,cAAc,CAAC,OAAO,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK,KAAK;AACjE,MAAI,YAAa,QAAO,cAAc;AAGtC,QAAM,eAAe,MAAM,WAAW,OAAO;AAC7C,MAAI,MAAM,QAAQ,YAAY,KAAK,aAAa,SAAS,GAAG;AAC1D,UAAM,SAAS,aACZ,IAAI,OAAM,OAAO,MAAM,WAAW,IAAK,EAAyB,KAAM,EACtE,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ;AACnD,QAAI,OAAO,SAAS,GAAG;AACrB,aAAO,OAAO,aAAa,UAAU,SAAY;AACjD,UAAI,aAAa,SAAS;AACxB,eAAO,QAAQ,EAAE,MAAM,UAAU,MAAM,OAAO;AAAA,MAChD;AAAA,IACF;AAAA,EACF,WAAW,aAAa,SAAS;AAC/B,WAAO,QAAQ,EAAE,MAAM,SAAS;AAAA,EAClC;AAEA,MAAI,MAAM,iBAAiB,QAAW;AACpC,WAAO,UAAU,MAAM;AAAA,EACzB;AAEA,QAAM,WAAW,QAAQ,MAAM,YAAY,OAAO,YAAY,KAAK;AACnE,SAAO,EAAE,MAAM,QAAQ,SAAS;AAClC;AAWA,SAAS,sBACP,QACA,aACA,YACgC;AAChC,QAAM,aAAsD,CAAC;AAC7D,QAAM,WAAqB,CAAC;AAG5B,QAAM,eACJ,MAAM,QAAQ,OAAO,SAAS,KAC9B,OAAO,UAAU,KAAK,OAAK,MAAM,eAAe,MAAM,mBAAmB,MAAM,iBAAiB,MAAM,gBAAgB;AACxH,MAAI,OAAO,cAAc,cAAc;AACrC,eAAW,WAAW;AAAA,MACpB,MAAM;AAAA,MACN,aAAa,OAAO,OAAO,UAAU;AAAA,IACvC;AAEA,QAAI,OAAO,iBAAiB,OAAO,eAAe;AAChD,eAAS,KAAK,UAAU;AAAA,IAC1B;AAAA,EACF;AAEA,aAAW,SAAS,OAAO,UAAU,CAAC,GAAG;AACvC,UAAM,WAAW,aAAa,OAAO,aAAa,UAAU;AAC5D,QAAI,CAAC,SAAU;AACf,eAAW,SAAS,IAAI,IAAI,SAAS;AACrC,QAAI,SAAS,SAAU,UAAS,KAAK,SAAS,IAAI;AAAA,EACpD;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,GAAI,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,IAC1C,sBAAsB;AAAA,EACxB;AACF;AAKO,SAAS,eAAe,QAAgB,SAAS,WAAmB;AACzE,SAAO,GAAG,MAAM,GAAG,OAAO,IAAI;AAChC;AAEA,SAAS,eAAe,QAAgB,aAA4C;AAClF,QAAM,QACJ,OAAO,OAAO,UAAU,WACpB,OAAO,QACP,OAAO,KAAK,QAAQ,MAAM,GAAG;AACnC,QAAM,SAAS,OAAO,cAAc,aAAa;AACjD,QAAM,cAAc,aAAa,SAAS;AAC1C,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,GAAG,KAAK,GAAG,cAAc,uBAAkB,WAAW,KAAK,EAAE,GAAG;AAC3E,MAAI,OAAO,kBAAkB,OAAO,OAAO,mBAAmB,UAAU;AACtE,UAAM,KAAK,eAAe,OAAO,cAAc,EAAE;AAAA,EACnD;AACA,MAAI,OAAO,KAAM,OAAM,KAAK,SAAS,OAAO,IAAI,GAAG;AACnD,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AASO,SAAS,uBACd,QACA,aACA,YACA,aAAa,WACY;AAKzB,MAAI,OAAO,cAAc,MAAO,QAAO;AACvC,MAAI,OAAO,SAAS,SAAS,OAAO,SAAS,WAAW,OAAO,SAAS,OAAQ,QAAO;AACvF,SAAO;AAAA,IACL,MAAM,eAAe,QAAQ,UAAU;AAAA,IACvC,aAAa,eAAe,QAAQ,WAAW;AAAA,IAC/C,YAAY,sBAAsB,QAAQ,aAAa,UAAU;AAAA,EACnE;AACF;AAaA,SAAS,0BAA0B,QAKjC;AACA,SAAO;AAAA,IACL,QAAQ,CAAC,QAAQ,IAAI,SACnB,OAAO,OAAO,QAAQ,EAAE,GAAG,MAAM,GAAG,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAAA,IAC1D,QAAQ,CAAC,QAAQ,SAAS,OAAO,OAAO,QAAQ,IAAI;AAAA,IACpD,MAAM,CAAC,QAAQ,UAAU,OAAO,KAAK,QAAQ,EAAE,MAAM,CAAC;AAAA,IACtD,QAAQ,OAAO,QAAQ,QAAQ;AAC7B,UAAI,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,WAAW,EAAG,QAAO;AAIpD,UAAI,QAAQ;AACZ,iBAAW,MAAM,KAAK;AACpB,cAAM,OAAO,OAAO,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAC7C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAMA,SAAS,wBACP,QACA,KACa;AACb,QAAM,oBAAoB,IAAI,aAAa,EAAE,IAAI,YAAY,MAAM,eAAe;AAClF,QAAM,iBACJ,MAAM,QAAQ,OAAO,SAAS,KAC9B,OAAO,UAAU;AAAA,IACf,OAAK,MAAM,eAAe,MAAM,mBAAmB,MAAM,iBAAiB,MAAM;AAAA,EAClF;AAEF,SAAO,OAAO,MAAM,YAAY;AAK9B,UAAM,YAAY,SAAS,QACvB,EAAE,IAAI,QAAQ,MAAM,IAAI,MAAM,QAAQ,MAAM,KAAK,IACjD;AACJ,UAAM,YAAY,yBAAyB,OAAO;AAClD,UAAM,aAAa,OAAO;AAC1B,UAAM,SAAS,OAAO;AACtB,UAAM,SAAiC;AAAA,MACrC,IAAI;AAAA,MACJ,QAAQ,OAAO;AAAA,MACf;AAAA,IACF;AAEA,QAAI,CAAC,YAAY;AACf,aAAO,QAAQ;AACf,aAAO,KAAK,UAAU,MAAM;AAAA,IAC9B;AACA,QAAI,CAAC,UAAU,OAAO,SAAS,UAAU;AACvC,aAAO,QAAQ;AACf,aAAO,KAAK,UAAU,MAAM;AAAA,IAC9B;AAEA,UAAM,WACJ,OAAO,KAAK,aAAa,YAAY,KAAK,SAAS,SAAS,IACxD,KAAK,WACL;AAEN,QAAI;AACJ,QAAI,gBAAgB;AAClB,UAAI,CAAC,UAAU;AACb,eAAO,QACL,oEACG,UAAU;AACf,eAAO,KAAK,UAAU,MAAM;AAAA,MAC9B;AACA,UAAI;AAGF,cAAM,QAAQ,MAAM,IAAI,WAAW,KAAK,YAAY;AAAA,UAClD,OAAO,EAAE,IAAI,SAAS;AAAA,UACtB,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AACD,iBAAU,MAAyC,CAAC;AACpD,YAAI,CAAC,QAAQ;AACX,iBAAO,QAAQ,UAAU,QAAQ,iBAAiB,UAAU;AAC5D,iBAAO,KAAK,UAAU,MAAM;AAAA,QAC9B;AACA,eAAO,WAAW;AAAA,MACpB,SAAS,KAAK;AACZ,eAAO,QAAQ,0BAA0B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AACzF,eAAO,KAAK,UAAU,MAAM;AAAA,MAC9B;AAAA,IACF;AAIA,UAAM,EAAE,UAAU,OAAO,GAAG,WAAW,IAAI;AAQ3C,QACE,IAAI,wBACJ,uBAAuB,MAAM,KAC7B,IAAI,WAAW,sBACf;AACA,UAAI;AACF,cAAM,WAAW,GAAG,IAAI,cAAc,SAAS,GAAG,OAAO,IAAI;AAC7D,cAAM,EAAE,GAAG,IAAI,MAAM,IAAI,UAAU,qBAAqB;AAAA,UACtD;AAAA,UACA,YAAY,OAAO;AAAA,UACnB;AAAA,UACA,WAAW;AAAA,UACX,gBAAgB,SAAS;AAAA,UACzB,WAAW,SAAS;AAAA,UACpB,YAAY,UAAU;AAAA,QACxB,CAAC;AACD,cAAM,UAGF;AAAA,UACF,IAAI;AAAA,UACJ,QAAQ,OAAO;AAAA,UACf;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,iBAAiB;AAAA,UACjB,SACE,WAAW,OAAO,IAAI,oEACA,EAAE;AAAA,QAG5B;AACA,eAAO,KAAK,UAAU,OAAO;AAAA,MAC/B,SAAS,KAAK;AACZ,eAAO,QAAQ,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC9F,eAAO,KAAK,UAAU,MAAM;AAAA,MAC9B;AAAA,IACF;AAEA,QAAI;AACF,UAAI;AACJ,UAAI,OAAO,SAAS,OAAO;AACzB,cAAM,MAAM,kBAAkB,QAAQ,KAAK,YAAY,QAAQ,QAAQ;AAAA,MACzE,WAAW,OAAO,SAAS,QAAQ;AACjC,cAAM,MAAM,mBAAmB,QAAQ,KAAK,YAAY,QAAQ,SAAS;AAAA,MAC3E,OAAO;AAEL,cAAM,MAAM,qBAAqB,QAAQ,KAAK,YAAY,QAAQ,SAAS;AAAA,MAC7E;AACA,aAAO,KAAK;AACZ,aAAO,SAAS,OAAO;AACvB,YAAM,aACJ,OAAO,OAAO,mBAAmB,WAAW,OAAO,iBAAiB;AACtE,aAAO,UAAU,cAAc,WAAW,OAAO,IAAI;AACrD,aAAO,KAAK,UAAU,MAAM;AAAA,IAC9B,SAAS,KAAK;AACZ,aAAO,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,aAAO,KAAK,UAAU,MAAM;AAAA,IAC9B;AAAA,EACF;AACF;AAQA,SAAS,yBAAyB,KAA8C;AAC9E,MAAI,KAAK,OAAO;AACd,WAAO;AAAA,MACL,QAAQ,IAAI,MAAM;AAAA,MAClB,OAAO,IAAI,MAAM,SAAS,CAAC;AAAA,MAC3B,aAAa,IAAI,MAAM,eAAe,CAAC;AAAA,MACvC,UAAU;AAAA,MACV,GAAI,IAAI,gBAAgB,EAAE,UAAU,IAAI,cAAc,IAAI,CAAC;AAAA,MAC3D,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;AAAA,IAChD;AAAA,EACF;AACA,SAAO,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,GAAG,UAAU,KAAK;AACtD;AAEA,eAAe,qBACb,QACA,KACA,QACA,QACA,WACkB;AAClB,QAAM,gBAAgB,0BAA0B,IAAI,UAAU;AAC9D,QAAM,aAAa,EAAE,QAAQ,MAAM,WAAW,QAAQ,eAAe,OAAO;AAC5E,SAAO,MAAO,IAAI,WAEf,gBAAgB,OAAO,YAAa,OAAO,QAAS,UAAU;AACnE;AAWO,SAAS,oBACd,QACA,MACA,QACA,UACyB;AACzB,QAAM,QAAQ,OAAO;AACrB,QAAM,UACJ,SAAS,OAAO,UAAU,YAAY,UAAU,SAAS,OAAO,MAAM,SAAS,WAC3E,MAAM,OACN;AACN,QAAM,OAAgC,UAAU,EAAE,CAAC,OAAO,GAAG,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK;AAEvF,MAAI,OAAO,eAAe;AACxB,UAAM,UAAU,OAAO,iBAAiB;AACxC,UAAM,UAAU,SAAS,OAAO,OAAO,IAAI;AAC3C,QAAI,YAAY,OAAW,MAAK,OAAO,aAAa,IAAI;AAAA,EAC1D;AAEA,MAAI,OAAO,aAAa,OAAO,OAAO,cAAc,UAAU;AAC5D,WAAO,OAAO,MAAM,OAAO,SAAoC;AAAA,EACjE;AACA,SAAO;AACT;AAEA,eAAe,kBACb,QACA,KACA,QACA,QACA,UACkB;AAClB,QAAM,SACJ,IAAI,cACH,IAAI,aACD,qBAAqB,EAAE,SAAS,IAAI,YAAY,SAAS,IAAI,WAAW,CAAC,IACzE;AACN,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,QAAM,SAAU,OAAO,UAAU;AACjC,QAAM,OAAO,oBAAoB,QAAQ,QAAQ,QAAQ,QAAQ;AACjE,SAAO,MAAM,OAAO,QAAQ;AAAA,IAC1B,KAAK,OAAO;AAAA,IACZ;AAAA,IACA,MAAM,WAAW,SAAS,WAAW,WAAW,SAAY;AAAA,IAC5D,SAAS,IAAI;AAAA,EACf,CAAC;AACH;AAEA,eAAe,mBACb,QACA,KACA,QACA,QACA,WACkB;AAClB,MAAI,CAAC,IAAI,YAAY;AACnB,UAAM,IAAI,MAAM,kEAAkE;AAAA,EACpF;AACA,QAAM,SAAS,MAAM,IAAI,WAAW,QAAQ,OAAO,QAAS;AAAA,IAC1D,aAAa,EAAE,QAAQ,QAAQ,MAAM,WAAW,QAAQ,OAAO,KAAK;AAAA,EACtE,CAAiD;AACjD,MAAI,UAAU,OAAO,WAAW,YAAY,aAAa,UAAU,OAAO,YAAY,OAAO;AAC3F,UAAM,IAAI;AAAA,MACR,SAAS,OAAO,MAAM,aAAc,OAA8B,SAAS,eAAe;AAAA,IAC5F;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,qBAAqB,SAIjB;AAClB,QAAM,YAAY,QAAQ,SAAS,WAAW;AAC9C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,sEAAsE;AAAA,EACxF;AACA,SAAO;AAAA,IACL,MAAM,QAAQ,EAAE,KAAK,QAAQ,MAAM,QAAQ,GAAG;AAC5C,YAAM,WAAW,eAAe,KAAK,GAAG,IAAI,MAAM,IAAI,QAAQ,WAAW,IAAI,QAAQ,OAAO,EAAE,CAAC,GAAG,IAAI,WAAW,GAAG,IAAI,KAAK,GAAG,GAAG,GAAG;AACtI,YAAM,MAAM,MAAM,UAAU,UAAU;AAAA,QACpC;AAAA,QACA,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAI,QAAQ,WAAW,CAAC;AAAA,UACxB,GAAI,WAAW,CAAC;AAAA,QAClB;AAAA,QACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,MACtC,CAAC;AACD,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,YAAM,SAAS,OAAO,cAAc,IAAI,IAAI;AAC5C,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,MACJ,UAAU,OAAO,WAAW,YAAY,WAAW,SAC9C,OAA8B,QAC/B;AACN,cAAM,IAAI,MAAM,GAAG,MAAM,IAAI,QAAQ,WAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,WAAW,MAAM,KAAK,UAAU,GAAG,CAAC,EAAE;AAAA,MACjH;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,cAAc,GAAoB;AACzC,MAAI;AACF,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAaA,eAAsB,uBACpB,UACA,SAIC;AACD,QAAM,UAAW,MAAM,QAAQ,SAAS,YAAY;AACpD,QAAM,SAAS,IAAI;AAAA,IACjB,QAAQ,OAAO,CAAC,MAAsB,QAAQ,GAAG,IAAI,CAAC,EAAE,IAAI,OAAK,CAAC,EAAE,MAAM,CAAC,CAAC;AAAA,EAC9E;AAEA,QAAM,aAAuB,CAAC;AAC9B,QAAM,UAAqD,CAAC;AAC5D,QAAM,SAAS,QAAQ,cAAc;AAErC,aAAW,OAAO,SAAS;AACzB,QAAI,CAAC,KAAK,WAAW,CAAC,MAAM,QAAQ,IAAI,OAAO,EAAG;AAClD,eAAW,UAAU,IAAI,SAAS;AAChC,UAAI,CAAC,UAAU,OAAO,OAAO,SAAS,SAAU;AAGhD,YAAM,aAAqB;AAAA,QACzB,GAAG;AAAA,QACH,YAAY,OAAO,cAAc,IAAI;AAAA,MACvC;AAEA,YAAM,SAAS,iBAAiB,YAAY;AAAA,QAC1C,YAAY,QAAQ;AAAA,QACpB,WAAW,QAAQ;AAAA,QACnB,YAAY,QAAQ;AAAA,QACpB,sBAAsB,QAAQ;AAAA,QAC9B,WAAW,QAAQ;AAAA,MACrB,CAAC;AACD,UAAI,WAAW,MAAM;AACnB,gBAAQ,KAAK,EAAE,QAAQ,WAAW,MAAM,OAAO,CAAC;AAChD;AAAA,MACF;AAEA,YAAM,aAAa,uBAAuB,YAAY,KAAK,QAAQ,MAAM;AACzE,UAAI,CAAC,WAAY;AAGjB,UAAI,SAAS,IAAI,WAAW,IAAI,GAAG;AACjC,gBAAQ,KAAK,EAAE,QAAQ,WAAW,MAAM,QAAQ,+BAA+B,CAAC;AAChF;AAAA,MACF;AAEA,YAAM,UAAU,wBAAwB,YAAY,OAAO;AAC3D,eAAS,SAAS,YAAY,OAAO;AACrC,iBAAW,KAAK,WAAW,IAAI;AAK/B,UACE,QAAQ,wBACR,uBAAuB,UAAU,KACjC,QAAQ,WAAW,iCACnB;AAGA,cAAM,YAAgC;AAAA,UACpC,GAAG;AAAA,UACH,sBAAsB;AAAA,QACxB;AACA,cAAM,gBAAgB,wBAAwB,YAAY,SAAS;AACnE,gBAAQ,UAAU;AAAA,UAChB,WAAW;AAAA,UACX,OAAO,UAAU;AACf,kBAAM,MAAM,MAAM,cAAc,KAAK;AAGrC,gBAAI,SAAkB;AACtB,gBAAI;AACF,uBAAS,OAAO,QAAQ,WAAW,KAAK,MAAM,GAAG,IAAI;AAAA,YACvD,QAAQ;AACN,uBAAS;AAAA,YACX;AAGA,gBACE,UACA,OAAO,WAAW,YAClB,QAAQ,UACP,OAA4B,OAAO,OACpC;AACA,oBAAM,SACH,OAA+B,SAAS,OACrC,OAAQ,OAA+B,KAAK,IAC5C;AACN,oBAAM,IAAI,MAAM,MAAM;AAAA,YACxB;AACA,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,YAAY,QAAQ;AAC/B;;;ACn1BA,IAAAC,aAA4B;AAuCrB,IAAM,eAAN,MAAmB;AAAA,EACxB,YACmB,iBACA,eACjB;AAFiB;AACA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUH,MAAM,aAA4E;AAChF,UAAM,WAAW,MAAM,KAAK,gBAAgB,KAAK,OAAO;AACxD,UAAM,SAA+D,CAAC;AAEtE,eAAW,OAAO,UAAU;AAC1B,YAAM,SAAS,uBAAY,UAAU,GAAG;AACxC,UAAI,OAAO,WAAW,OAAO,KAAK,QAAQ;AACxC,eAAO,KAAK;AAAA,UACV,MAAM,OAAO,KAAK;AAAA,UAClB,OAAO,OAAO,KAAK;AAAA,UACnB,MAAM,OAAO,KAAK;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,UAAU,WAA+C;AAC7D,UAAM,MAAM,MAAM,KAAK,gBAAgB,IAAI,SAAS,SAAS;AAC7D,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,SAAS,uBAAY,UAAU,GAAG;AACxC,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO;AAAA,IACT;AACA,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,oBACE,OACA,SACA,cACgB;AAChB,UAAM,QAAkB,CAAC;AAGzB,UAAM,KAAK,MAAM,YAAY;AAG7B,QAAI,SAAS;AACX,YAAM,MAAgB,CAAC;AACvB,UAAI,QAAQ,QAAS,KAAI,KAAK,gBAAgB,QAAQ,OAAO,EAAE;AAC/D,UAAI,QAAQ,WAAY,KAAI,KAAK,mBAAmB,QAAQ,UAAU,EAAE;AACxE,UAAI,QAAQ,SAAU,KAAI,KAAK,uBAAuB,QAAQ,QAAQ,EAAE;AACxE,UAAI,QAAQ,SAAU,KAAI,KAAK,iBAAiB,QAAQ,QAAQ,EAAE;AAClE,UAAI,IAAI,SAAS,GAAG;AAClB,cAAM,KAAK,gCAAgC,IAAI,KAAK,IAAI,CAAC;AAAA,MAC3D;AAAA,IACF;AAGA,QAAI,gBAAgB,aAAa,SAAS,KAAK,KAAK,eAAe;AACjE,YAAM,QAAQ,KAAK,cAAc,yBAAyB,YAAY;AACtE,UAAI,MAAO,OAAM,KAAK,KAAK;AAAA,IAC7B;AAEA,WAAO,CAAC,EAAE,MAAM,UAAmB,SAAS,MAAM,KAAK,IAAI,EAAE,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,oBACE,OACA,gBACA,cACkB;AAClB,UAAM,UAA4B,CAAC;AAGnC,QAAI,MAAM,OAAO;AACf,cAAQ,QAAQ,MAAM,MAAM;AAC5B,cAAQ,cAAc,MAAM,MAAM;AAClC,cAAQ,YAAY,MAAM,MAAM;AAAA,IAClC;AAGA,UAAM,UAAU,IAAI,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9D,UAAM,OAAO,oBAAI,IAAY;AAC7B,UAAM,WAA+B,CAAC;AAEtC,QAAI,MAAM,SAAS,MAAM,MAAM,SAAS,GAAG;AACzC,iBAAW,OAAO,MAAM,OAAO;AAC7B,YAAI,KAAK,IAAI,IAAI,IAAI,EAAG;AACxB,cAAM,MAAM,QAAQ,IAAI,IAAI,IAAI;AAChC,YAAI,KAAK;AACP,mBAAS,KAAK,GAAG;AACjB,eAAK,IAAI,IAAI,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,gBAAgB,aAAa,SAAS,KAAK,KAAK,eAAe;AACjE,YAAM,aAAa,KAAK,cAAc,eAAe,cAAc,cAAc;AACjF,iBAAW,OAAO,YAAY;AAC5B,YAAI,KAAK,IAAI,IAAI,IAAI,EAAG;AACxB,iBAAS,KAAK,GAAG;AACjB,aAAK,IAAI,IAAI,IAAI;AAAA,MACnB;AAAA,IACF;AAEA,QAAI,SAAS,SAAS,GAAG;AACvB,cAAQ,QAAQ;AAChB,cAAQ,aAAa;AAAA,IACvB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,oBAAoB,OAAc,SAA8C;AACpF,QAAI,CAAC,KAAK,cAAe,QAAO,CAAC;AACjC,QAAI,CAAC,MAAM,UAAU,MAAM,OAAO,WAAW,EAAG,QAAO,CAAC;AACxD,WAAO,KAAK,cAAc,iBAAiB,WAAW,CAAC,GAAG,MAAM,MAAM;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,oBAAoB,SAAwD;AAChF,QAAI,SAAS,SAAS;AACpB,YAAM,SAAS,MAAM,KAAK,gBAAgB,IAAI,OAAO,QAAQ,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3F,YAAM,mBAAoB,QAAkD;AAC5E,UAAI,kBAAkB;AACpB,cAAM,QAAQ,MAAM,KAAK,UAAU,gBAAgB;AACnD,YAAI,SAAS,MAAM,WAAW,MAAO,QAAO;AAAA,MAC9C;AAAA,IACF;AAGA,UAAM,YAAY,MAAM,KAAK,WAAW;AACxC,QAAI,UAAU,WAAW,EAAG,QAAO;AACnC,WAAO,KAAK,UAAU,UAAU,CAAC,EAAE,IAAI;AAAA,EACzC;AACF;;;ACxPA,IAAAC,aAA4B;AA0DrB,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAA6B,iBAAmC;AAAnC;AAAA,EAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWjE,MAAM,UAAU,WAA+C;AAC7D,UAAM,MAAM,MAAM,KAAK,gBAAgB,IAAI,SAAS,SAAS;AAC7D,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,SAAS,uBAAY,UAAU,GAAG;AACxC,QAAI,CAAC,OAAO,QAAS,QAAO;AAC5B,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAA+B;AACnC,UAAM,MAAM,MAAM,KAAK,gBAAgB,KAAK,OAAO;AACnD,UAAM,SAAkB,CAAC;AACzB,eAAW,QAAQ,KAAK;AACtB,YAAM,SAAS,uBAAY,UAAU,IAAI;AACzC,UAAI,OAAO,WAAW,OAAO,KAAK,WAAW,OAAO;AAClD,eAAO,KAAK,OAAO,IAAI;AAAA,MACzB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WAAW,YAAiD;AAChE,UAAM,SAAkB,CAAC;AACzB,eAAW,QAAQ,YAAY;AAC7B,YAAM,QAAQ,MAAM,KAAK,UAAU,IAAI;AACvC,UAAI,SAAS,MAAM,WAAW,OAAO;AACnC,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,iBACJ,UAAwB,CAAC,GACzB,YACkB;AAClB,UAAM,YAAY,aAAa,IAAI,IAAI,UAAU,IAAI;AACrD,UAAM,MAAM,MAAM,KAAK,WAAW;AAClC,WAAO,IAAI,OAAO,CAAC,UAAU;AAC3B,UAAI,aAAa,CAAC,UAAU,IAAI,MAAM,IAAI,EAAG,QAAO;AACpD,aAAO,KAAK,eAAe,OAAO,OAAO;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,eAAe,OAAc,SAAgC;AAC3D,UAAM,aAAa,MAAM;AACzB,QAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO;AACnD,WAAO,WAAW,MAAM,CAAC,SAAS,KAAK,kBAAkB,MAAM,OAAO,CAAC;AAAA,EACzE;AAAA,EAEQ,kBAAkB,MAA6B,SAAgC;AACrF,UAAM,aAAa,QAAQ,KAAK,KAAK;AACrC,UAAM,WAAW,KAAK;AAEtB,YAAQ,KAAK,UAAU;AAAA,MACrB,KAAK;AACH,eAAO,eAAe;AAAA,MACxB,KAAK;AACH,eAAO,eAAe;AAAA,MACxB,KAAK,MAAM;AACT,cAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ;AAC3D,eAAO,KAAK,SAAS,UAAoB;AAAA,MAC3C;AAAA,MACA,KAAK,UAAU;AACb,cAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ;AAC3D,eAAO,CAAC,KAAK,SAAS,UAAoB;AAAA,MAC5C;AAAA,MACA,KAAK,YAAY;AACf,YAAI,OAAO,eAAe,YAAY,OAAO,aAAa,UAAU;AAClE,iBAAO,WAAW,SAAS,QAAQ;AAAA,QACrC;AACA,YAAI,MAAM,QAAQ,UAAU,GAAG;AAC7B,iBAAO,MAAM,QAAQ,QAAQ,IACzB,SAAS,MAAM,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC,IAC5C,WAAW,SAAS,QAAkB;AAAA,QAC5C;AACA,eAAO;AAAA,MACT;AAAA,MACA;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,eAAe,QAA0B,gBAAiE;AACxG,UAAM,UAAU,IAAI,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9D,UAAM,OAAO,oBAAI,IAAY;AAC7B,UAAM,WAA+B,CAAC;AACtC,eAAW,SAAS,QAAQ;AAC1B,iBAAW,YAAY,MAAM,OAAO;AAKlC,YAAI,SAAS,SAAS,GAAG,GAAG;AAC1B,gBAAM,SAAS,SAAS,MAAM,GAAG,EAAE;AACnC,qBAAWC,QAAO,gBAAgB;AAChC,gBAAI,CAACA,KAAI,KAAK,WAAW,MAAM,EAAG;AAClC,gBAAI,KAAK,IAAIA,KAAI,IAAI,EAAG;AACxB,qBAAS,KAAKA,IAAG;AACjB,iBAAK,IAAIA,KAAI,IAAI;AAAA,UACnB;AACA;AAAA,QACF;AACA,YAAI,KAAK,IAAI,QAAQ,EAAG;AACxB,cAAM,MAAM,QAAQ,IAAI,QAAQ;AAChC,YAAI,KAAK;AACP,mBAAS,KAAK,GAAG;AACjB,eAAK,IAAI,QAAQ;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,yBAAyB,QAAkC;AACzD,QAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,UAAM,QAAkB,CAAC,IAAI,uBAAuB;AACpD,eAAW,SAAS,QAAQ;AAC1B,YAAM,KAAK;AAAA,MAAS,MAAM,KAAK,KAAK,MAAM,IAAI,GAAG;AACjD,UAAI,MAAM,YAAa,OAAM,KAAK,MAAM,WAAW;AACnD,UAAI,MAAM,aAAc,OAAM,KAAK,MAAM,YAAY;AACrD,UAAI,MAAM,MAAM,SAAS,GAAG;AAC1B,cAAM,KAAK,UAAU,MAAM,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,MAC/C;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,OAA4B;AACpC,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,aAAa,MAAM;AAAA,MACnB,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM,MAAM;AAAA,IACzB;AAAA,EACF;AACF;;;AChPO,IAAM,kBAAyB;AAAA,EACpC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,cAAc;AAAA;AAAA;AAAA,EAId,OAAO;AAAA,IACL,UAAU;AAAA,IACV,OAAO;AAAA,IACP,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA;AAAA;AAAA,EAIA,QAAQ,CAAC,iBAAiB,kBAAkB;AAAA,EAE5C,QAAQ;AAAA,EACR,YAAY;AAAA,EAEZ,YAAY;AAAA,IACV,wBAAwB;AAAA,IACxB,qBAAqB;AAAA,IACrB,eAAe,CAAC,kBAAkB,cAAc,cAAc;AAAA,EAChE;AAAA,EAEA,UAAU;AAAA,IACR,UAAU;AAAA,IACV,eAAe;AAAA,IACf,aAAa;AAAA,EACf;AAAA,EAEA,QAAQ;AAAA,IACN,WAAW;AAAA,MACT,aAAa;AAAA,MACb,WAAW;AAAA,IACb;AAAA,EACF;AACF;;;AC5CO,IAAM,2BAAkC;AAAA,EAC7C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,cAAc;AAAA;AAAA;AAAA,EAId,OAAO;AAAA,IACL,UAAU;AAAA,IACV,OAAO;AAAA,IACP,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA;AAAA,EAGA,QAAQ,CAAC,oBAAoB;AAAA,EAE7B,QAAQ;AAAA,EACR,YAAY;AAAA,EAEZ,YAAY;AAAA,IACV,wBAAwB;AAAA,IACxB,qBAAqB;AAAA,IACrB,eAAe,CAAC,iBAAiB,WAAW,eAAe;AAAA,EAC7D;AAAA,EAEA,UAAU;AAAA,IACR,UAAU;AAAA,IACV,eAAe;AAAA,IACf,aAAa;AAAA,EACf;AAAA,EAEA,QAAQ;AAAA,IACN,WAAW;AAAA,MACT,aAAa;AAAA,MACb,WAAW;AAAA,IACb;AAAA,EACF;AACF;;;AChDO,IAAM,sBAA6B;AAAA,EACxC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBd,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AACV;;;ACxCO,IAAM,2BAAkC;AAAA,EAC7C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBd,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AACV;;;ACtCO,IAAM,yBAAgC;AAAA,EAC3C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aACE;AAAA,EAEF,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBd,OAAO,CAAC,UAAU;AAAA,EAClB,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AACV;;;AC/CA,IAAAC,aAAyF;AAQzF,SAAS,mBAAmB,SAAqD;AAC/E,MAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,QAAM,OAAgC,CAAC;AAEvC,MAAI,QAAQ,eAAe,KAAM,MAAK,cAAc,QAAQ;AAC5D,MAAI,QAAQ,aAAa,KAAM,MAAK,YAAY,QAAQ;AACxD,MAAI,QAAQ,MAAM,OAAQ,MAAK,gBAAgB,QAAQ;AAEvD,MAAI,QAAQ,OAAO,QAAQ;AACzB,UAAM,QAAiC,CAAC;AACxC,eAAW,KAAK,QAAQ,OAA6B;AACnD,YAAM,EAAE,IAAI,QAAI,WAAAC,MAAW;AAAA,QACzB,aAAa,EAAE;AAAA,QACf,iBAAa,uBAAW,EAAE,UAAiB;AAAA,MAC7C,CAAC;AAAA,IACH;AACA,SAAK,QAAQ;AAAA,EACf;AAEA,MAAI,QAAQ,cAAc,MAAM;AAC9B,SAAK,aAAa,QAAQ;AAAA,EAC5B;AAEA,SAAO;AACT;AAiBO,IAAM,mBAAN,MAA6C;AAAA,EAKlD,YAAY,QAAgC;AAJ5C,SAAS,OAAO;AAKd,SAAK,QAAQ,OAAO;AAAA,EACtB;AAAA,EAEA,MAAM,KAAK,UAA0B,SAA+C;AAClF,UAAM,SAAS,UAAM,yBAAa;AAAA,MAChC,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,GAAG,mBAAmB,OAAO;AAAA,IAC/B,CAAC;AAED,WAAO;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,OAAO,OAAO,UAAU;AAAA,MACxB,WAAW,OAAO,WAAW,SAAS,OAAO,YAAY;AAAA,MACzD,OAAO,OAAO,QAAQ;AAAA,QACpB,cAAc,OAAO,MAAM,eAAe;AAAA,QAC1C,kBAAkB,OAAO,MAAM,gBAAgB;AAAA,QAC/C,aAAa,OAAO,MAAM,eAAe;AAAA,MAC3C,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,QAAgB,SAA+C;AAC5E,UAAM,SAAS,UAAM,yBAAa;AAAA,MAChC,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,GAAG,mBAAmB,OAAO;AAAA,IAC/B,CAAC;AAED,WAAO;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,OAAO,OAAO,UAAU;AAAA,MACxB,OAAO,OAAO,QAAQ;AAAA,QACpB,cAAc,OAAO,MAAM,eAAe;AAAA,QAC1C,kBAAkB,OAAO,MAAM,gBAAgB;AAAA,QAC/C,aAAa,OAAO,MAAM,eAAe;AAAA,MAC3C,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EAEA,OAAO,WACL,UACA,SACwC;AACxC,UAAM,aAAS,uBAAW;AAAA,MACxB,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,GAAG,mBAAmB,OAAO;AAAA,IAC/B,CAAC;AAED,QAAI;AACF,uBAAiB,QAAQ,OAAO,YAAY;AAC1C,cAAM;AAAA,MACR;AAAA,IACF,SAAS,KAAK;AAGZ,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,QAAgD;AAE1D,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,UACA,QACA,SAC4B;AAC5B,UAAM,EAAE,YAAY,mBAAmB,GAAG,KAAK,IAAI,WAAW,CAAC;AAC/D,UAAM,SAAS,UAAM,2BAAe;AAAA,MAClC,OAAO,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,mBAAmB,IAAI;AAAA,IAC5B,CAAC;AAED,WAAO;AAAA,MACL,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO,UAAU;AAAA,MACxB,OAAO,OAAO,QAAQ;AAAA,QACpB,cAAc,OAAO,MAAM,eAAe;AAAA,QAC1C,kBAAkB,OAAO,MAAM,gBAAgB;AAAA,QAC/C,aAAa,OAAO,MAAM,eAAe;AAAA,MAC3C,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EAEA,MAAM,aAAgC;AAEpC,WAAO,CAAC;AAAA,EACV;AACF;;;AC5IO,IAAM,gBAAN,MAAoB;AAAA,EAIzB,YAAY,SAA8B,CAAC,GAAG;AAH9C,SAAiB,SAAS,oBAAI,IAA4B;AAIxD,eAAW,SAAS,OAAO,UAAU,CAAC,GAAG;AACvC,WAAK,OAAO,IAAI,MAAM,IAAI,KAAK;AAAA,IACjC;AACA,SAAK,iBAAiB,OAAO;AAAA,EAC/B;AAAA;AAAA,EAGA,SAAS,OAA6B;AACpC,SAAK,OAAO,IAAI,MAAM,IAAI,KAAK;AAAA,EACjC;AAAA;AAAA,EAGA,IAAI,IAAwC;AAC1C,WAAO,KAAK,OAAO,IAAI,EAAE;AAAA,EAC3B;AAAA;AAAA,EAGA,WAAW,IAA4B;AACrC,UAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR,kCAAkC,EAAE,kBAClC,CAAC,GAAG,KAAK,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI,KAAK,QACxC;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAyC;AACvC,QAAI,KAAK,gBAAgB;AACvB,aAAO,KAAK,OAAO,IAAI,KAAK,cAAc;AAAA,IAC5C;AACA,WAAO,KAAK,OAAO,OAAO,EAAE,KAAK,EAAE;AAAA,EACrC;AAAA;AAAA,EAGA,WAAW,IAAkB;AAC3B,SAAK,WAAW,EAAE;AAClB,SAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA,EAGA,OAAyB;AACvB,WAAO,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC;AAAA,EACjC;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAa,SAAiB,OAA6C;AACzE,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,OAAO,QAAS,QAAO;AAC5B,WAAO,YAAY,MAAM,SAAS,KAAK;AAAA,EACzC;AACF;AAiCO,SAAS,YAAY,SAA0B,OAAiC;AACrF,QAAM,YACJ,QAAQ,wBAAwB,OAC3B,MAAM,eAAe,MAAQ,QAAQ,uBACtC;AACN,QAAM,aACJ,QAAQ,yBAAyB,OAC5B,MAAM,mBAAmB,MAAQ,QAAQ,wBAC1C;AACN,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAW,YAAY;AAAA,IACvB,UAAU,QAAQ,YAAY;AAAA,EAChC;AACF;;;A1BhCO,IAAM,kBAAN,MAAwC;AAAA,EAS7C,YAAY,UAAkC,CAAC,GAAG;AARlD,gBAAO;AACP,mBAAU;AACV,gBAAO;AACP,wBAAyB,CAAC,iCAAiC;AAMzD,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,uBACZ,KACA,QAC8D;AAC9D,UAAM,WAAW,OAAO,OAAO,YAAY,QAAQ;AAEnD,QAAI,aAAa,UAAU;AACzB,aAAO,EAAE,SAAS,IAAI,iBAAiB,GAAG,aAAa,+BAA+B;AAAA,IACxF;AAEA,QAAI,aAAa,WAAW;AAC1B,YAAM,eAAe,OAAO,OAAO,iBAAiB,EAAE,EAAE,KAAK;AAC7D,UAAI,CAAC,aAAc,QAAO;AAC1B,UAAI;AACF,cAAM,aAAa;AACnB,cAAM,EAAE,QAAQ,IAAI,MAAM;AAAA;AAAA,UAAiC;AAAA;AAC3D,eAAO;AAAA,UACL,SAAS,IAAI,iBAAiB,EAAE,OAAO,QAAQ,YAAY,EAAE,CAAC;AAAA,UAC9D,aAAa,6BAA6B,YAAY;AAAA,QACxD;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,OAAO;AAAA,UACT;AAAA,UACA,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI;AAAA,QAClD;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,gBAA6G;AAAA,MACjH,QAAQ,EAAE,KAAK,kBAAkB,SAAS,UAAU,cAAc,UAAU,aAAa,SAAS;AAAA,MAClG,WAAW,EAAE,KAAK,qBAAqB,SAAS,aAAa,cAAc,4BAA4B,aAAa,YAAY;AAAA,MAChI,QAAQ,EAAE,KAAK,kBAAkB,SAAS,UAAU,cAAc,oBAAoB,aAAa,SAAS;AAAA,IAC9G;AACA,UAAM,OAAO,cAAc,QAAQ;AACnC,QAAI,CAAC,KAAM,QAAO;AAElB,UAAM,SAAS,OAAO,OAAO,GAAG,QAAQ,UAAU,KAAK,EAAE,EAAE,KAAK;AAChE,QAAI,CAAC,OAAQ,QAAO;AAMpB,UAAM,SACJ,aAAa,WAAW,mBACtB,aAAa,cAAc,sBAC3B;AACJ,YAAQ,IAAI,MAAM,IAAI;AAEtB,QAAI;AACF,YAAM,MAAM,MAAM;AAAA;AAAA,QAAiC,KAAK;AAAA;AACxD,YAAM,UAAU,IAAI,KAAK,OAAO,KAAK,IAAI;AACzC,UAAI,OAAO,YAAY,WAAY,QAAO;AAC1C,YAAM,UAAU,OAAO,OAAO,GAAG,QAAQ,QAAQ,KAAK,EAAE,EAAE,KAAK,KAAK,KAAK;AAEzE,YAAM,aAAa,aAAa,YAAY,OAAQ,QAAgB,SAAS;AAC7E,YAAM,QAAQ,aAAc,QAAgB,KAAK,OAAO,IAAI,QAAQ,OAAO;AAC3E,YAAM,YAAY,aAAa,wBAAwB;AACvD,aAAO;AAAA,QACL,SAAS,IAAI,iBAAiB,EAAE,MAAM,CAAC;AAAA,QACvC,aAAa,GAAG,KAAK,WAAW,YAAY,OAAO,IAAI,SAAS;AAAA,MAClE;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,OAAO;AAAA,QACT,uBAAuB,KAAK,GAAG,iBAAiB,QAAQ;AAAA,QACxD,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI;AAAA,MAClD;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAc,wBACZ,KACA,QAC8D;AAC9D,UAAM,WAAW,OAAO,OAAO,qBAAqB,MAAM,EAAE,KAAK;AACjE,QAAI,CAAC,YAAY,aAAa,OAAQ,QAAO;AAE7C,UAAM,SAAS,OAAO,OAAO,oBAAoB,EAAE,EAAE,KAAK;AAC1D,UAAM,QAAQ,OAAO,OAAO,kBAAkB,EAAE,EAAE,KAAK,KAAK;AAC5D,UAAM,kBAAkB,OAAO,OAAO,qBAAqB,EAAE,EAAE,KAAK,KAAK;AACzE,UAAM,aACJ,OAAO,uBAAuB,QAAQ,OAAO,wBAAwB,KACjE,OAAO,OAAO,mBAAmB,IACjC;AAIN,QAAI,CAAC,UAAU,aAAa,UAAU;AACpC,UAAI,OAAO;AAAA,QACT,0BAA0B,QAAQ;AAAA,MACpC;AACA,aAAO;AAAA,IACT;AACA,SAAK,aAAa,YAAY,aAAa,YAAY,CAAC,iBAAiB;AACvE,UAAI,OAAO;AAAA,QACT,0BAA0B,QAAQ;AAAA,MACpC;AACA,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,MAAM;AACZ,YAAM,MAAM,MAAM;AAAA;AAAA,QAAiC;AAAA;AACnD,YAAM,SAAS,IAAI,wBAAwB,IAAI,SAAS;AACxD,UAAI,OAAO,WAAW,YAAY;AAChC,YAAI,OAAO;AAAA,UACT,QAAQ,GAAG;AAAA,QACb;AACA,eAAO;AAAA,MACT;AACA,YAAM,WAAW,OAAO;AAAA,QACtB,QAAQ,aAAa,WAAW,SAAY;AAAA,QAC5C,SAAS;AAAA,QACT,QAAQ,UAAU;AAAA,QAClB;AAAA,QACA,YAAY,OAAO,SAAS,UAAU,IAAI,aAAa;AAAA,QACvD,IAAI;AAAA,MACN,CAAC;AACD,YAAM,YAAY,SAAS,aAAa,QAAQ,SAAS,UAAU,KAAK;AACxE,aAAO;AAAA,QACL;AAAA,QACA,aAAa,wCAAwC,QAAQ,GAAG,QAAQ,WAAW,KAAK,KAAK,EAAE,KAAK,SAAS;AAAA,MAC/G;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,OAAO;AAAA,QACT,0EAA0E,QAAQ;AAAA,QAClF,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI;AAAA,MAClD;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAc,cAAc,KAA2E;AAErG,UAAM,eAAe,QAAQ,IAAI;AACjC,QAAI,cAAc;AAChB,UAAI;AACF,cAAM,aAAa;AACnB,cAAM,EAAE,QAAQ,IAAI,MAAM;AAAA;AAAA,UAAiC;AAAA;AAC3D,cAAM,UAAU,IAAI,iBAAiB,EAAE,OAAO,QAAQ,YAAY,EAAE,CAAC;AACrE,eAAO,EAAE,SAAS,aAAa,6BAA6B,YAAY,IAAI;AAAA,MAC9E,SAAS,KAAK;AACZ,YAAI,OAAO;AAAA,UACT,4DAA4D,YAAY;AAAA,UACxE,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,kBAMD;AAAA,MACH;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,SAAS;AAAA,QACT,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,SAAS;AAAA,QACT,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,SAAS;AAAA,QACT,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,IACF;AAEA,eAAW,EAAE,QAAQ,KAAK,SAAS,cAAc,YAAY,KAAK,iBAAiB;AACjF,UAAI,QAAQ,IAAI,MAAM,GAAG;AACvB,YAAI;AACF,gBAAM,MAAM,MAAM;AAAA;AAAA,YAAiC;AAAA;AACnD,gBAAM,WAAW,IAAI,OAAO,KAAK,IAAI;AACrC,cAAI,OAAO,aAAa,YAAY;AAClC,kBAAM,UAAU,QAAQ,IAAI,YAAY;AASxC,kBAAM,aAAa,YAAY,YAAY,OAAQ,SAAiB,SAAS;AAC7E,kBAAM,QAAQ,aACT,SAAiB,KAAK,OAAO,IAC9B,SAAS,OAAO;AACpB,kBAAM,UAAU,IAAI,iBAAiB,EAAE,MAAM,CAAC;AAC9C,kBAAM,YAAY,aAAa,wBAAwB;AACvD,mBAAO,EAAE,SAAS,aAAa,GAAG,WAAW,YAAY,OAAO,IAAI,SAAS,GAAG;AAAA,UAClF;AAAA,QACF,SAAS,KAAK;AACZ,cAAI,OAAO;AAAA,YACT,uBAAuB,GAAG,QAAQ,MAAM;AAAA,YACxC,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI;AAAA,UAClD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,OAAO,KAAK,sNAAsN;AACtO,WAAO,EAAE,SAAS,IAAI,iBAAiB,GAAG,aAAa,kDAAkD;AAAA,EAC3G;AAAA,EAEA,MAAM,KAAK,KAAmC;AAE5C,QAAI,cAAc;AAClB,QAAI;AACF,YAAM,WAAW,IAAI,WAAuB,IAAI;AAChD,UAAI,YAAY,OAAO,SAAS,SAAS,YAAY;AACnD,sBAAc;AACd,YAAI,OAAO,MAAM,2CAA2C;AAAA,MAC9D;AAAA,IACF,QAAQ;AAAA,IAER;AAGA,QAAI,sBAA0D,KAAK,QAAQ;AAC3E,QAAI,CAAC,qBAAqB;AACxB,UAAI;AACF,cAAM,SAAS,IAAI,WAAwB,MAAM;AACjD,YAAI,UAAU,OAAO,OAAO,SAAS,YAAY;AAC/C,gCAAsB,IAAI,4BAA4B,MAAM;AAC5D,cAAI,OAAO,KAAK,+DAA+D;AAAA,QACjF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AAEJ,QAAI,KAAK,QAAQ,SAAS;AAExB,gBAAU,KAAK,QAAQ;AACvB,2BAAqB,GAAG,QAAQ,IAAI;AAAA,IACtC,OAAO;AAEL,YAAM,WAAW,MAAM,KAAK,cAAc,GAAG;AAC7C,gBAAU,SAAS;AACnB,2BAAqB,SAAS;AAAA,IAChC;AAGA,QAAI,OAAO,KAAK,2BAA2B,kBAAkB,EAAE;AAG/D,UAAM,gBAAgB,IAAI,cAAc;AAAA,MACtC,QAAQ,KAAK,QAAQ;AAAA,MACrB,gBAAgB,KAAK,QAAQ;AAAA,IAC/B,CAAC;AACD,QAAI,cAAc,OAAO,GAAG;AAC1B,UAAI,OAAO,KAAK,uCAAuC,cAAc,IAAI,WAAW;AAAA,IACtF;AAGA,QAAI;AACJ,QAAI;AACJ,QAAI;AACF,YAAM,SAAS,IAAI,WAAwB,MAAM;AACjD,UAAI,UAAU,OAAO,OAAO,WAAW,YAAY;AACjD,qBAAa;AAAA,MACf;AAAA,IACF,QAAQ;AAAA,IAER;AACA,QAAI,KAAK,QAAQ,kBAAkB,MAAM;AAEvC,UAAI,OAAO,MAAM,4CAA4C;AAAA,IAC/D,WAAW,KAAK,QAAQ,eAAe;AACrC,sBAAgB,KAAK,QAAQ;AAAA,IAC/B,WAAW,YAAY;AACrB,sBAAgB,IAAI,sBAAsB,YAAY,EAAE,QAAQ,IAAI,OAAO,CAAC;AAC5E,UAAI,OAAO,KAAK,yDAAyD;AAAA,IAC3E;AAEA,UAAM,SAA0B;AAAA,MAC9B;AAAA,MACA,QAAQ,IAAI;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,SAAK,UAAU,IAAI,UAAU,MAAM;AAGnC,QAAI,aAAa;AACf,UAAI,eAAe,MAAM,KAAK,OAAO;AAAA,IACvC,OAAO;AACL,UAAI,gBAAgB,MAAM,KAAK,OAAO;AAAA,IACxC;AAGA,QAAI,WAAuC,UAAU,EAAE,SAAS;AAAA,MAC9D,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW;AAAA,MACX,SAAS,CAAC,sBAAsB,iBAAiB,eAAe,qBAAqB;AAAA,MACrF,OAAO,CAAC,aAAa,mBAAmB;AAAA,IAC1C,CAAC;AAED,QAAI,KAAK,QAAQ,OAAO;AACtB,UAAI,KAAK,iBAAiB,OAAO,aAAsB;AACrD,YAAI,OAAO,MAAM,oBAAoB,EAAE,SAAS,CAAC;AAAA,MACnD,CAAC;AAAA,IACH;AAEA,QAAI,OAAO,KAAK,0BAA0B;AAAA,EAC5C;AAAA,EAEA,MAAM,MAAM,KAAmC;AAC7C,QAAI,CAAC,KAAK,QAAS;AAGnB,QAAI;AAEJ,UAAM,cAAc,CAAI,SAAqB,KAAK,QAChD,QAAQ,KAAK,CAAC,SAAS,IAAI,QAAc,aAAW,WAAW,MAAM,QAAQ,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;AAC3F,QAAI;AACF,wBAAkB,IAAI,WAA6B,UAAU;AAC7D,cAAQ,IAAI,2CAA2C,CAAC,CAAC,iBAAiB,2BAA2B,OAAQ,iBAAyB,kBAAkB;AAAA,IAC1J,SAAS,GAAQ;AACf,cAAQ,IAAI,wCAAwC,EAAE,OAAO;AAC7D,UAAI,OAAO,MAAM,qCAAqC;AAAA,IACxD;AAKA,QAAI,mBAAmB,OAAO,gBAAgB,WAAW,YAAY;AACnE,YAAM,cAAc,MAAM,YAAY,gBAAgB,OAAO,QAAQ,WAAW,GAAG,GAAI;AACvF,UAAI,gBAAgB,MAAM;AACxB,YAAI,OAAO,KAAK,kHAA6G;AAC7H,0BAAkB;AAAA,MACpB;AAAA,IACF;AAGA,QAAI;AACF,YAAM,aAAa,IAAI,WAAwB,MAAM;AACrD,UAAI,YAAY;AACd,0BAAkB,KAAK,QAAQ,cAAc,EAAE,WAAW,CAAC;AAC3D,YAAI,OAAO,KAAK,qCAAqC;AAIrD,YAAI,iBAAiB;AACnB,gCAAsB,KAAK,QAAQ,cAAc;AAAA,YAC/C,IAAI,KAAK;AAAA,YACT,UAAU;AAAA,YACV;AAAA,UACF,CAAC;AACD,cAAI,OAAO,KAAK,iCAAiC;AAOjD,cAAI;AAGF,gBAAI;AACJ,gBAAI;AACF,2BAAa,IAAI,WAA+B,YAAY;AAAA,YAC9D,QAAQ;AACN,2BAAa;AAAA,YACf;AACA,kBAAM,aACJ,KAAK,QAAQ,oBAAoB,QAAQ,IAAI;AAC/C,kBAAM,aAAa,KAAK,QAAQ;AAChC,kBAAM,EAAE,YAAY,QAAQ,IAAI,MAAM;AAAA,cACpC,KAAK,QAAQ;AAAA,cACb;AAAA,gBACE,UAAU;AAAA,gBACV;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,sBAAsB,KAAK,QAAQ,wBAAwB;AAAA,gBAC3D,WAAW,KAAK;AAAA,cAClB;AAAA,YACF;AACA,gBAAI,WAAW,SAAS,GAAG;AACzB,kBAAI,OAAO;AAAA,gBACT,QAAQ,WAAW,MAAM,+BAA+B,WAAW,KAAK,IAAI,CAAC;AAAA,cAC/E;AAAA,YACF;AACA,gBAAI,QAAQ,SAAS,GAAG;AACtB,kBAAI,OAAO;AAAA,gBACT,gBAAgB,QAAQ,MAAM;AAAA,gBAC9B,EAAE,QAAQ;AAAA,cACZ;AAAA,YACF;AAAA,UACF,SAAS,KAAK;AACZ,gBAAI,OAAO;AAAA,cACT;AAAA,cACA,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI,EAAE,OAAO,OAAO,GAAG,EAAE;AAAA,YACvE;AAAA,UACF;AAAA,QACF;AAGA,YAAI,iBAAiB;AACnB,gBAAM,EAAE,uBAAAC,uBAAsB,IAAI,MAAM;AACxC,qBAAW,WAAWA,wBAAuB;AAC3C,kBAAM,aACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,QAAQ,QAAQ,IAAI,CAAC,IAC9D;AAEN,gBAAI,eAAe,MAAM;AACvB,kBAAI,OAAO,KAAK,2FAA2F;AAC3G;AAAA,YACF;AAEA,gBAAI,CAAC,YAAY;AACf,kBAAI;AACF,sBAAM,YAAY,gBAAgB,SAAS,QAAQ,QAAQ,MAAM,OAAO,CAAC;AAAA,cAC3E,SAAS,KAAK;AACZ,oBAAI,OAAO;AAAA,kBAAK;AAAA,kBACd,eAAe,QAAQ,EAAE,MAAM,QAAQ,MAAM,OAAO,IAAI,QAAQ,IAAI,EAAE,MAAM,QAAQ,KAAK;AAAA,gBAAC;AAAA,cAC9F;AAAA,YACF;AAAA,UACF;AACA,cAAI,OAAO,KAAK,QAAQA,uBAAsB,MAAM,oCAAoC;AAAA,QAC1F;AAGA,YAAI,iBAAiB;AACnB,cAAI;AACF,kBAAM,cACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,SAAS,gBAAgB,IAAI,CAAC,IACvE;AAEN,gBAAI,gBAAgB,MAAM;AACxB,kBAAI,OAAO,KAAK,oEAAoE;AAAA,YACtF,WAAW,CAAC,aAAa;AACvB,oBAAM,YAAY,gBAAgB,SAAS,SAAS,gBAAgB,MAAM,eAAe,CAAC;AAC1F,sBAAQ,IAAI,oDAAoD;AAChE,kBAAI,OAAO,KAAK,iCAAiC;AAAA,YACnD,OAAO;AACL,sBAAQ,IAAI,+CAA+C;AAC3D,kBAAI,OAAO,MAAM,iEAAiE;AAAA,YACpF;AAAA,UACF,SAAS,KAAK;AACZ,gBAAI,OAAO,KAAK,2CAA2C,eAAe,QAAQ,EAAE,OAAO,IAAI,SAAS,OAAO,IAAI,MAAM,IAAI,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAAA,UACrJ;AAGA,cAAI;AACF,kBAAM,cACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,SAAS,oBAAoB,IAAI,CAAC,IAC3E;AAEN,gBAAI,gBAAgB,MAAM;AACxB,kBAAI,OAAO,KAAK,wEAAwE;AAAA,YAC1F,WAAW,CAAC,aAAa;AACvB,oBAAM,YAAY,gBAAgB,SAAS,SAAS,oBAAoB,MAAM,mBAAmB,CAAC;AAClG,kBAAI,OAAO,KAAK,qCAAqC;AAAA,YACvD,OAAO;AACL,kBAAI,OAAO,MAAM,qEAAqE;AAAA,YACxF;AAAA,UACF,SAAS,KAAK;AACZ,gBAAI,OAAO,KAAK,+CAA+C,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAAA,UACvI;AAGA,cAAI;AACF,kBAAM,cACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,SAAS,uBAAuB,IAAI,CAAC,IAC9E;AAEN,gBAAI,gBAAgB,MAAM;AACxB,kBAAI,OAAO,KAAK,2EAA2E;AAAA,YAC7F,WAAW,CAAC,aAAa;AACvB,oBAAM,YAAY,gBAAgB,SAAS,SAAS,uBAAuB,MAAM,sBAAsB,CAAC;AACxG,kBAAI,OAAO,KAAK,wCAAwC;AAAA,YAC1D,OAAO;AACL,kBAAI,OAAO,MAAM,wEAAwE;AAAA,YAC3F;AAAA,UACF,SAAS,KAAK;AACZ,gBAAI,OAAO,KAAK,kDAAkD,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAAA,UAC1I;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AACN,UAAI,OAAO,MAAM,qDAAqD;AAAA,IACxE;AAGA,QAAI,iBAAiB;AACnB,UAAI;AACF,8BAAsB,KAAK,QAAQ,cAAc,EAAE,gBAAgB,CAAC;AACpE,YAAI,OAAO,KAAK,yCAAyC;AAGzD,cAAM,EAAE,2BAAAC,2BAA0B,IAAI,MAAM;AAC5C,mBAAW,WAAWA,4BAA2B;AAC/C,gBAAM,aACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,QAAQ,QAAQ,IAAI,CAAC,IAC9D;AAEN,cAAI,eAAe,MAAM;AACvB,gBAAI,OAAO,KAAK,2FAA2F;AAC3G;AAAA,UACF;AAEA,cAAI,CAAC,YAAY;AACf,gBAAI;AACF,oBAAM,YAAY,gBAAgB,SAAS,QAAQ,QAAQ,MAAM,OAAO,CAAC;AAAA,YAC3E,SAAS,KAAK;AACZ,kBAAI,OAAO;AAAA,gBAAK;AAAA,gBACd,eAAe,QAAQ,EAAE,MAAM,QAAQ,MAAM,OAAO,IAAI,QAAQ,IAAI,EAAE,MAAM,QAAQ,KAAK;AAAA,cAAC;AAAA,YAC9F;AAAA,UACF;AAAA,QACF;AACA,YAAI,OAAO,KAAK,QAAQA,2BAA0B,MAAM,wCAAwC;AAGhG,YAAI;AACF,gBAAM,cACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,SAAS,yBAAyB,IAAI,CAAC,IAChF;AAEN,cAAI,gBAAgB,MAAM;AACxB,gBAAI,OAAO,KAAK,6EAA6E;AAAA,UAC/F,WAAW,CAAC,aAAa;AACvB,kBAAM,YAAY,gBAAgB,SAAS,SAAS,yBAAyB,MAAM,wBAAwB,CAAC;AAC5G,oBAAQ,IAAI,6DAA6D;AACzE,gBAAI,OAAO,KAAK,0CAA0C;AAAA,UAC5D,OAAO;AACL,oBAAQ,IAAI,wDAAwD;AACpE,gBAAI,OAAO,MAAM,0EAA0E;AAAA,UAC7F;AAAA,QACF,SAAS,KAAK;AACZ,cAAI,OAAO,KAAK,oDAAoD,eAAe,QAAQ,EAAE,OAAO,IAAI,SAAS,OAAO,IAAI,MAAM,IAAI,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAAA,QAC9J;AAGA,YAAI;AACF,gBAAM,cACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,SAAS,yBAAyB,IAAI,CAAC,IAChF;AAEN,cAAI,gBAAgB,MAAM;AACxB,gBAAI,OAAO,KAAK,6EAA6E;AAAA,UAC/F,WAAW,CAAC,aAAa;AACvB,kBAAM,YAAY,gBAAgB,SAAS,SAAS,yBAAyB,MAAM,wBAAwB,CAAC;AAC5G,gBAAI,OAAO,KAAK,0CAA0C;AAAA,UAC5D,OAAO;AACL,gBAAI,OAAO,MAAM,0EAA0E;AAAA,UAC7F;AAAA,QACF,SAAS,KAAK;AACZ,cAAI,OAAO,KAAK,oDAAoD,eAAe,QAAQ,EAAE,OAAO,IAAI,QAAQ,IAAI,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAAA,QAC5I;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,OAAO,MAAM,0CAA0C,eAAe,QAAQ,MAAM,MAAS;AAAA,MACnG;AAAA,IACF;AAGA,UAAM,IAAI,QAAQ,YAAY,KAAK,OAAO;AAS1C,QAAI,iBAAiB;AACnB,UAAI;AACF,cAAM,WAAW,IAAI,WAAgB,UAAU;AAC/C,cAAM,WAAW,UAAU;AAC3B,YAAI,YAAY,OAAO,SAAS,cAAc,YAAY;AACxD,gBAAM,cAAc,SAAS,UAAU,OAAO;AAC9C,cAAI,UAAU;AACd,qBAAW,SAAS,aAAa;AAC/B,kBAAM,QAAQ,OAAO,WAAW;AAChC,kBAAM,YAAY,OAAO;AACzB,gBAAI,CAAC,aAAa,OAAO,cAAc,SAAU;AACjD,kBAAM,SACJ,OAAO,gBAAgB,WAAW,aAC9B,MAAM,YAAY,gBAAgB,OAAO,SAAS,SAAS,CAAC,IAC5D;AACN,gBAAI,WAAW,KAAM;AACrB,gBAAI;AACF,oBAAM,YAAY,gBAAgB,SAAS,SAAS,WAAW,KAAK,CAAC;AACrE;AAAA,YACF,SAAS,KAAK;AACZ,kBAAI,OAAO;AAAA,gBACT;AAAA,gBACA,eAAe,QAAQ,EAAE,OAAO,WAAW,OAAO,IAAI,QAAQ,IAAI,EAAE,OAAO,UAAU;AAAA,cACvF;AAAA,YACF;AAAA,UACF;AACA,cAAI,UAAU,GAAG;AACf,gBAAI,OAAO,KAAK,gBAAgB,OAAO,gDAAgD;AACvF,oBAAQ,IAAI,gBAAgB,OAAO,gDAAgD;AAAA,UACrF;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,OAAO,MAAM,+DAA+D,eAAe,QAAQ,MAAM,MAAS;AAAA,MACxH;AAAA,IACF;AAGA,UAAM,SAAS,cAAc,KAAK,SAAS,KAAK,QAAQ,qBAAqB,IAAI,MAAM;AAGvF,UAAM,aAAa,gBAAgB,KAAK,SAAS,IAAI,MAAM;AAC3D,WAAO,KAAK,GAAG,UAAU;AACzB,QAAI,OAAO,KAAK,gCAAgC,WAAW,MAAM,UAAU;AAG3E,UAAM,gBAAgB,yBAAyB,KAAK,SAAS,IAAI,MAAM;AACvE,WAAO,KAAK,GAAG,aAAa;AAC5B,QAAI,OAAO,KAAK,0CAA0C,cAAc,MAAM,UAAU;AAGxF,QAAI,iBAAiB;AACnB,YAAM,gBAAgB,IAAI,cAAc,eAAe;AACvD,YAAM,eAAe,IAAI,aAAa,iBAAiB,aAAa;AACpE,YAAM,cAAc,iBAAiB,KAAK,SAAS,cAAc,IAAI,MAAM;AAC3E,aAAO,KAAK,GAAG,WAAW;AAC1B,UAAI,OAAO,KAAK,iCAAiC,YAAY,MAAM,UAAU;AAE7E,YAAM,kBAAkB,qBAAqB,KAAK,SAAS,cAAc,eAAe,IAAI,MAAM;AAClG,aAAO,KAAK,GAAG,eAAe;AAC9B,UAAI,OAAO,KAAK,+CAA+C,gBAAgB,MAAM,UAAU;AAAA,IACjG,OAAO;AACL,UAAI,OAAO,MAAM,0EAA0E;AAAA,IAC7F;AAGA,UAAM,IAAI,QAAQ,aAAa,MAAM;AAGrC,UAAM,SAAS,IAAI,UAAU;AAC7B,QAAI,QAAQ;AACV,MAAC,OAAe,aAAa;AAAA,IAC/B;AAEA,QAAI,OAAO;AAAA,MACT,wCAAmC,KAAK,QAAQ,WAAW,YAClD,KAAK,QAAQ,aAAa,IAAI,YAC7B,OAAO,MAAM;AAAA,IACzB;AAMA,QAAI,KAAK,QAAQ,mBAAmB,OAAO;AACzC,UAAI,KAAK,gBAAgB,YAAY;AACnC,cAAM,KAAK,aAAa,GAAG;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,aAAa,KAAmC;AAC5D,QAAI,CAAC,KAAK,QAAS;AACnB,QAAI;AACJ,QAAI;AACF,iBAAW,IAAI,WAAgB,UAAU;AAAA,IAC3C,QAAQ;AACN;AAAA,IACF;AACA,QAAI,CAAC,YAAY,OAAO,SAAS,iBAAiB,WAAY;AAE9D,UAAM,gBAAgB,YAA2B;AAC/C,UAAI,CAAC,KAAK,QAAS;AACnB,UAAI;AACF,cAAM,UAAU,MAAM,SAAS,aAAa,IAAI;AAChD,cAAM,SAAkC,CAAC;AACzC,mBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,MAA6B,GAAG;AAC1E,iBAAO,CAAC,IAAI,GAAG;AAAA,QACjB;AACA,cAAM,WAAW,OAAO,OAAO,YAAY,QAAQ;AAGnD,YAAI,aAAa,SAAU;AAC3B,cAAM,QAAQ,MAAM,KAAK,uBAAuB,KAAK,MAAM;AAC3D,YAAI,CAAC,OAAO;AACV,cAAI,OAAO;AAAA,YACT,0BAA0B,QAAQ,uFACD,KAAK,QAAQ,WAAW;AAAA,UAC3D;AACA;AAAA,QACF;AACA,aAAK,QAAQ,WAAW,MAAM,OAAO;AACrC,YAAI,OAAO,KAAK,uCAAuC,MAAM,WAAW,EAAE;AAAA,MAC5E,SAAS,KAAU;AACjB,YAAI,OAAO,KAAK,wCAAwC,KAAK,WAAW,IAAI;AAAA,MAC9E;AAAA,IACF;AAEA,UAAM,cAAc;AACpB,QAAI,OAAO,SAAS,cAAc,YAAY;AAC5C,eAAS,UAAU,MAAM,MAAM;AAAE,aAAK,cAAc;AAAA,MAAG,CAAC;AACxD,UAAI,OAAO,KAAK,iDAAiD;AAAA,IACnE;AAQA,QAAI,oBAAmC;AACvC,UAAM,gBAAgB,YAA2B;AAC/C,UAAI;AACF,cAAM,UAAU,MAAM,SAAS,aAAa,IAAI;AAChD,cAAM,SAAkC,CAAC;AACzC,mBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,MAA6B,GAAG;AAC1E,iBAAO,CAAC,IAAI,GAAG;AAAA,QACjB;AACA,cAAM,QAAQ,MAAM,KAAK,wBAAwB,KAAK,MAAM;AAC5D,YAAI,CAAC,OAAO;AACV,cAAI,sBAAsB,MAAM;AAC9B,gBAAI,OAAO,KAAK,oEAAoE;AACpF,gCAAoB;AAAA,UACtB;AACA;AAAA,QACF;AAEA,cAAM,UAAW,IAAY,kBAAkB,IAAI;AACnD,gBAAQ,KAAK,KAAK,mCAAkB,MAAM,QAAQ;AAClD,4BAAoB,MAAM,SAAS;AACnC,YAAI,OAAO,KAAK,2CAA2C,MAAM,WAAW,EAAE;AAAA,MAChF,SAAS,KAAU;AACjB,YAAI,OAAO,KAAK,8CAA8C,KAAK,WAAW,IAAI;AAAA,MACpF;AAAA,IACF;AAEA,UAAM,cAAc;AACpB,QAAI,OAAO,SAAS,cAAc,YAAY;AAC5C,eAAS,UAAU,MAAM,MAAM;AAAE,aAAK,cAAc;AAAA,MAAG,CAAC;AAAA,IAC1D;AAKA,QAAI,OAAO,SAAS,mBAAmB,YAAY;AACjD,eAAS,eAAe,MAAM,iBAAiB,OAAO,EAAE,QAAQ,QAAQ,MAAW;AACjF,cAAM,YACJ,WAAW,OAAO,YAAY,YAAY,YAAY,QAAQ,YAAY,UACrE,QAAiD,UAAU,CAAC,IAC7D,CAAC;AACP,cAAM,SAAkC,EAAE,GAAI,UAAU,CAAC,GAAI,GAAG,UAAU;AAC1E,cAAM,WAAW,OAAO,OAAO,qBAAqB,MAAM;AAC1D,YAAI,aAAa,QAAQ;AACvB,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS;AAAA,UACX;AAAA,QACF;AACA,YAAI;AACJ,YAAI;AACF,kBAAQ,MAAM,KAAK,wBAAwB,KAAK,MAAM;AAAA,QACxD,SAAS,KAAU;AACjB,iBAAO,EAAE,IAAI,OAAO,UAAU,SAAS,SAAS,KAAK,WAAW,OAAO,GAAG,EAAE;AAAA,QAC9E;AACA,YAAI,CAAC,OAAO;AACV,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS,yCAAyC,QAAQ;AAAA,UAC5D;AAAA,QACF;AACA,cAAM,UAAU,KAAK,IAAI;AACzB,YAAI;AACF,gBAAM,UAAU,MAAM,MAAM,SAAS,MAAM,CAAC,MAAM,CAAC;AACnD,gBAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,gBAAM,MAAM,QAAQ,CAAC,GAAG,UAAU;AAClC,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS,GAAG,MAAM,WAAW,iBAAiB,OAAO,mBAAmB,GAAG;AAAA,UAC7E;AAAA,QACF,SAAS,KAAU;AACjB,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS,GAAG,MAAM,WAAW,oBAAoB,KAAK,WAAW,OAAO,GAAG,CAAC;AAAA,UAC9E;AAAA,QACF;AAAA,MACF,CAAC;AACD,UAAI,OAAO,KAAK,uDAAuD;AAAA,IACzE;AAKA,QAAI,OAAO,SAAS,mBAAmB,YAAY;AACjD,eAAS,eAAe,MAAM,QAAQ,OAAO,EAAE,QAAQ,QAAQ,MAAW;AACxE,cAAM,YACJ,WAAW,OAAO,YAAY,YAAY,YAAY,QAAQ,YAAY,UACrE,QAAiD,UAAU,CAAC,IAC7D,CAAC;AACP,cAAM,SAAkC,EAAE,GAAI,UAAU,CAAC,GAAI,GAAG,UAAU;AAC1E,cAAM,WAAW,OAAO,OAAO,YAAY,QAAQ;AACnD,YAAI,aAAa,UAAU;AACzB,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS;AAAA,UACX;AAAA,QACF;AACA,YAAI;AACJ,YAAI;AACF,kBAAQ,MAAM,KAAK,uBAAuB,KAAK,MAAM;AAAA,QACvD,SAAS,KAAU;AACjB,iBAAO,EAAE,IAAI,OAAO,UAAU,SAAS,SAAS,KAAK,WAAW,OAAO,GAAG,EAAE;AAAA,QAC9E;AACA,YAAI,CAAC,OAAO;AACV,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS,wCAAwC,QAAQ;AAAA,UAC3D;AAAA,QACF;AACA,cAAM,UAAU,KAAK,IAAI;AACzB,YAAI;AACF,gBAAM,SAAS,MAAM,MAAM,QAAQ;AAAA,YACjC,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,YAClC,EAAE,WAAW,EAAE;AAAA,UACjB;AACA,gBAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,gBAAM,UAAU,OAAQ,QAAgB,QAAQ,EAAE,EAAE,MAAM,GAAG,EAAE;AAC/D,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS,GAAG,MAAM,WAAW,iBAAiB,OAAO,KAAK,UAAU,YAAO,OAAO,MAAM,EAAE;AAAA,UAC5F;AAAA,QACF,SAAS,KAAU;AACjB,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,YACV,SAAS,GAAG,MAAM,WAAW,oBAAoB,KAAK,WAAW,OAAO,GAAG,CAAC;AAAA,UAC9E;AAAA,QACF;AAAA,MACF,CAAC;AACD,UAAI,OAAO,KAAK,8CAA8C;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,SAAK,UAAU;AAAA,EACjB;AACF;;;AN3/BA;AAIA;;;AiCNA,IAAM,gBAAgB;AACtB,IAAM,YAAY;AAWlB,SAASC,oBAAmB,KAA8C;AACxE,MAAI,KAAK,OAAO;AACd,WAAO;AAAA,MACL,QAAQ,IAAI,MAAM;AAAA,MAClB,OAAO,IAAI,MAAM,SAAS,CAAC;AAAA,MAC3B,aAAa,IAAI,MAAM,eAAe,CAAC;AAAA,MACvC,UAAU;AAAA,MACV,GAAI,IAAI,gBAAgB,EAAE,UAAU,IAAI,cAAc,IAAI,CAAC;AAAA,MAC3D,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;AAAA,IAChD;AAAA,EACF;AACA,SAAO,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,GAAG,UAAU,KAAK;AACtD;AAEO,IAAM,wBAA0C;AAAA,EACrD,MAAM;AAAA,EACN,aACE;AAAA,EAKF,YAAY;AAAA,IACV,MAAM;AAAA,IACN,YAAY;AAAA,MACV,OAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,WAAW;AAAA,QACT,MAAM;AAAA,QACN,OAAO,EAAE,MAAM,SAAS;AAAA,QACxB,aACE;AAAA,MAEJ;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa,mCAAmC,aAAa,SAAS,SAAS;AAAA,MACjF;AAAA,MACA,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,aACE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,UAAU,CAAC,OAAO;AAAA,EACpB;AACF;AAEA,SAAS,6BAA6B,SAA4C;AAChF,SAAO,OAAO,MAAM,QAAQ;AAC1B,UAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;AACnE,QAAI,CAAC,OAAO;AACV,aAAO,KAAK,UAAU,EAAE,OAAO,yCAAyC,CAAC;AAAA,IAC3E;AAEA,UAAM,YAAY,MAAM,QAAQ,KAAK,SAAS,IAC1C,KAAK,UAAU,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,IAC/D;AACJ,UAAM,UAAU,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAC5D,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,KAAK,MAAM,OAAO,CAAC,CAAC;AACjE,UAAM,SACJ,KAAK,UAAU,OAAO,KAAK,WAAW,YAAY,CAAC,MAAM,QAAQ,KAAK,MAAM,IACvE,KAAK,SACN;AAEN,UAAM,OAA+B;AAAA,MACnC;AAAA,MACA,kBAAkBA,oBAAmB,GAAG;AAAA,IAC1C;AACA,QAAI,aAAa,UAAU,SAAS,EAAG,MAAK,YAAY;AACxD,QAAI,OAAQ,MAAK,SAAS;AAE1B,QAAI;AACF,YAAM,OAAO,MAAM,QAAQ,iBAAiB,OAAO,OAAO,IAAI;AAC9D,aAAO,KAAK,UAAU;AAAA,QACpB;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK,IAAI,CAAC,OAAO;AAAA,UACrB,YAAY,EAAE;AAAA,UACd,SAAS,EAAE;AAAA,UACX,UAAU,EAAE;AAAA,UACZ,gBAAgB,EAAE;AAAA,UAClB,OAAO,OAAO,EAAE,OAAO,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC;AAAA,UACnD,OAAO,EAAE;AAAA,UACT,SAAS,EAAE;AAAA,UACX,UAAU,EAAE;AAAA,QACd,EAAE;AAAA,MACJ,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,4BAA4B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACrF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAaO,SAAS,uBACd,UACA,SACM;AACN,WAAS,SAAS,uBAAuB,6BAA6B,OAAO,CAAC;AAChF;;;AjChHA;;;AkCtCA,IAAAC,cAA2B;AAQpB,IAAM,uBAAmB,wBAAW;AAAA,EACzC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aACE;AAAA,EAEF,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,IACV,MAAM;AAAA,IACN,YAAY;AAAA,MACV,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,aAAa;AAAA,QACb,MAAM,CAAC,aAAa,YAAY,cAAc,aAAa,gBAAgB,OAAO;AAAA,MACpF;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA,EACxB;AACF,CAAC;;;AC/BD,IAAAC,cAA2B;AAOpB,IAAM,qBAAiB,wBAAW;AAAA,EACvC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aACE;AAAA,EAEF,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,IACV,MAAM;AAAA,IACN,YAAY;AAAA,MACV,WAAW;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,WAAW;AAAA,IACtB,sBAAsB;AAAA,EACxB;AACF,CAAC;;;AC1BD,IAAAC,cAA2B;AAQpB,IAAM,wBAAoB,wBAAW;AAAA,EAC1C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aACE;AAAA,EAGF,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,IACV,MAAM;AAAA,IACN,YAAY;AAAA,MACV,IAAI;AAAA,QACF,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,aAAa;AAAA,QACX,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,WAAW;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,QACb,MAAM,CAAC,eAAe,UAAU,WAAW,UAAU;AAAA,QACrD,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,UAAU,CAAC,MAAM,MAAM;AAAA,IACvB,sBAAsB;AAAA,EACxB;AACF,CAAC;;;ACnDD,IAAAC,cAA2B;AAOpB,IAAM,2BAAuB,wBAAW;AAAA,EAC7C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aACE;AAAA,EAEF,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,IACV,MAAM;AAAA,IACN,YAAY,CAAC;AAAA,IACb,sBAAsB;AAAA,EACxB;AACF,CAAC;;;ACpBD,IAAAC,cAA2B;AAQpB,IAAM,2BAAuB,wBAAW;AAAA,EAC7C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aACE;AAAA,EAEF,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,IACV,MAAM;AAAA,IACN,YAAY;AAAA,MACV,WAAW;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,WAAW;AAAA,IACtB,sBAAsB;AAAA,EACxB;AACF,CAAC;;;ACLM,IAAM,2BAAmC;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAiEA,IAAM,oBAAoB;AAG1B,IAAMC,iBAAgB;AAGtB,IAAM,YAAY;AAKlB,SAAS,gBAAgB,OAAwB;AAC/C,SAAO,kBAAkB,KAAK,KAAK;AACrC;AAKA,SAASC,aAAY,OAAwB;AAC3C,SAAOD,eAAc,KAAK,KAAK;AACjC;AAKA,SAAS,SAAS,OAAwB;AACxC,SAAO,UAAU,KAAK,KAAK;AAC7B;AAMA,SAAS,gBAAgB,WAA2B;AAClD,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,SAAO,MAAM,MAAM,SAAS,CAAC;AAC/B;AAMA,SAAS,0BAA0B,KAAsC;AACvE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,QAAQ,QAAQ,IAAK,QAAQ,CAAC;AAKtC,UAAM,SAAiD,CAAC;AACxD,QAAI,OAAQ,QAAO,SAAS;AAC5B,QAAI,YAAY,OAAW,QAAO,UAAU;AAE5C,UAAM,WAAW,MAAM,IAAI,gBAAgB,KAAK,MAAM;AAEtD,UAAM,SAAS,SAAS,IAAI,UAAQ;AAAA,MAClC,IAAI,IAAI,SAAS;AAAA,MACjB,MAAM,IAAI,SAAS;AAAA,MACnB,SAAS,IAAI,SAAS;AAAA,MACtB,MAAM,IAAI,SAAS;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,MACb,aAAa,IAAI;AAAA,MACjB,aAAa,IAAI,SAAS;AAAA,IAC5B,EAAE;AAEF,WAAO,KAAK,UAAU;AAAA,MACpB,UAAU;AAAA,MACV,OAAO,OAAO;AAAA,IAChB,CAAC;AAAA,EACH;AACF;AAEA,SAAS,wBAAwB,KAAsC;AACrE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,UAAU,IAAI;AAEtB,QAAI,CAAC,WAAW;AACd,aAAO,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC;AAAA,IAC1D;AAEA,UAAM,MAAM,MAAM,IAAI,gBAAgB,IAAI,SAAS;AAEnD,QAAI,CAAC,KAAK;AACR,aAAO,KAAK,UAAU,EAAE,OAAO,YAAY,SAAS,cAAc,CAAC;AAAA,IACrE;AAEA,WAAO,KAAK,UAAU;AAAA,MACpB,IAAI,IAAI,SAAS;AAAA,MACjB,MAAM,IAAI,SAAS;AAAA,MACnB,SAAS,IAAI,SAAS;AAAA,MACtB,MAAM,IAAI,SAAS;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,MACb,aAAa,IAAI;AAAA,MACjB,WAAW,IAAI;AAAA,MACf,aAAa,IAAI,SAAS;AAAA,MAC1B,WAAW,IAAI,SAAS;AAAA,MACxB,cAAc,IAAI,SAAS;AAAA,MAC3B,sBAAsB,IAAI;AAAA,IAC5B,CAAC;AAAA,EACH;AACF;AAEA,SAAS,2BAA2B,KAAsC;AACxE,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,IAAI,MAAM,UAAU,SAAS,aAAa,WAAW,OAAO,cAAc,IAAI;AAUtF,QAAI,CAAC,MAAM,CAAC,MAAM;AAChB,aAAO,KAAK,UAAU,EAAE,OAAO,oCAAoC,CAAC;AAAA,IACtE;AAGA,QAAI,CAAC,gBAAgB,EAAE,GAAG;AACxB,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,uBAAuB,EAAE;AAAA,MAClC,CAAC;AAAA,IACH;AAGA,QAAI,CAAC,SAAS,OAAO,GAAG;AACtB,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,oBAAoB,OAAO;AAAA,MACpC,CAAC;AAAA,IACH;AAGA,UAAM,SAAS,MAAM,IAAI,gBAAgB,OAAO,EAAE;AAClD,QAAI,QAAQ;AACV,aAAO,KAAK,UAAU,EAAE,OAAO,YAAY,EAAE,mBAAmB,CAAC;AAAA,IACnE;AAGA,UAAM,mBAAmB,aAAa,gBAAgB,EAAE;AACxD,QAAI,CAACC,aAAY,gBAAgB,GAAG;AAClC,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,sBAAsB,gBAAgB;AAAA,MAC/C,CAAC;AAAA,IACH;AAGA,UAAM,WAAoC;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,IACvC;AAGA,UAAM,mBAAmB,MAAM,IAAI,gBAAgB,QAAQ,QAAQ;AAGnE,QAAI,IAAI,uBAAuB,IAAI,gBAAgB;AACjD,UAAI;AACF,cAAM,IAAI,oBAAoB,iBAAiB,IAAI,gBAAgB;AAAA,UACjE,iBAAiB;AAAA,QACnB,CAAC;AAAA,MACH,SAAS,KAAK;AAEZ,gBAAQ,KAAK,iDAAiD,GAAG;AAAA,MACnE;AAAA,IACF;AAEA,WAAO,KAAK,UAAU;AAAA,MACpB,WAAW,iBAAiB,SAAS;AAAA,MACrC,MAAM,iBAAiB,SAAS;AAAA,MAChC,SAAS,iBAAiB,SAAS;AAAA,MACnC,WAAW,iBAAiB,SAAS;AAAA,MACrC,QAAQ,iBAAiB;AAAA,MACzB,SAAS,YAAY,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AACF;AAEA,SAAS,8BAA8B,KAAsC;AAC3E,SAAO,YAAY;AAEjB,QAAI,CAAC,IAAI,uBAAuB,CAAC,IAAI,gBAAgB;AACnD,aAAO,KAAK,UAAU;AAAA,QACpB,iBAAiB;AAAA,QACjB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,IAAI,oBAAoB,cAAc,IAAI,cAAc;AAC/E,YAAM,kBAAkB,UAAU;AAElC,UAAI,CAAC,iBAAiB;AACpB,eAAO,KAAK,UAAU;AAAA,UACpB,iBAAiB;AAAA,UACjB,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAGA,YAAM,MAAM,MAAM,IAAI,gBAAgB,IAAI,eAAe;AAEzD,UAAI,CAAC,KAAK;AACR,eAAO,KAAK,UAAU;AAAA,UACpB;AAAA,UACA,OAAO,mBAAmB,eAAe;AAAA,QAC3C,CAAC;AAAA,MACH;AAEA,aAAO,KAAK,UAAU;AAAA,QACpB,iBAAiB,IAAI,SAAS;AAAA,QAC9B,MAAM,IAAI,SAAS;AAAA,QACnB,SAAS,IAAI,SAAS;AAAA,QACtB,WAAW,IAAI,SAAS;AAAA,QACxB,MAAM,IAAI,SAAS;AAAA,MACrB,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,iCAAkC,IAAc,OAAO;AAAA,MAChE,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,8BAA8B,KAAsC;AAC3E,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,UAAU,IAAI;AAEtB,QAAI,CAAC,WAAW;AACd,aAAO,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC;AAAA,IAC1D;AAGA,UAAM,MAAM,MAAM,IAAI,gBAAgB,IAAI,SAAS;AACnD,QAAI,CAAC,KAAK;AACR,aAAO,KAAK,UAAU,EAAE,OAAO,YAAY,SAAS,cAAc,CAAC;AAAA,IACrE;AAGA,QAAI,CAAC,IAAI,uBAAuB,CAAC,IAAI,gBAAgB;AACnD,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI;AACF,YAAM,IAAI,oBAAoB,iBAAiB,IAAI,gBAAgB;AAAA,QACjE,iBAAiB;AAAA,MACnB,CAAC;AAED,aAAO,KAAK,UAAU;AAAA,QACpB,iBAAiB;AAAA,QACjB,MAAM,IAAI,SAAS;AAAA,QACnB,WAAW,IAAI,SAAS;AAAA,QACxB,SAAS,0BAA0B,IAAI,SAAS,IAAI;AAAA,MACtD,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,iCAAkC,IAAc,OAAO;AAAA,MAChE,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAuBO,SAAS,qBACd,UACA,SACM;AACN,WAAS,SAAS,kBAAkB,0BAA0B,OAAO,CAAC;AACtE,WAAS,SAAS,gBAAgB,wBAAwB,OAAO,CAAC;AAClE,WAAS,SAAS,mBAAmB,2BAA2B,OAAO,CAAC;AACxE,WAAS,SAAS,sBAAsB,8BAA8B,OAAO,CAAC;AAC9E,WAAS,SAAS,sBAAsB,8BAA8B,OAAO,CAAC;AAChF;","names":["import_ai","import_ai","import_ai","import_ai","import_ai","result","import_node_crypto","import_data","import_data","import_data","import_spec","import_ai","import_ai","def","import_ai","vercelTool","DATA_TOOL_DEFINITIONS","METADATA_TOOL_DEFINITIONS","buildEngineContext","import_ai","import_ai","import_ai","import_ai","import_ai","SNAKE_CASE_RE","isSnakeCase"]}