@objectstack/service-ai 6.0.0 → 6.2.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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AIToolDefinition, ToolCallPart, ToolResultPart, IDataEngine, Logger, IAIService, IAIConversationService, LLMAdapter, ModelMessage, AIRequestOptions, AIResult, GenerateObjectOptions, AIObjectResult, TextStreamPart, ToolSet, ChatWithToolsOptions, AIConversation, IMetadataService } from '@objectstack/spec/contracts';
1
+ import { AIToolDefinition, ToolCallPart, ToolResultPart, IDataEngine, Logger, IAIService, IAIConversationService, LLMAdapter, ModelMessage, AIRequestOptions, AIResult, GenerateObjectOptions, AIObjectResult, TextStreamPart, ToolSet, ChatWithToolsOptions, ProposePendingActionInput, PendingActionStatus, PendingActionRow, AIConversation, IMetadataService, IAutomationService } from '@objectstack/spec/contracts';
2
2
  export { LLMAdapter } from '@objectstack/spec/contracts';
3
3
  import { z } from 'zod';
4
4
  import * as AI from '@objectstack/spec/ai';
@@ -7,6 +7,7 @@ import { Plugin, PluginContext } from '@objectstack/core';
7
7
  import { LanguageModelV2 } from '@ai-sdk/provider';
8
8
  import { TextStreamPart as TextStreamPart$1, ToolSet as ToolSet$1 } from 'ai';
9
9
  import { InstalledPackage } from '@objectstack/spec/kernel';
10
+ import { Action } from '@objectstack/spec/ui';
10
11
  import * as _objectstack_spec_data from '@objectstack/spec/data';
11
12
 
12
13
  /**
@@ -257,6 +258,13 @@ interface AIServiceConfig {
257
258
  modelRegistry?: ModelRegistry;
258
259
  /** Trace recorder for per-call observability. Defaults to no-op. */
259
260
  traceRecorder?: TraceRecorder;
261
+ /**
262
+ * Data engine used to persist `ai_pending_actions` rows for the
263
+ * actions-as-tools HITL queue. Optional — when omitted, the
264
+ * `proposePendingAction` / `approvePendingAction` methods throw if
265
+ * called. Wired by `AIServicePlugin` after the data driver is up.
266
+ */
267
+ dataEngine?: IDataEngine;
260
268
  }
261
269
  /**
262
270
  * AIService — Unified AI capability service.
@@ -280,6 +288,15 @@ declare class AIService implements IAIService {
280
288
  readonly conversationService: IAIConversationService;
281
289
  readonly modelRegistry?: ModelRegistry;
282
290
  readonly traceRecorder: TraceRecorder;
291
+ /**
292
+ * Map of tool-name → dispatcher used to re-run an approved pending
293
+ * action. Populated by `registerActionsAsTools()` when action
294
+ * approval is enabled. Kept private because callers should go
295
+ * through `approvePendingAction()`.
296
+ */
297
+ private readonly pendingDispatchers;
298
+ /** Data engine for `ai_pending_actions` persistence. */
299
+ private readonly dataEngine?;
283
300
  constructor(config?: AIServiceConfig);
284
301
  /** The name of the active LLM adapter. */
285
302
  get adapterName(): string;
@@ -325,6 +342,7 @@ declare class AIService implements IAIService {
325
342
  * maximum number of iterations (`maxIterations`) is reached.
326
343
  */
327
344
  chatWithTools(messages: ModelMessage[], options?: ChatWithToolsOptions): Promise<AIResult>;
345
+ private chatWithToolsImpl;
328
346
  /**
329
347
  * Stream chat with automatic tool call resolution.
330
348
  *
@@ -333,6 +351,29 @@ declare class AIService implements IAIService {
333
351
  * fed back until a final text stream is produced.
334
352
  */
335
353
  streamChatWithTools(messages: ModelMessage[], options?: ChatWithToolsOptions): AsyncIterable<TextStreamPart<ToolSet>>;
354
+ /**
355
+ * Register a dispatcher callback for a tool. Called by
356
+ * `registerActionsAsTools()` when action approval is enabled so the
357
+ * approval handler can re-run the exact same code path the LLM
358
+ * would have triggered.
359
+ */
360
+ registerPendingActionDispatcher(toolName: string, dispatch: (input: Record<string, unknown>) => Promise<unknown>): void;
361
+ proposePendingAction(input: ProposePendingActionInput): Promise<{
362
+ id: string;
363
+ }>;
364
+ approvePendingAction(id: string, actorId: string): Promise<{
365
+ status: 'executed' | 'failed';
366
+ result?: unknown;
367
+ error?: string;
368
+ }>;
369
+ rejectPendingAction(id: string, actorId: string, reason?: string): Promise<void>;
370
+ listPendingActions(filter?: {
371
+ status?: PendingActionStatus | PendingActionStatus[];
372
+ conversationId?: string;
373
+ objectName?: string;
374
+ limit?: number;
375
+ }): Promise<PendingActionRow[]>;
376
+ private loadPendingRow;
336
377
  }
337
378
 
338
379
  /**
@@ -354,6 +395,12 @@ interface AIServicePluginOptions {
354
395
  models?: AI.ModelConfig[];
355
396
  /** Default model id (must appear in `models`). */
356
397
  defaultModelId?: string;
398
+ /**
399
+ * Explicit trace recorder override. When set, auto-detection
400
+ * of {@link ObjectQLTraceRecorder} is skipped.
401
+ *
402
+ * Set to `null` to disable tracing entirely.
403
+ */
357
404
  /**
358
405
  * Explicit trace recorder override. When set, auto-detection
359
406
  * of {@link ObjectQLTraceRecorder} is skipped.
@@ -361,6 +408,31 @@ interface AIServicePluginOptions {
361
408
  * Set to `null` to disable tracing entirely.
362
409
  */
363
410
  traceRecorder?: TraceRecorder | null;
411
+ /**
412
+ * Base URL prepended to relative `target` paths for `type:'api'`
413
+ * actions invoked by the AI tool runtime. When unset, falls back to
414
+ * `process.env.OS_AI_ACTION_API_BASE_URL`. If neither is set, api
415
+ * actions are skipped at registration with a clear reason.
416
+ */
417
+ apiActionBaseUrl?: string;
418
+ /**
419
+ * Extra HTTP headers (e.g. `{ Authorization: 'Bearer ...' }`) applied
420
+ * to every `type:'api'` action dispatch. Useful for forwarding the
421
+ * caller's session token so server-side authorization still applies.
422
+ */
423
+ apiActionHeaders?: Record<string, string>;
424
+ /**
425
+ * Opt into Human-In-The-Loop approval for dangerous actions exposed
426
+ * as AI tools. When `true`, actions with `confirmText`, `mode:'delete'`,
427
+ * or `variant:'danger'` are still registered as tools — but invoking
428
+ * them enqueues an `ai_pending_actions` row and returns
429
+ * `{ status: 'pending_approval' }` instead of running. A human
430
+ * operator approves via Studio's pending-actions inbox to execute.
431
+ *
432
+ * Defaults to `false` (safer: dangerous actions stay invisible to LLM
433
+ * until an operator explicitly enables this routing).
434
+ */
435
+ enableActionApproval?: boolean;
364
436
  }
365
437
  /**
366
438
  * AIServicePlugin — Kernel plugin for the unified AI capability service.
@@ -937,6 +1009,163 @@ interface PackageToolContext {
937
1009
  */
938
1010
  declare function registerPackageTools(registry: ToolRegistry, context: PackageToolContext): void;
939
1011
 
1012
+ /**
1013
+ * Actions-as-Tools — turn declarative {@link Action} metadata into
1014
+ * AI-callable tools so an agent can not only **read** the user's data
1015
+ * (via `query_data` / `data_explorer`) but also **act** on it.
1016
+ *
1017
+ * Phase 1 scope (this module):
1018
+ * - Only `type: 'script'` actions are auto-exposed. Their handler is
1019
+ * resolved through {@link IDataEngine.executeAction} (the same
1020
+ * dispatcher used by Studio's "row toolbar" buttons), so the LLM
1021
+ * ends up calling exactly the same business logic the UI does.
1022
+ * - Skip any action that is dangerous (`confirmText`, `variant: 'danger'`,
1023
+ * `mode: 'delete'`) — these require Phase 2 HITL plumbing.
1024
+ * - Skip any action whose owner opted out via `aiExposed: false` (the
1025
+ * hint is read from the action record but not formalised in the Zod
1026
+ * schema yet; spec change is backwards-compatible additive).
1027
+ *
1028
+ * The tool's JSON Schema is materialised from `action.params[]`,
1029
+ * resolving field-backed params (`{ field: 'priority' }`) against the
1030
+ * owning object so the LLM sees the same type/options/required
1031
+ * constraints the modal dialog would render.
1032
+ */
1033
+
1034
+ /** Minimal field shape we care about when resolving param types. */
1035
+ interface FieldDef {
1036
+ type?: string;
1037
+ label?: string;
1038
+ required?: boolean;
1039
+ options?: Array<{
1040
+ value: string;
1041
+ label?: unknown;
1042
+ } | string>;
1043
+ description?: string;
1044
+ }
1045
+ /** Minimal object shape — same as what {@link SchemaRetriever} consumes. */
1046
+ interface ObjectDef {
1047
+ name: string;
1048
+ label?: string;
1049
+ pluralLabel?: string;
1050
+ fields?: Record<string, FieldDef>;
1051
+ actions?: Action[];
1052
+ }
1053
+ /**
1054
+ * Dependencies needed to invoke an Action from the AI tool runtime.
1055
+ *
1056
+ * The `metadata` service is used at registration time to resolve param
1057
+ * field types; the `dataEngine` is used at call time to (a) load the
1058
+ * subject record when a `recordIdParam` is configured and (b) dispatch
1059
+ * to the registered handler via `executeAction`.
1060
+ *
1061
+ * `automation` enables `type:'flow'` actions to dispatch into the
1062
+ * automation service's flow runner. When omitted, flow actions are
1063
+ * skipped at registration time with a clear reason.
1064
+ *
1065
+ * `apiClient` (or `apiBaseUrl`) enables `type:'api'` actions to perform
1066
+ * an HTTP call to the action's `target` URL. The default client uses
1067
+ * the global `fetch` and prepends `apiBaseUrl` to relative `target`s.
1068
+ * Supply a custom client when you need bespoke auth, in-process
1069
+ * routing, or stubbing in tests.
1070
+ *
1071
+ * `principal` lets callers attribute AI-initiated mutations to a known
1072
+ * user id; it defaults to a synthetic `'ai_agent'` user so traces /
1073
+ * audit always have *some* actor.
1074
+ */
1075
+ interface ActionToolsContext {
1076
+ metadata: IMetadataService;
1077
+ dataEngine: IDataEngine;
1078
+ /** Automation service for `type:'flow'` action dispatch. Optional. */
1079
+ automation?: IAutomationService;
1080
+ /** Custom API client for `type:'api'` actions. Defaults to a fetch-based client. */
1081
+ apiClient?: ApiActionClient;
1082
+ /** Base URL prepended to relative `target` paths for `type:'api'` actions. */
1083
+ apiBaseUrl?: string;
1084
+ /** Extra HTTP headers (e.g. auth bearer) applied to every `type:'api'` call. */
1085
+ apiHeaders?: Record<string, string>;
1086
+ /** Synthetic user attribution for AI-initiated calls. */
1087
+ principal?: {
1088
+ id: string;
1089
+ name?: string;
1090
+ };
1091
+ /** Tool-name prefix (default: `action_`). Keeps namespace separate from data tools. */
1092
+ toolPrefix?: string;
1093
+ /**
1094
+ * AI service used to enqueue HITL approvals for dangerous actions.
1095
+ * When supplied together with `enableActionApproval: true`, actions
1096
+ * that would otherwise be skipped on safety grounds (`confirmText`,
1097
+ * `mode:'delete'`, `variant:'danger'`) are registered as tools whose
1098
+ * handler proposes a pending action and returns
1099
+ * `{ status: 'pending_approval' }` instead of executing.
1100
+ */
1101
+ aiService?: {
1102
+ proposePendingAction?: (input: {
1103
+ objectName: string;
1104
+ actionName: string;
1105
+ toolName: string;
1106
+ toolInput: Record<string, unknown>;
1107
+ conversationId?: string;
1108
+ messageId?: string;
1109
+ proposedBy?: string;
1110
+ }) => Promise<{
1111
+ id: string;
1112
+ }>;
1113
+ registerPendingActionDispatcher?: (toolName: string, dispatch: (input: Record<string, unknown>) => Promise<unknown>) => void;
1114
+ };
1115
+ /**
1116
+ * Opt into the HITL approval queue for dangerous actions. Default
1117
+ * is `false` (safer: dangerous actions stay invisible to the LLM
1118
+ * until an operator explicitly enables approval routing).
1119
+ */
1120
+ enableActionApproval?: boolean;
1121
+ }
1122
+ /**
1123
+ * Minimal HTTP client shape used by `type:'api'` action dispatch.
1124
+ *
1125
+ * Implementations are expected to return a JSON-deserialised body (or
1126
+ * `null` for empty responses) on 2xx, and throw on non-2xx so the tool
1127
+ * surfaces the failure to the LLM as a tool error.
1128
+ */
1129
+ interface ApiActionClient {
1130
+ request(input: {
1131
+ url: string;
1132
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
1133
+ body?: Record<string, unknown>;
1134
+ headers?: Record<string, string>;
1135
+ }): Promise<unknown>;
1136
+ }
1137
+ declare function actionSkipReason(action: Action, ctx?: {
1138
+ automation?: IAutomationService;
1139
+ apiClient?: ApiActionClient;
1140
+ apiBaseUrl?: string;
1141
+ enableActionApproval?: boolean;
1142
+ aiService?: ActionToolsContext['aiService'];
1143
+ }): string | null;
1144
+ /** Compute the AI tool name for a given action (prefixed for namespacing). */
1145
+ declare function actionToolName(action: Action, prefix?: string): string;
1146
+ /**
1147
+ * Convert a single {@link Action} into a complete {@link AIToolDefinition}.
1148
+ *
1149
+ * Returns `null` when the action is filtered out by {@link actionSkipReason}.
1150
+ */
1151
+ declare function actionToToolDefinition(action: Action, ownerObject: ObjectDef | undefined, allObjects: Map<string, ObjectDef>, toolPrefix?: string): AIToolDefinition | null;
1152
+ /**
1153
+ * Walk every registered object in the {@link IMetadataService}, pick out
1154
+ * each object's actions, and register the ones that pass {@link actionSkipReason}
1155
+ * as AI tools.
1156
+ *
1157
+ * Returns the list of registered tool names and a parallel list of
1158
+ * `{ action, reason }` for actions that were intentionally skipped —
1159
+ * useful for Studio's "AI exposure" diagnostics surface.
1160
+ */
1161
+ declare function registerActionsAsTools(registry: ToolRegistry, context: ActionToolsContext): Promise<{
1162
+ registered: string[];
1163
+ skipped: Array<{
1164
+ action: string;
1165
+ reason: string;
1166
+ }>;
1167
+ }>;
1168
+
940
1169
  /**
941
1170
  * Runtime context passed when chatting with the ambient assistant.
942
1171
  *
@@ -1229,6 +1458,58 @@ declare const DATA_CHAT_AGENT: Agent;
1229
1458
  */
1230
1459
  declare const METADATA_ASSISTANT_AGENT: Agent;
1231
1460
 
1461
+ /**
1462
+ * Built-in `data_explorer` skill — the read-only data-Q&A capability
1463
+ * bundle that the `data_chat` agent (and any other agent that wants
1464
+ * data-exploration powers) attaches to its `skills[]`.
1465
+ *
1466
+ * Following the platform's metadata-driven philosophy, the agent
1467
+ * itself no longer hardcodes which tools it can call; instead it
1468
+ * names this skill and the SkillRegistry resolves the tool list at
1469
+ * request time. Disabling this skill via the metadata service
1470
+ * disables data exploration for every agent that references it,
1471
+ * without code changes.
1472
+ */
1473
+ declare const DATA_EXPLORER_SKILL: Skill;
1474
+
1475
+ /**
1476
+ * Built-in `metadata_authoring` skill — the write-side schema-design
1477
+ * capability bundle attached to the `metadata_assistant` agent (and
1478
+ * any other agent that should be allowed to mutate schema).
1479
+ *
1480
+ * Splitting this off from the agent record lets us:
1481
+ * - Reuse the same authoring tools across multiple agent personas
1482
+ * (e.g. an "ops bot" that ALSO can author).
1483
+ * - Disable authoring globally by setting `active: false` on the
1484
+ * skill metadata, without redeploying the agent.
1485
+ * - Layer permissions via `Skill.permissions` independent of the
1486
+ * agent's permissions.
1487
+ */
1488
+ declare const METADATA_AUTHORING_SKILL: Skill;
1489
+
1490
+ /**
1491
+ * Built-in `actions_executor` skill — the write-side counterpart to
1492
+ * `data_explorer`.
1493
+ *
1494
+ * Where `data_explorer` lets an agent **answer** questions about the
1495
+ * user's data, `actions_executor` lets the same agent **perform**
1496
+ * business operations: complete tasks, start workflows, send invites,
1497
+ * etc. The concrete tools are not enumerated here — they're materialised
1498
+ * at runtime from every `Action` declared on every object the metadata
1499
+ * service knows about (see `registerActionsAsTools` in
1500
+ * `tools/action-tools.ts`). The skill records the *intent* ("agent may
1501
+ * invoke business actions"); the registry expands it into actual tools
1502
+ * after metadata is loaded.
1503
+ *
1504
+ * The `tools` array is intentionally empty — Phase 1 lets the
1505
+ * skill-registry resolver fall through to the global tool list when an
1506
+ * agent's skill bundle would otherwise filter out the dynamically
1507
+ * registered `action_*` tools. Skills that want to restrict the set
1508
+ * should be authored project-side with the specific `action_<name>`
1509
+ * tools they want to expose.
1510
+ */
1511
+ declare const ACTIONS_EXECUTOR_SKILL: Skill;
1512
+
1232
1513
  declare const ActionRefSchema: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
1233
1514
  type: z.ZodString;
1234
1515
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
@@ -1283,7 +1564,7 @@ declare const AiConversationObject: Omit<{
1283
1564
  abstract: boolean;
1284
1565
  datasource: string;
1285
1566
  fields: Record<string, {
1286
- type: "number" | "boolean" | "file" | "text" | "json" | "tags" | "currency" | "code" | "avatar" | "vector" | "date" | "datetime" | "signature" | "progress" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "percent" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "qrcode";
1567
+ type: "number" | "boolean" | "file" | "text" | "json" | "tags" | "currency" | "code" | "date" | "avatar" | "vector" | "datetime" | "signature" | "progress" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "percent" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "qrcode";
1287
1568
  required: boolean;
1288
1569
  searchable: boolean;
1289
1570
  multiple: boolean;
@@ -1422,7 +1703,7 @@ declare const AiConversationObject: Omit<{
1422
1703
  autoRotate: boolean;
1423
1704
  } | undefined;
1424
1705
  };
1425
- scope: "field" | "database" | "record" | "table";
1706
+ scope: "record" | "field" | "database" | "table";
1426
1707
  deterministicEncryption: boolean;
1427
1708
  searchableEncryption: boolean;
1428
1709
  } | undefined;
@@ -1855,7 +2136,7 @@ declare const AiConversationObject: Omit<{
1855
2136
  trash: boolean;
1856
2137
  mru: boolean;
1857
2138
  clone: boolean;
1858
- apiMethods?: ("search" | "upsert" | "create" | "import" | "delete" | "list" | "get" | "update" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
2139
+ apiMethods?: ("restore" | "export" | "import" | "delete" | "purge" | "upsert" | "search" | "create" | "list" | "get" | "update" | "history" | "bulk" | "aggregate")[] | undefined;
1859
2140
  } | undefined;
1860
2141
  recordTypes?: string[] | undefined;
1861
2142
  sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
@@ -1926,6 +2207,7 @@ declare const AiConversationObject: Omit<{
1926
2207
  } | undefined;
1927
2208
  shortcut?: string | undefined;
1928
2209
  bulkEnabled?: boolean | undefined;
2210
+ aiExposed?: boolean | undefined;
1929
2211
  recordIdParam?: string | undefined;
1930
2212
  recordIdField?: string | undefined;
1931
2213
  bodyShape?: "flat" | {
@@ -3207,7 +3489,7 @@ declare const AiMessageObject: Omit<{
3207
3489
  abstract: boolean;
3208
3490
  datasource: string;
3209
3491
  fields: Record<string, {
3210
- type: "number" | "boolean" | "file" | "text" | "json" | "tags" | "currency" | "code" | "avatar" | "vector" | "date" | "datetime" | "signature" | "progress" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "percent" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "qrcode";
3492
+ type: "number" | "boolean" | "file" | "text" | "json" | "tags" | "currency" | "code" | "date" | "avatar" | "vector" | "datetime" | "signature" | "progress" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "percent" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "qrcode";
3211
3493
  required: boolean;
3212
3494
  searchable: boolean;
3213
3495
  multiple: boolean;
@@ -3346,7 +3628,7 @@ declare const AiMessageObject: Omit<{
3346
3628
  autoRotate: boolean;
3347
3629
  } | undefined;
3348
3630
  };
3349
- scope: "field" | "database" | "record" | "table";
3631
+ scope: "record" | "field" | "database" | "table";
3350
3632
  deterministicEncryption: boolean;
3351
3633
  searchableEncryption: boolean;
3352
3634
  } | undefined;
@@ -3779,7 +4061,7 @@ declare const AiMessageObject: Omit<{
3779
4061
  trash: boolean;
3780
4062
  mru: boolean;
3781
4063
  clone: boolean;
3782
- apiMethods?: ("search" | "upsert" | "create" | "import" | "delete" | "list" | "get" | "update" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
4064
+ apiMethods?: ("restore" | "export" | "import" | "delete" | "purge" | "upsert" | "search" | "create" | "list" | "get" | "update" | "history" | "bulk" | "aggregate")[] | undefined;
3783
4065
  } | undefined;
3784
4066
  recordTypes?: string[] | undefined;
3785
4067
  sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
@@ -3850,6 +4132,7 @@ declare const AiMessageObject: Omit<{
3850
4132
  } | undefined;
3851
4133
  shortcut?: string | undefined;
3852
4134
  bulkEnabled?: boolean | undefined;
4135
+ aiExposed?: boolean | undefined;
3853
4136
  recordIdParam?: string | undefined;
3854
4137
  recordIdField?: string | undefined;
3855
4138
  bodyShape?: "flat" | {
@@ -5133,7 +5416,7 @@ declare const AiTraceObject: Omit<{
5133
5416
  abstract: boolean;
5134
5417
  datasource: string;
5135
5418
  fields: Record<string, {
5136
- type: "number" | "boolean" | "file" | "text" | "json" | "tags" | "currency" | "code" | "avatar" | "vector" | "date" | "datetime" | "signature" | "progress" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "percent" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "qrcode";
5419
+ type: "number" | "boolean" | "file" | "text" | "json" | "tags" | "currency" | "code" | "date" | "avatar" | "vector" | "datetime" | "signature" | "progress" | "url" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "percent" | "time" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "video" | "audio" | "formula" | "summary" | "autonumber" | "location" | "address" | "color" | "rating" | "slider" | "qrcode";
5137
5420
  required: boolean;
5138
5421
  searchable: boolean;
5139
5422
  multiple: boolean;
@@ -5272,7 +5555,7 @@ declare const AiTraceObject: Omit<{
5272
5555
  autoRotate: boolean;
5273
5556
  } | undefined;
5274
5557
  };
5275
- scope: "field" | "database" | "record" | "table";
5558
+ scope: "record" | "field" | "database" | "table";
5276
5559
  deterministicEncryption: boolean;
5277
5560
  searchableEncryption: boolean;
5278
5561
  } | undefined;
@@ -5705,7 +5988,7 @@ declare const AiTraceObject: Omit<{
5705
5988
  trash: boolean;
5706
5989
  mru: boolean;
5707
5990
  clone: boolean;
5708
- apiMethods?: ("search" | "upsert" | "create" | "import" | "delete" | "list" | "get" | "update" | "history" | "bulk" | "aggregate" | "restore" | "purge" | "export")[] | undefined;
5991
+ apiMethods?: ("restore" | "export" | "import" | "delete" | "purge" | "upsert" | "search" | "create" | "list" | "get" | "update" | "history" | "bulk" | "aggregate")[] | undefined;
5709
5992
  } | undefined;
5710
5993
  recordTypes?: string[] | undefined;
5711
5994
  sharingModel?: "private" | "read" | "full" | "read_write" | undefined;
@@ -5776,6 +6059,7 @@ declare const AiTraceObject: Omit<{
5776
6059
  } | undefined;
5777
6060
  shortcut?: string | undefined;
5778
6061
  bulkEnabled?: boolean | undefined;
6062
+ aiExposed?: boolean | undefined;
5779
6063
  recordIdParam?: string | undefined;
5780
6064
  recordIdField?: string | undefined;
5781
6065
  bodyShape?: "flat" | {
@@ -8972,125 +9256,871 @@ declare const AiTraceObject: Omit<{
8972
9256
  }, "fields">;
8973
9257
 
8974
9258
  /**
8975
- * SchemaRetrieverKeyword-based metadata retrieval for AI prompts.
8976
- *
8977
- * Given a free-text query (typically the user's last message), surfaces the
8978
- * most relevant `object` definitions and renders a compact schema snippet
8979
- * suitable for injection into the system prompt.
8980
- *
8981
- * v1 strategy is intentionally simple:
8982
- * - Tokenise the query into lower-case alphanumeric terms
8983
- * - Score each registered object by counting term hits against its name,
8984
- * label, field names, and field labels
8985
- * - Return the top `limit` matches above the score threshold
8986
- *
8987
- * This does *not* use embeddings — for v1 the user-defined object catalogue
8988
- * is small enough (< 1000 objects in practice) that a single linear scan
8989
- * over already-cached metadata is faster than a vector round-trip and
8990
- * eliminates the need for a vector store.
9259
+ * ai_tracesbuilt-in Studio list view.
8991
9260
  *
8992
- * Future versions can swap in {@link IAIService.embed} backed retrieval
8993
- * behind the same `retrieve()` shape.
9261
+ * Exposes per-call observability for every LLM invocation that flowed
9262
+ * through the `AIService`. Ships with the platform so users don't have
9263
+ * to author a view for an object they didn't create.
8994
9264
  *
8995
- * @example
8996
- * ```ts
8997
- * const retriever = new SchemaRetriever(metadataService);
8998
- * const hits = await retriever.retrieve('how many open tasks are due this week?');
8999
- * const snippet = SchemaRetriever.renderSnippet(hits);
9000
- * // snippet:
9001
- * // ## Schema context (auto-injected)
9002
- * // ### task — Project Task
9003
- * // - id: text
9004
- * // - title: text
9005
- * // - status: select(open|in_progress|done)
9006
- * // - due_date: date
9007
- * ```
9008
- */
9009
- declare class SchemaRetriever {
9010
- private readonly metadata;
9011
- private readonly options;
9012
- constructor(metadata: IMetadataService, options?: SchemaRetrieverOptions);
9013
- /**
9014
- * Find object definitions whose name/label/fields match terms in the query.
9015
- *
9016
- * Returns matches sorted by score (descending) capped at `limit`. When
9017
- * the query yields no matches, returns an empty array — callers may
9018
- * fall back to a generic "describe what data exists" tool call.
9019
- */
9020
- retrieve(query: string): Promise<SchemaHit[]>;
9021
- /**
9022
- * Render hits as a compact Markdown schema snippet.
9023
- *
9024
- * Designed to be appended to the system message — every line carries
9025
- * exactly the information a model needs to choose object/field names
9026
- * for query construction.
9027
- */
9028
- static renderSnippet(hits: SchemaHit[], maxFieldsPerObject?: number): string;
9029
- }
9030
- /** A scored retrieval result. */
9031
- interface SchemaHit {
9032
- object: ObjectShape;
9033
- score: number;
9034
- }
9035
- /** Options for {@link SchemaRetriever}. */
9036
- interface SchemaRetrieverOptions {
9037
- /** Maximum number of objects to return (default: 3). */
9038
- limit?: number;
9039
- /** Minimum score required to include an object (default: 1). */
9040
- minScore?: number;
9041
- /** Maximum fields rendered per object in the snippet (default: 12). */
9042
- maxFieldsPerObject?: number;
9043
- }
9044
- /** Minimal shape of an object definition we care about. */
9045
- interface ObjectShape {
9046
- name: string;
9047
- label?: string;
9048
- pluralLabel?: string;
9049
- description?: string;
9050
- fields?: Record<string, FieldShape>;
9051
- }
9052
- /** Minimal shape of a field definition. */
9053
- interface FieldShape {
9054
- type?: string;
9055
- label?: string;
9056
- options?: unknown;
9057
- reference?: string;
9058
- }
9059
-
9060
- /**
9061
- * Context for the `query_data` tool.
9265
+ * - Default list: grid sorted by `created_at` desc, showing the columns an
9266
+ * operator usually wants at a glance (operation, model, latency, tokens,
9267
+ * cost, status).
9268
+ * - `errors` view: pre-filtered to status="error" for triage.
9269
+ * - `by_model` view: grouped by model for cost / quality comparison.
9062
9270
  *
9063
- * Wires together the three services it needs:
9064
- * - {@link IAIService} for structured-output generation of the ObjectQL query
9065
- * - {@link IMetadataService} for schema discovery
9066
- * - {@link IDataEngine} for actually executing the resolved query
9271
+ * Registered via the AIService plugin's manifest payload — appears
9272
+ * automatically in Studio when AIService is loaded.
9067
9273
  */
9068
- interface QueryDataToolContext {
9069
- ai: IAIService;
9070
- metadata: IMetadataService;
9071
- dataEngine: IDataEngine;
9072
- /** Maximum number of records returned per call (default: 100). */
9073
- maxLimit?: number;
9074
- }
9075
- /**
9076
- * Zod schema used to constrain the LLM's structured output.
9077
- *
9078
- * Kept small and strict — every property is documented so providers like
9079
- * OpenAI Structured Outputs and Anthropic Tool Use can render high-quality
9080
- * prompts from the schema metadata.
9274
+ declare const AiTraceView: {
9275
+ list?: {
9276
+ type: "map" | "kanban" | "calendar" | "gantt" | "gallery" | "timeline" | "chart" | "grid";
9277
+ columns: string[] | {
9278
+ field: string;
9279
+ label?: string | undefined;
9280
+ width?: number | undefined;
9281
+ align?: "left" | "center" | "right" | undefined;
9282
+ hidden?: boolean | undefined;
9283
+ sortable?: boolean | undefined;
9284
+ resizable?: boolean | undefined;
9285
+ wrap?: boolean | undefined;
9286
+ type?: string | undefined;
9287
+ pinned?: "left" | "right" | undefined;
9288
+ summary?: "none" | "min" | "max" | "count" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
9289
+ link?: boolean | undefined;
9290
+ action?: string | undefined;
9291
+ }[];
9292
+ name?: string | undefined;
9293
+ label?: string | undefined;
9294
+ data?: {
9295
+ provider: "object";
9296
+ object: string;
9297
+ } | {
9298
+ provider: "api";
9299
+ read?: {
9300
+ url: string;
9301
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9302
+ headers?: Record<string, string> | undefined;
9303
+ params?: Record<string, unknown> | undefined;
9304
+ body?: unknown;
9305
+ } | undefined;
9306
+ write?: {
9307
+ url: string;
9308
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9309
+ headers?: Record<string, string> | undefined;
9310
+ params?: Record<string, unknown> | undefined;
9311
+ body?: unknown;
9312
+ } | undefined;
9313
+ } | {
9314
+ provider: "value";
9315
+ items: unknown[];
9316
+ } | undefined;
9317
+ filter?: {
9318
+ field: string;
9319
+ operator: string;
9320
+ value?: string | number | boolean | (string | number)[] | null | undefined;
9321
+ }[] | undefined;
9322
+ sort?: string | {
9323
+ field: string;
9324
+ order: "asc" | "desc";
9325
+ }[] | undefined;
9326
+ searchableFields?: string[] | undefined;
9327
+ filterableFields?: string[] | undefined;
9328
+ resizable?: boolean | undefined;
9329
+ striped?: boolean | undefined;
9330
+ bordered?: boolean | undefined;
9331
+ compactToolbar?: boolean | undefined;
9332
+ selection?: {
9333
+ type: "none" | "multiple" | "single";
9334
+ } | undefined;
9335
+ navigation?: {
9336
+ mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
9337
+ preventNavigation: boolean;
9338
+ openNewTab: boolean;
9339
+ view?: string | undefined;
9340
+ width?: string | number | undefined;
9341
+ } | undefined;
9342
+ pagination?: {
9343
+ pageSize: number;
9344
+ pageSizeOptions?: number[] | undefined;
9345
+ } | undefined;
9346
+ kanban?: {
9347
+ groupByField: string;
9348
+ columns: string[];
9349
+ summarizeField?: string | undefined;
9350
+ } | undefined;
9351
+ calendar?: {
9352
+ startDateField: string;
9353
+ titleField: string;
9354
+ endDateField?: string | undefined;
9355
+ colorField?: string | undefined;
9356
+ } | undefined;
9357
+ gantt?: {
9358
+ startDateField: string;
9359
+ endDateField: string;
9360
+ titleField: string;
9361
+ progressField?: string | undefined;
9362
+ dependenciesField?: string | undefined;
9363
+ } | undefined;
9364
+ gallery?: {
9365
+ coverFit: "cover" | "contain";
9366
+ cardSize: "small" | "medium" | "large";
9367
+ coverField?: string | undefined;
9368
+ titleField?: string | undefined;
9369
+ visibleFields?: string[] | undefined;
9370
+ } | undefined;
9371
+ timeline?: {
9372
+ startDateField: string;
9373
+ titleField: string;
9374
+ scale: "day" | "week" | "month" | "quarter" | "year" | "hour";
9375
+ endDateField?: string | undefined;
9376
+ groupByField?: string | undefined;
9377
+ colorField?: string | undefined;
9378
+ } | undefined;
9379
+ chart?: {
9380
+ chartType: "bar" | "line" | "pie" | "area" | "scatter";
9381
+ xAxisField: string;
9382
+ yAxisFields: string[];
9383
+ aggregation?: "min" | "max" | "count" | "sum" | "avg" | undefined;
9384
+ groupByField?: string | undefined;
9385
+ } | undefined;
9386
+ description?: string | undefined;
9387
+ sharing?: {
9388
+ type: "personal" | "collaborative";
9389
+ lockedBy?: string | undefined;
9390
+ } | undefined;
9391
+ rowHeight?: "medium" | "short" | "compact" | "tall" | "extra_tall" | undefined;
9392
+ grouping?: {
9393
+ fields: {
9394
+ field: string;
9395
+ order: "asc" | "desc";
9396
+ collapsed: boolean;
9397
+ }[];
9398
+ } | undefined;
9399
+ rowColor?: {
9400
+ field: string;
9401
+ colors?: Record<string, string> | undefined;
9402
+ } | undefined;
9403
+ hiddenFields?: string[] | undefined;
9404
+ fieldOrder?: string[] | undefined;
9405
+ rowActions?: string[] | undefined;
9406
+ bulkActions?: string[] | undefined;
9407
+ bulkActionDefs?: Record<string, any>[] | undefined;
9408
+ virtualScroll?: boolean | undefined;
9409
+ conditionalFormatting?: {
9410
+ condition: {
9411
+ dialect: "cel" | "js" | "cron" | "template";
9412
+ source?: string | undefined;
9413
+ ast?: unknown;
9414
+ meta?: {
9415
+ rationale?: string | undefined;
9416
+ generatedBy?: string | undefined;
9417
+ } | undefined;
9418
+ } | {
9419
+ dialect: "cel" | "js" | "cron" | "template";
9420
+ source?: string | undefined;
9421
+ ast?: unknown;
9422
+ meta?: {
9423
+ rationale?: string | undefined;
9424
+ generatedBy?: string | undefined;
9425
+ } | undefined;
9426
+ };
9427
+ style: Record<string, string>;
9428
+ }[] | undefined;
9429
+ inlineEdit?: boolean | undefined;
9430
+ exportOptions?: ("json" | "csv" | "xlsx" | "pdf")[] | undefined;
9431
+ userActions?: {
9432
+ sort: boolean;
9433
+ search: boolean;
9434
+ filter: boolean;
9435
+ rowHeight: boolean;
9436
+ addRecordForm: boolean;
9437
+ buttons?: string[] | undefined;
9438
+ } | undefined;
9439
+ appearance?: {
9440
+ showDescription: boolean;
9441
+ allowedVisualizations?: ("map" | "kanban" | "calendar" | "gantt" | "gallery" | "timeline" | "grid")[] | undefined;
9442
+ } | undefined;
9443
+ tabs?: {
9444
+ name: string;
9445
+ pinned: boolean;
9446
+ isDefault: boolean;
9447
+ visible: boolean;
9448
+ label?: string | undefined;
9449
+ icon?: string | undefined;
9450
+ view?: string | undefined;
9451
+ filter?: {
9452
+ field: string;
9453
+ operator: string;
9454
+ value?: string | number | boolean | (string | number)[] | null | undefined;
9455
+ }[] | undefined;
9456
+ order?: number | undefined;
9457
+ }[] | undefined;
9458
+ addRecord?: {
9459
+ enabled: boolean;
9460
+ position: "top" | "bottom" | "both";
9461
+ mode: "modal" | "form" | "inline";
9462
+ formView?: string | undefined;
9463
+ } | undefined;
9464
+ showRecordCount?: boolean | undefined;
9465
+ allowPrinting?: boolean | undefined;
9466
+ emptyState?: {
9467
+ title?: string | undefined;
9468
+ message?: string | undefined;
9469
+ icon?: string | undefined;
9470
+ } | undefined;
9471
+ aria?: {
9472
+ ariaLabel?: string | undefined;
9473
+ ariaDescribedBy?: string | undefined;
9474
+ role?: string | undefined;
9475
+ } | undefined;
9476
+ responsive?: {
9477
+ breakpoint?: "md" | "xs" | "sm" | "lg" | "xl" | "2xl" | undefined;
9478
+ hiddenOn?: ("md" | "xs" | "sm" | "lg" | "xl" | "2xl")[] | undefined;
9479
+ columns?: {
9480
+ xs?: number | undefined;
9481
+ sm?: number | undefined;
9482
+ md?: number | undefined;
9483
+ lg?: number | undefined;
9484
+ xl?: number | undefined;
9485
+ '2xl'?: number | undefined;
9486
+ } | undefined;
9487
+ order?: {
9488
+ xs?: number | undefined;
9489
+ sm?: number | undefined;
9490
+ md?: number | undefined;
9491
+ lg?: number | undefined;
9492
+ xl?: number | undefined;
9493
+ '2xl'?: number | undefined;
9494
+ } | undefined;
9495
+ } | undefined;
9496
+ performance?: {
9497
+ lazyLoad?: boolean | undefined;
9498
+ virtualScroll?: {
9499
+ enabled: boolean;
9500
+ itemHeight?: number | undefined;
9501
+ overscan?: number | undefined;
9502
+ } | undefined;
9503
+ cacheStrategy?: "none" | "cache-first" | "network-first" | "stale-while-revalidate" | undefined;
9504
+ prefetch?: boolean | undefined;
9505
+ pageSize?: number | undefined;
9506
+ debounceMs?: number | undefined;
9507
+ } | undefined;
9508
+ } | undefined;
9509
+ form?: {
9510
+ type: "split" | "modal" | "drawer" | "simple" | "tabbed" | "wizard";
9511
+ data?: {
9512
+ provider: "object";
9513
+ object: string;
9514
+ } | {
9515
+ provider: "api";
9516
+ read?: {
9517
+ url: string;
9518
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9519
+ headers?: Record<string, string> | undefined;
9520
+ params?: Record<string, unknown> | undefined;
9521
+ body?: unknown;
9522
+ } | undefined;
9523
+ write?: {
9524
+ url: string;
9525
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9526
+ headers?: Record<string, string> | undefined;
9527
+ params?: Record<string, unknown> | undefined;
9528
+ body?: unknown;
9529
+ } | undefined;
9530
+ } | {
9531
+ provider: "value";
9532
+ items: unknown[];
9533
+ } | undefined;
9534
+ sections?: {
9535
+ collapsible: boolean;
9536
+ collapsed: boolean;
9537
+ columns: 1 | 2 | 3 | 4;
9538
+ fields: (string | {
9539
+ field: string;
9540
+ label?: string | undefined;
9541
+ placeholder?: string | undefined;
9542
+ helpText?: string | undefined;
9543
+ readonly?: boolean | undefined;
9544
+ required?: boolean | undefined;
9545
+ hidden?: boolean | undefined;
9546
+ colSpan?: number | undefined;
9547
+ widget?: string | undefined;
9548
+ dependsOn?: string | undefined;
9549
+ visibleOn?: {
9550
+ dialect: "cel" | "js" | "cron" | "template";
9551
+ source?: string | undefined;
9552
+ ast?: unknown;
9553
+ meta?: {
9554
+ rationale?: string | undefined;
9555
+ generatedBy?: string | undefined;
9556
+ } | undefined;
9557
+ } | {
9558
+ dialect: "cel" | "js" | "cron" | "template";
9559
+ source?: string | undefined;
9560
+ ast?: unknown;
9561
+ meta?: {
9562
+ rationale?: string | undefined;
9563
+ generatedBy?: string | undefined;
9564
+ } | undefined;
9565
+ } | undefined;
9566
+ })[];
9567
+ label?: string | undefined;
9568
+ }[] | undefined;
9569
+ groups?: {
9570
+ collapsible: boolean;
9571
+ collapsed: boolean;
9572
+ columns: 1 | 2 | 3 | 4;
9573
+ fields: (string | {
9574
+ field: string;
9575
+ label?: string | undefined;
9576
+ placeholder?: string | undefined;
9577
+ helpText?: string | undefined;
9578
+ readonly?: boolean | undefined;
9579
+ required?: boolean | undefined;
9580
+ hidden?: boolean | undefined;
9581
+ colSpan?: number | undefined;
9582
+ widget?: string | undefined;
9583
+ dependsOn?: string | undefined;
9584
+ visibleOn?: {
9585
+ dialect: "cel" | "js" | "cron" | "template";
9586
+ source?: string | undefined;
9587
+ ast?: unknown;
9588
+ meta?: {
9589
+ rationale?: string | undefined;
9590
+ generatedBy?: string | undefined;
9591
+ } | undefined;
9592
+ } | {
9593
+ dialect: "cel" | "js" | "cron" | "template";
9594
+ source?: string | undefined;
9595
+ ast?: unknown;
9596
+ meta?: {
9597
+ rationale?: string | undefined;
9598
+ generatedBy?: string | undefined;
9599
+ } | undefined;
9600
+ } | undefined;
9601
+ })[];
9602
+ label?: string | undefined;
9603
+ }[] | undefined;
9604
+ defaultSort?: {
9605
+ field: string;
9606
+ order: "asc" | "desc";
9607
+ }[] | undefined;
9608
+ sharing?: {
9609
+ enabled: boolean;
9610
+ allowAnonymous: boolean;
9611
+ publicLink?: string | undefined;
9612
+ password?: string | undefined;
9613
+ allowedDomains?: string[] | undefined;
9614
+ expiresAt?: string | undefined;
9615
+ } | undefined;
9616
+ submitBehavior?: {
9617
+ kind: "thank-you";
9618
+ title?: string | undefined;
9619
+ message?: string | undefined;
9620
+ } | {
9621
+ kind: "redirect";
9622
+ url: string;
9623
+ delayMs?: number | undefined;
9624
+ } | {
9625
+ kind: "continue";
9626
+ } | {
9627
+ kind: "next-record";
9628
+ } | undefined;
9629
+ aria?: {
9630
+ ariaLabel?: string | undefined;
9631
+ ariaDescribedBy?: string | undefined;
9632
+ role?: string | undefined;
9633
+ } | undefined;
9634
+ } | undefined;
9635
+ listViews?: Record<string, {
9636
+ type: "map" | "kanban" | "calendar" | "gantt" | "gallery" | "timeline" | "chart" | "grid";
9637
+ columns: string[] | {
9638
+ field: string;
9639
+ label?: string | undefined;
9640
+ width?: number | undefined;
9641
+ align?: "left" | "center" | "right" | undefined;
9642
+ hidden?: boolean | undefined;
9643
+ sortable?: boolean | undefined;
9644
+ resizable?: boolean | undefined;
9645
+ wrap?: boolean | undefined;
9646
+ type?: string | undefined;
9647
+ pinned?: "left" | "right" | undefined;
9648
+ summary?: "none" | "min" | "max" | "count" | "sum" | "avg" | "count_empty" | "count_filled" | "count_unique" | "percent_empty" | "percent_filled" | undefined;
9649
+ link?: boolean | undefined;
9650
+ action?: string | undefined;
9651
+ }[];
9652
+ name?: string | undefined;
9653
+ label?: string | undefined;
9654
+ data?: {
9655
+ provider: "object";
9656
+ object: string;
9657
+ } | {
9658
+ provider: "api";
9659
+ read?: {
9660
+ url: string;
9661
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9662
+ headers?: Record<string, string> | undefined;
9663
+ params?: Record<string, unknown> | undefined;
9664
+ body?: unknown;
9665
+ } | undefined;
9666
+ write?: {
9667
+ url: string;
9668
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9669
+ headers?: Record<string, string> | undefined;
9670
+ params?: Record<string, unknown> | undefined;
9671
+ body?: unknown;
9672
+ } | undefined;
9673
+ } | {
9674
+ provider: "value";
9675
+ items: unknown[];
9676
+ } | undefined;
9677
+ filter?: {
9678
+ field: string;
9679
+ operator: string;
9680
+ value?: string | number | boolean | (string | number)[] | null | undefined;
9681
+ }[] | undefined;
9682
+ sort?: string | {
9683
+ field: string;
9684
+ order: "asc" | "desc";
9685
+ }[] | undefined;
9686
+ searchableFields?: string[] | undefined;
9687
+ filterableFields?: string[] | undefined;
9688
+ resizable?: boolean | undefined;
9689
+ striped?: boolean | undefined;
9690
+ bordered?: boolean | undefined;
9691
+ compactToolbar?: boolean | undefined;
9692
+ selection?: {
9693
+ type: "none" | "multiple" | "single";
9694
+ } | undefined;
9695
+ navigation?: {
9696
+ mode: "none" | "split" | "page" | "modal" | "drawer" | "popover" | "new_window";
9697
+ preventNavigation: boolean;
9698
+ openNewTab: boolean;
9699
+ view?: string | undefined;
9700
+ width?: string | number | undefined;
9701
+ } | undefined;
9702
+ pagination?: {
9703
+ pageSize: number;
9704
+ pageSizeOptions?: number[] | undefined;
9705
+ } | undefined;
9706
+ kanban?: {
9707
+ groupByField: string;
9708
+ columns: string[];
9709
+ summarizeField?: string | undefined;
9710
+ } | undefined;
9711
+ calendar?: {
9712
+ startDateField: string;
9713
+ titleField: string;
9714
+ endDateField?: string | undefined;
9715
+ colorField?: string | undefined;
9716
+ } | undefined;
9717
+ gantt?: {
9718
+ startDateField: string;
9719
+ endDateField: string;
9720
+ titleField: string;
9721
+ progressField?: string | undefined;
9722
+ dependenciesField?: string | undefined;
9723
+ } | undefined;
9724
+ gallery?: {
9725
+ coverFit: "cover" | "contain";
9726
+ cardSize: "small" | "medium" | "large";
9727
+ coverField?: string | undefined;
9728
+ titleField?: string | undefined;
9729
+ visibleFields?: string[] | undefined;
9730
+ } | undefined;
9731
+ timeline?: {
9732
+ startDateField: string;
9733
+ titleField: string;
9734
+ scale: "day" | "week" | "month" | "quarter" | "year" | "hour";
9735
+ endDateField?: string | undefined;
9736
+ groupByField?: string | undefined;
9737
+ colorField?: string | undefined;
9738
+ } | undefined;
9739
+ chart?: {
9740
+ chartType: "bar" | "line" | "pie" | "area" | "scatter";
9741
+ xAxisField: string;
9742
+ yAxisFields: string[];
9743
+ aggregation?: "min" | "max" | "count" | "sum" | "avg" | undefined;
9744
+ groupByField?: string | undefined;
9745
+ } | undefined;
9746
+ description?: string | undefined;
9747
+ sharing?: {
9748
+ type: "personal" | "collaborative";
9749
+ lockedBy?: string | undefined;
9750
+ } | undefined;
9751
+ rowHeight?: "medium" | "short" | "compact" | "tall" | "extra_tall" | undefined;
9752
+ grouping?: {
9753
+ fields: {
9754
+ field: string;
9755
+ order: "asc" | "desc";
9756
+ collapsed: boolean;
9757
+ }[];
9758
+ } | undefined;
9759
+ rowColor?: {
9760
+ field: string;
9761
+ colors?: Record<string, string> | undefined;
9762
+ } | undefined;
9763
+ hiddenFields?: string[] | undefined;
9764
+ fieldOrder?: string[] | undefined;
9765
+ rowActions?: string[] | undefined;
9766
+ bulkActions?: string[] | undefined;
9767
+ bulkActionDefs?: Record<string, any>[] | undefined;
9768
+ virtualScroll?: boolean | undefined;
9769
+ conditionalFormatting?: {
9770
+ condition: {
9771
+ dialect: "cel" | "js" | "cron" | "template";
9772
+ source?: string | undefined;
9773
+ ast?: unknown;
9774
+ meta?: {
9775
+ rationale?: string | undefined;
9776
+ generatedBy?: string | undefined;
9777
+ } | undefined;
9778
+ } | {
9779
+ dialect: "cel" | "js" | "cron" | "template";
9780
+ source?: string | undefined;
9781
+ ast?: unknown;
9782
+ meta?: {
9783
+ rationale?: string | undefined;
9784
+ generatedBy?: string | undefined;
9785
+ } | undefined;
9786
+ };
9787
+ style: Record<string, string>;
9788
+ }[] | undefined;
9789
+ inlineEdit?: boolean | undefined;
9790
+ exportOptions?: ("json" | "csv" | "xlsx" | "pdf")[] | undefined;
9791
+ userActions?: {
9792
+ sort: boolean;
9793
+ search: boolean;
9794
+ filter: boolean;
9795
+ rowHeight: boolean;
9796
+ addRecordForm: boolean;
9797
+ buttons?: string[] | undefined;
9798
+ } | undefined;
9799
+ appearance?: {
9800
+ showDescription: boolean;
9801
+ allowedVisualizations?: ("map" | "kanban" | "calendar" | "gantt" | "gallery" | "timeline" | "grid")[] | undefined;
9802
+ } | undefined;
9803
+ tabs?: {
9804
+ name: string;
9805
+ pinned: boolean;
9806
+ isDefault: boolean;
9807
+ visible: boolean;
9808
+ label?: string | undefined;
9809
+ icon?: string | undefined;
9810
+ view?: string | undefined;
9811
+ filter?: {
9812
+ field: string;
9813
+ operator: string;
9814
+ value?: string | number | boolean | (string | number)[] | null | undefined;
9815
+ }[] | undefined;
9816
+ order?: number | undefined;
9817
+ }[] | undefined;
9818
+ addRecord?: {
9819
+ enabled: boolean;
9820
+ position: "top" | "bottom" | "both";
9821
+ mode: "modal" | "form" | "inline";
9822
+ formView?: string | undefined;
9823
+ } | undefined;
9824
+ showRecordCount?: boolean | undefined;
9825
+ allowPrinting?: boolean | undefined;
9826
+ emptyState?: {
9827
+ title?: string | undefined;
9828
+ message?: string | undefined;
9829
+ icon?: string | undefined;
9830
+ } | undefined;
9831
+ aria?: {
9832
+ ariaLabel?: string | undefined;
9833
+ ariaDescribedBy?: string | undefined;
9834
+ role?: string | undefined;
9835
+ } | undefined;
9836
+ responsive?: {
9837
+ breakpoint?: "md" | "xs" | "sm" | "lg" | "xl" | "2xl" | undefined;
9838
+ hiddenOn?: ("md" | "xs" | "sm" | "lg" | "xl" | "2xl")[] | undefined;
9839
+ columns?: {
9840
+ xs?: number | undefined;
9841
+ sm?: number | undefined;
9842
+ md?: number | undefined;
9843
+ lg?: number | undefined;
9844
+ xl?: number | undefined;
9845
+ '2xl'?: number | undefined;
9846
+ } | undefined;
9847
+ order?: {
9848
+ xs?: number | undefined;
9849
+ sm?: number | undefined;
9850
+ md?: number | undefined;
9851
+ lg?: number | undefined;
9852
+ xl?: number | undefined;
9853
+ '2xl'?: number | undefined;
9854
+ } | undefined;
9855
+ } | undefined;
9856
+ performance?: {
9857
+ lazyLoad?: boolean | undefined;
9858
+ virtualScroll?: {
9859
+ enabled: boolean;
9860
+ itemHeight?: number | undefined;
9861
+ overscan?: number | undefined;
9862
+ } | undefined;
9863
+ cacheStrategy?: "none" | "cache-first" | "network-first" | "stale-while-revalidate" | undefined;
9864
+ prefetch?: boolean | undefined;
9865
+ pageSize?: number | undefined;
9866
+ debounceMs?: number | undefined;
9867
+ } | undefined;
9868
+ }> | undefined;
9869
+ formViews?: Record<string, {
9870
+ type: "split" | "modal" | "drawer" | "simple" | "tabbed" | "wizard";
9871
+ data?: {
9872
+ provider: "object";
9873
+ object: string;
9874
+ } | {
9875
+ provider: "api";
9876
+ read?: {
9877
+ url: string;
9878
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9879
+ headers?: Record<string, string> | undefined;
9880
+ params?: Record<string, unknown> | undefined;
9881
+ body?: unknown;
9882
+ } | undefined;
9883
+ write?: {
9884
+ url: string;
9885
+ method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
9886
+ headers?: Record<string, string> | undefined;
9887
+ params?: Record<string, unknown> | undefined;
9888
+ body?: unknown;
9889
+ } | undefined;
9890
+ } | {
9891
+ provider: "value";
9892
+ items: unknown[];
9893
+ } | undefined;
9894
+ sections?: {
9895
+ collapsible: boolean;
9896
+ collapsed: boolean;
9897
+ columns: 1 | 2 | 3 | 4;
9898
+ fields: (string | {
9899
+ field: string;
9900
+ label?: string | undefined;
9901
+ placeholder?: string | undefined;
9902
+ helpText?: string | undefined;
9903
+ readonly?: boolean | undefined;
9904
+ required?: boolean | undefined;
9905
+ hidden?: boolean | undefined;
9906
+ colSpan?: number | undefined;
9907
+ widget?: string | undefined;
9908
+ dependsOn?: string | undefined;
9909
+ visibleOn?: {
9910
+ dialect: "cel" | "js" | "cron" | "template";
9911
+ source?: string | undefined;
9912
+ ast?: unknown;
9913
+ meta?: {
9914
+ rationale?: string | undefined;
9915
+ generatedBy?: string | undefined;
9916
+ } | undefined;
9917
+ } | {
9918
+ dialect: "cel" | "js" | "cron" | "template";
9919
+ source?: string | undefined;
9920
+ ast?: unknown;
9921
+ meta?: {
9922
+ rationale?: string | undefined;
9923
+ generatedBy?: string | undefined;
9924
+ } | undefined;
9925
+ } | undefined;
9926
+ })[];
9927
+ label?: string | undefined;
9928
+ }[] | undefined;
9929
+ groups?: {
9930
+ collapsible: boolean;
9931
+ collapsed: boolean;
9932
+ columns: 1 | 2 | 3 | 4;
9933
+ fields: (string | {
9934
+ field: string;
9935
+ label?: string | undefined;
9936
+ placeholder?: string | undefined;
9937
+ helpText?: string | undefined;
9938
+ readonly?: boolean | undefined;
9939
+ required?: boolean | undefined;
9940
+ hidden?: boolean | undefined;
9941
+ colSpan?: number | undefined;
9942
+ widget?: string | undefined;
9943
+ dependsOn?: string | undefined;
9944
+ visibleOn?: {
9945
+ dialect: "cel" | "js" | "cron" | "template";
9946
+ source?: string | undefined;
9947
+ ast?: unknown;
9948
+ meta?: {
9949
+ rationale?: string | undefined;
9950
+ generatedBy?: string | undefined;
9951
+ } | undefined;
9952
+ } | {
9953
+ dialect: "cel" | "js" | "cron" | "template";
9954
+ source?: string | undefined;
9955
+ ast?: unknown;
9956
+ meta?: {
9957
+ rationale?: string | undefined;
9958
+ generatedBy?: string | undefined;
9959
+ } | undefined;
9960
+ } | undefined;
9961
+ })[];
9962
+ label?: string | undefined;
9963
+ }[] | undefined;
9964
+ defaultSort?: {
9965
+ field: string;
9966
+ order: "asc" | "desc";
9967
+ }[] | undefined;
9968
+ sharing?: {
9969
+ enabled: boolean;
9970
+ allowAnonymous: boolean;
9971
+ publicLink?: string | undefined;
9972
+ password?: string | undefined;
9973
+ allowedDomains?: string[] | undefined;
9974
+ expiresAt?: string | undefined;
9975
+ } | undefined;
9976
+ submitBehavior?: {
9977
+ kind: "thank-you";
9978
+ title?: string | undefined;
9979
+ message?: string | undefined;
9980
+ } | {
9981
+ kind: "redirect";
9982
+ url: string;
9983
+ delayMs?: number | undefined;
9984
+ } | {
9985
+ kind: "continue";
9986
+ } | {
9987
+ kind: "next-record";
9988
+ } | undefined;
9989
+ aria?: {
9990
+ ariaLabel?: string | undefined;
9991
+ ariaDescribedBy?: string | undefined;
9992
+ role?: string | undefined;
9993
+ } | undefined;
9994
+ }> | undefined;
9995
+ };
9996
+
9997
+ /**
9998
+ * SchemaRetriever — Keyword-based metadata retrieval for AI prompts.
9999
+ *
10000
+ * Given a free-text query (typically the user's last message), surfaces the
10001
+ * most relevant `object` definitions and renders a compact schema snippet
10002
+ * suitable for injection into the system prompt.
10003
+ *
10004
+ * v1 strategy is intentionally simple:
10005
+ * - Tokenise the query into lower-case alphanumeric terms
10006
+ * - Score each registered object by counting term hits against its name,
10007
+ * label, field names, and field labels
10008
+ * - Return the top `limit` matches above the score threshold
10009
+ *
10010
+ * This does *not* use embeddings — for v1 the user-defined object catalogue
10011
+ * is small enough (< 1000 objects in practice) that a single linear scan
10012
+ * over already-cached metadata is faster than a vector round-trip and
10013
+ * eliminates the need for a vector store.
10014
+ *
10015
+ * Future versions can swap in {@link IAIService.embed} backed retrieval
10016
+ * behind the same `retrieve()` shape.
10017
+ *
10018
+ * @example
10019
+ * ```ts
10020
+ * const retriever = new SchemaRetriever(metadataService);
10021
+ * const hits = await retriever.retrieve('how many open tasks are due this week?');
10022
+ * const snippet = SchemaRetriever.renderSnippet(hits);
10023
+ * // snippet:
10024
+ * // ## Schema context (auto-injected)
10025
+ * // ### task — Project Task
10026
+ * // - id: text
10027
+ * // - title: text
10028
+ * // - status: select(open|in_progress|done)
10029
+ * // - due_date: date
10030
+ * ```
10031
+ */
10032
+ declare class SchemaRetriever {
10033
+ private readonly metadata;
10034
+ private readonly options;
10035
+ constructor(metadata: IMetadataService, options?: SchemaRetrieverOptions);
10036
+ /**
10037
+ * Find object definitions whose name/label/fields match terms in the query.
10038
+ *
10039
+ * Returns matches sorted by score (descending) capped at `limit`. When
10040
+ * the query yields no matches, returns an empty array — callers may
10041
+ * fall back to a generic "describe what data exists" tool call.
10042
+ */
10043
+ retrieve(query: string): Promise<SchemaHit[]>;
10044
+ /**
10045
+ * Render hits as a compact Markdown schema snippet.
10046
+ *
10047
+ * Designed to be appended to the system message — every line carries
10048
+ * exactly the information a model needs to choose object/field names
10049
+ * for query construction.
10050
+ */
10051
+ static renderSnippet(hits: SchemaHit[], maxFieldsPerObject?: number): string;
10052
+ }
10053
+ /** A scored retrieval result. */
10054
+ interface SchemaHit {
10055
+ object: ObjectShape;
10056
+ score: number;
10057
+ }
10058
+ /** Options for {@link SchemaRetriever}. */
10059
+ interface SchemaRetrieverOptions {
10060
+ /** Maximum number of objects to return (default: 3). */
10061
+ limit?: number;
10062
+ /** Minimum score required to include an object (default: 1). */
10063
+ minScore?: number;
10064
+ /** Maximum fields rendered per object in the snippet (default: 12). */
10065
+ maxFieldsPerObject?: number;
10066
+ }
10067
+ /** Minimal shape of an object definition we care about. */
10068
+ interface ObjectShape {
10069
+ name: string;
10070
+ label?: string;
10071
+ pluralLabel?: string;
10072
+ description?: string;
10073
+ fields?: Record<string, FieldShape>;
10074
+ }
10075
+ /** Minimal shape of a field definition. */
10076
+ interface FieldShape {
10077
+ type?: string;
10078
+ label?: string;
10079
+ options?: unknown;
10080
+ reference?: string;
10081
+ }
10082
+
10083
+ /**
10084
+ * Context for the `query_data` tool.
10085
+ *
10086
+ * Wires together the three services it needs:
10087
+ * - {@link IAIService} for structured-output generation of the ObjectQL query
10088
+ * - {@link IMetadataService} for schema discovery
10089
+ * - {@link IDataEngine} for actually executing the resolved query
10090
+ */
10091
+ interface QueryDataToolContext {
10092
+ ai: IAIService;
10093
+ metadata: IMetadataService;
10094
+ dataEngine: IDataEngine;
10095
+ /** Maximum number of records returned per call (default: 100). */
10096
+ maxLimit?: number;
10097
+ }
10098
+ /**
10099
+ * Zod schema used to constrain the LLM's structured output.
10100
+ *
10101
+ * Kept small and strict — every property is documented so providers like
10102
+ * OpenAI Structured Outputs and Anthropic Tool Use can render high-quality
10103
+ * prompts from the schema metadata.
10104
+ *
10105
+ * NOTE: `where` is intentionally typed as a JSON string rather than a free-form
10106
+ * record. OpenAI's Structured Outputs surface rejects `propertyNames`
10107
+ * (which Zod's `z.record(z.string(), ...)` emits), and Anthropic's tool-use
10108
+ * surface dislikes open-ended object schemas without `additionalProperties`.
10109
+ * Having the model emit a JSON-encoded filter sidesteps both restrictions and
10110
+ * keeps the tool portable across providers.
9081
10111
  */
9082
10112
  declare const QueryPlanSchema: z.ZodObject<{
9083
10113
  objectName: z.ZodString;
9084
- where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
9085
- fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
9086
- orderBy: z.ZodOptional<z.ZodArray<z.ZodObject<{
10114
+ whereJson: z.ZodNullable<z.ZodString>;
10115
+ fields: z.ZodNullable<z.ZodArray<z.ZodString>>;
10116
+ orderBy: z.ZodNullable<z.ZodArray<z.ZodObject<{
9087
10117
  field: z.ZodString;
9088
10118
  order: z.ZodEnum<{
9089
10119
  asc: "asc";
9090
10120
  desc: "desc";
9091
10121
  }>;
9092
10122
  }, z.core.$strip>>>;
9093
- limit: z.ZodOptional<z.ZodNumber>;
10123
+ limit: z.ZodNullable<z.ZodNumber>;
9094
10124
  }, z.core.$strip>;
9095
10125
  /** Strongly-typed query plan inferred from the LLM. */
9096
10126
  type QueryPlan = z.infer<typeof QueryPlanSchema>;
@@ -9249,4 +10279,4 @@ declare function buildAssistantRoutes(aiService: AIService, agentRuntime: AgentR
9249
10279
  */
9250
10280
  declare function buildToolRoutes(aiService: AIService, logger: Logger): RouteDefinition[];
9251
10281
 
9252
- export { AIService, type AIServiceConfig, AIServicePlugin, type AIServicePluginOptions, type AgentChatContext, AgentRuntime, AiConversationObject, AiMessageObject, AiTraceObject, type CostEstimate, DATA_CHAT_AGENT, DATA_TOOL_DEFINITIONS, type DataToolContext, type FieldShape, type IConversationService, type IPackageRegistry, InMemoryConversationService, METADATA_ASSISTANT_AGENT, METADATA_TOOL_DEFINITIONS, MemoryLLMAdapter, type MetadataToolContext, ModelRegistry, type ModelRegistryConfig, NullTraceRecorder, ObjectQLConversationService, ObjectQLTraceRecorder, type ObjectShape, PACKAGE_TOOL_DEFINITIONS, type PackageToolContext, QUERY_DATA_TOOL, type QueryDataToolContext, type QueryPlan, type RouteDefinition, type RouteRequest, type RouteResponse, type RouteUserContext, type SchemaHit, SchemaRetriever, type SchemaRetrieverOptions, type SkillContext, SkillRegistry, type SkillSummary, type TokenUsage, type ToolExecutionResult, type ToolHandler, ToolRegistry, type TraceEvent, type TraceOperation, type TraceRecorder, VercelLLMAdapter, type VercelLLMAdapterConfig, addFieldTool, buildAIRoutes, buildAgentRoutes, buildAssistantRoutes, buildToolRoutes, buildTraceEvent, computeCost, createObjectTool, createPackageTool, createQueryDataHandler, deleteFieldTool, describeObjectTool, encodeStreamPart, encodeVercelDataStream, getActivePackageTool, getPackageTool, listObjectsTool, listPackagesTool, modifyFieldTool, registerDataTools, registerMetadataTools, registerPackageTools, registerQueryDataTool, setActivePackageTool };
10282
+ export { ACTIONS_EXECUTOR_SKILL, AIService, type AIServiceConfig, AIServicePlugin, type AIServicePluginOptions, type ActionToolsContext, type AgentChatContext, AgentRuntime, AiConversationObject, AiMessageObject, AiTraceObject, AiTraceView, type CostEstimate, DATA_CHAT_AGENT, DATA_EXPLORER_SKILL, DATA_TOOL_DEFINITIONS, type DataToolContext, type FieldShape, type IConversationService, type IPackageRegistry, InMemoryConversationService, METADATA_ASSISTANT_AGENT, METADATA_AUTHORING_SKILL, METADATA_TOOL_DEFINITIONS, MemoryLLMAdapter, type MetadataToolContext, ModelRegistry, type ModelRegistryConfig, NullTraceRecorder, ObjectQLConversationService, ObjectQLTraceRecorder, type ObjectShape, PACKAGE_TOOL_DEFINITIONS, type PackageToolContext, QUERY_DATA_TOOL, type QueryDataToolContext, type QueryPlan, type RouteDefinition, type RouteRequest, type RouteResponse, type RouteUserContext, type SchemaHit, SchemaRetriever, type SchemaRetrieverOptions, type SkillContext, SkillRegistry, type SkillSummary, type TokenUsage, type ToolExecutionResult, type ToolHandler, ToolRegistry, type TraceEvent, type TraceOperation, type TraceRecorder, VercelLLMAdapter, type VercelLLMAdapterConfig, actionSkipReason, actionToToolDefinition, actionToolName, addFieldTool, buildAIRoutes, buildAgentRoutes, buildAssistantRoutes, buildToolRoutes, buildTraceEvent, computeCost, createObjectTool, createPackageTool, createQueryDataHandler, deleteFieldTool, describeObjectTool, encodeStreamPart, encodeVercelDataStream, getActivePackageTool, getPackageTool, listObjectsTool, listPackagesTool, modifyFieldTool, registerActionsAsTools, registerDataTools, registerMetadataTools, registerPackageTools, registerQueryDataTool, setActivePackageTool };