@thyn-ai/sqai-ai-sdk 0.1.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.js ADDED
@@ -0,0 +1,794 @@
1
+ // src/toolkit.ts
2
+ import { SQAI, SqaiError as SqaiError2 } from "@thyn-ai/sqai";
3
+
4
+ // src/tools.ts
5
+ import { tool } from "ai";
6
+ import {
7
+ ContractIndex,
8
+ SqaiError,
9
+ currentPlatformKey,
10
+ invocationHash,
11
+ isReadOnlyEligible,
12
+ lookupCapability
13
+ } from "@thyn-ai/sqai";
14
+
15
+ // src/schemas.ts
16
+ import { z } from "zod";
17
+ var filterConditionSchema = z.object({
18
+ column: z.string().optional().describe("Exact column name to filter on."),
19
+ op: z.enum(["eq", "in", "gt", "gte", "lt", "lte", "is_null", "is_not_null"]),
20
+ value: z.union([z.string(), z.number(), z.boolean()]).optional(),
21
+ values: z.array(z.union([z.string(), z.number(), z.boolean()])).optional().describe("Values for the 'in' operator.")
22
+ });
23
+ var filterSpecSchema = z.object({
24
+ time_filter: z.string().optional().describe("Named time window, e.g. 'last_30_days'."),
25
+ conditions: z.array(filterConditionSchema).optional()
26
+ });
27
+ var querySpecSchema = z.object({
28
+ metric: z.string().describe("The measure to compute, e.g. 'revenue'. Use exact field names from listSources."),
29
+ aggregation: z.enum(["sum", "avg", "count", "min", "max"]).optional(),
30
+ group_by: z.string().optional().describe("Column to group results by."),
31
+ filter: filterSpecSchema.optional(),
32
+ limit: z.number().int().positive().optional().describe("Maximum rows to return."),
33
+ order: z.enum(["asc", "desc"]).optional(),
34
+ source: z.string().optional().describe("Source name to query (maps to source_name). Omit to let the planner pick.")
35
+ });
36
+ var taggedScalarSchema = z.object({
37
+ type: z.enum(["decimal", "bigint"]),
38
+ value: z.string()
39
+ });
40
+ var algentaWireValueSchema = z.lazy(
41
+ () => z.union([
42
+ z.null(),
43
+ z.boolean(),
44
+ z.number(),
45
+ z.string(),
46
+ z.array(algentaWireValueSchema),
47
+ taggedScalarSchema,
48
+ z.record(z.string(), algentaWireValueSchema)
49
+ ])
50
+ );
51
+ var singleBindingSchema = z.object({
52
+ parameter: z.union([z.string(), z.number()]).describe("Target parameter, by name or positional index."),
53
+ source: z.string().describe("Connected source name to pull the column from."),
54
+ field: z.string().describe("Column to extract."),
55
+ filter: filterSpecSchema.optional()
56
+ });
57
+ var alignedBindingSchema = z.object({
58
+ parameters: z.array(z.union([z.string(), z.number()])).describe("Target parameters, one per field, row-aligned."),
59
+ source: z.string(),
60
+ fields: z.array(z.string()).describe("Columns to extract, one per parameter."),
61
+ filter: filterSpecSchema.optional(),
62
+ alignment: z.literal("rowwise"),
63
+ nullPolicy: z.enum(["pairwise", "preserve"]).optional()
64
+ });
65
+ var computationBindingSchema = z.union([singleBindingSchema, alignedBindingSchema]);
66
+ var computationSpecSchema = z.object({
67
+ module: z.string().describe("Capability module, e.g. 'stats'. Discover via listSources."),
68
+ function: z.string().describe("Function inside the module, e.g. 'median'."),
69
+ args: z.array(algentaWireValueSchema).default([]).describe("Positional arguments."),
70
+ kwargs: z.record(z.string(), algentaWireValueSchema).optional().describe("Named arguments."),
71
+ bindings: z.array(computationBindingSchema).optional().describe("Pull columns from connected sources instead of pasting data inline."),
72
+ seed: z.union([z.number(), z.string()]).optional().describe("Required for simulation modules; makes runs replayable")
73
+ });
74
+ var queryDataInputSchema = z.discriminatedUnion("kind", [
75
+ z.object({
76
+ version: z.literal("1"),
77
+ kind: z.literal("query"),
78
+ spec: querySpecSchema
79
+ }),
80
+ z.object({
81
+ version: z.literal("1"),
82
+ kind: z.literal("computation"),
83
+ spec: computationSpecSchema
84
+ })
85
+ ]);
86
+ var explainQueryInputSchema = queryDataInputSchema;
87
+ var listSourcesInputSchema = z.object({
88
+ capabilitySearch: z.string().optional().describe("Search the computation capability catalog; returns matching modules."),
89
+ module: z.string().optional().describe("List a module's functions with exact signatures.")
90
+ });
91
+ var cellSchema = z.union([z.number(), z.string(), z.boolean(), z.null()]);
92
+ var candidateSchema = z.looseObject({
93
+ source: z.string().optional(),
94
+ column: z.string().optional(),
95
+ role: z.string().optional(),
96
+ confidence: z.number().optional()
97
+ });
98
+ var errorOutputSchema = z.object({
99
+ status: z.literal("error"),
100
+ code: z.string(),
101
+ message: z.string(),
102
+ retryable: z.boolean(),
103
+ request_id: z.string().nullable(),
104
+ nearest_matches: z.array(z.string()).optional()
105
+ });
106
+ var clarificationOutputSchema = z.object({
107
+ status: z.literal("needs_clarification"),
108
+ question: z.string(),
109
+ candidates: z.array(candidateSchema),
110
+ explanation: z.array(z.string())
111
+ });
112
+ var rejectedOutputSchema = z.object({
113
+ status: z.literal("rejected"),
114
+ rejection_reason: z.string(),
115
+ candidates: z.array(candidateSchema),
116
+ explanation: z.array(z.string())
117
+ });
118
+ var queryOkOutputSchema = z.object({
119
+ status: z.literal("ok"),
120
+ kind: z.literal("query"),
121
+ data: z.object({
122
+ columns: z.array(z.string()),
123
+ rows: z.array(z.array(cellSchema))
124
+ }),
125
+ total_rows: z.number(),
126
+ returned_rows: z.number(),
127
+ truncated: z.boolean(),
128
+ result_id: z.string().optional(),
129
+ plan_hash: z.string().nullable(),
130
+ schema_revision: z.string().nullable(),
131
+ source_name: z.string().nullable(),
132
+ intent_signature: z.string().nullable(),
133
+ deterministic_scope: z.string().nullable(),
134
+ decision_path: z.string().nullable(),
135
+ validated: z.boolean().nullable(),
136
+ request_id: z.string().nullable(),
137
+ explanation: z.array(z.string())
138
+ });
139
+ var determinismEnvelopeSchema = z.object({
140
+ runtime_bundle_version: z.string(),
141
+ runtime_bundle_sha256: z.string(),
142
+ platform: z.string(),
143
+ architecture: z.string(),
144
+ kernel_build: z.string(),
145
+ precision_mode: z.string(),
146
+ thread_count: z.number(),
147
+ seed: z.union([z.number(), z.string()]).optional(),
148
+ input_hash: z.string()
149
+ });
150
+ var bindingProvenanceSchema = z.object({
151
+ source_name: z.string(),
152
+ fields: z.array(z.string()),
153
+ schema_revision: z.string().nullable(),
154
+ row_count: z.number(),
155
+ input_hash: z.string()
156
+ });
157
+ var computationOkOutputSchema = z.object({
158
+ status: z.literal("ok"),
159
+ kind: z.literal("computation"),
160
+ value: algentaWireValueSchema,
161
+ value_type: z.string(),
162
+ preview: algentaWireValueSchema.optional(),
163
+ element_count: z.number().optional(),
164
+ truncated: z.boolean(),
165
+ result_id: z.string().optional(),
166
+ invocation_hash: z.string(),
167
+ computation_hash: z.string(),
168
+ contract_hash: z.string(),
169
+ determinism: determinismEnvelopeSchema,
170
+ provenance: z.object({ bindings: z.array(bindingProvenanceSchema) }).optional(),
171
+ latency_ms: z.number(),
172
+ request_id: z.string()
173
+ });
174
+ var queryDataOutputSchema = z.union([
175
+ queryOkOutputSchema,
176
+ computationOkOutputSchema,
177
+ clarificationOutputSchema,
178
+ rejectedOutputSchema,
179
+ errorOutputSchema
180
+ ]);
181
+ var sourceListOutputSchema = z.object({
182
+ sources: z.array(
183
+ z.object({
184
+ name: z.string(),
185
+ fields: z.array(
186
+ z.object({
187
+ name: z.string(),
188
+ type: z.string(),
189
+ ops: z.array(z.string())
190
+ })
191
+ ),
192
+ row_count: z.number().nullable(),
193
+ schema_revision: z.string().nullable()
194
+ })
195
+ )
196
+ });
197
+ var moduleListOutputSchema = z.object({
198
+ modules: z.array(
199
+ z.object({
200
+ name: z.string(),
201
+ category: z.string(),
202
+ deterministic: z.boolean(),
203
+ function_count: z.number(),
204
+ sample_functions: z.array(z.string())
205
+ })
206
+ )
207
+ });
208
+ var functionListOutputSchema = z.object({
209
+ functions: z.array(
210
+ z.object({
211
+ name: z.string(),
212
+ signature: z.string(),
213
+ params: z.array(
214
+ z.object({
215
+ name: z.string(),
216
+ type: z.string(),
217
+ required: z.boolean()
218
+ })
219
+ ),
220
+ returns: z.string(),
221
+ deterministic: z.boolean(),
222
+ seed_required: z.boolean()
223
+ })
224
+ )
225
+ });
226
+ var listSourcesOutputSchema = z.union([
227
+ sourceListOutputSchema,
228
+ moduleListOutputSchema,
229
+ functionListOutputSchema,
230
+ errorOutputSchema
231
+ ]);
232
+ var explainQueryOkQueryOutputSchema = z.object({
233
+ status: z.literal("ok"),
234
+ kind: z.literal("query"),
235
+ resolved_plan: z.record(z.string(), z.unknown()),
236
+ plan: z.array(z.string()),
237
+ plan_hash: z.string().nullable(),
238
+ confidence: z.number(),
239
+ validated: z.boolean()
240
+ });
241
+ var explainQueryOkComputationOutputSchema = z.object({
242
+ status: z.literal("ok"),
243
+ kind: z.literal("computation"),
244
+ matched_signature: z.string(),
245
+ invocation_hash: z.string(),
246
+ seed_required: z.boolean()
247
+ });
248
+ var explainQueryOutputSchema = z.union([
249
+ explainQueryOkQueryOutputSchema,
250
+ explainQueryOkComputationOutputSchema,
251
+ clarificationOutputSchema,
252
+ rejectedOutputSchema,
253
+ errorOutputSchema
254
+ ]);
255
+
256
+ // src/truncate.ts
257
+ function toCell(value) {
258
+ if (value === null || value === void 0) {
259
+ return null;
260
+ }
261
+ if (typeof value === "number" || typeof value === "string" || typeof value === "boolean") {
262
+ return value;
263
+ }
264
+ return JSON.stringify(value);
265
+ }
266
+ function shapeQueryResult(result, options) {
267
+ if (!Array.isArray(result)) {
268
+ return {
269
+ data: { columns: ["value"], rows: [[toCell(result)]] },
270
+ total_rows: 1,
271
+ returned_rows: 1,
272
+ truncated: false
273
+ };
274
+ }
275
+ const totalRows = result.length;
276
+ if (totalRows === 0) {
277
+ return { data: { columns: [], rows: [] }, total_rows: 0, returned_rows: 0, truncated: false };
278
+ }
279
+ const first = result[0];
280
+ let columns;
281
+ let toRow;
282
+ if (first !== null && typeof first === "object" && !Array.isArray(first)) {
283
+ columns = Object.keys(first);
284
+ toRow = (row) => columns.map((column) => toCell(row[column]));
285
+ } else {
286
+ columns = ["value"];
287
+ toRow = (row) => [toCell(row)];
288
+ }
289
+ let keep = Math.min(totalRows, Math.max(0, Math.floor(options.maxRowsToModel)));
290
+ const cellsPerRow = Math.max(1, columns.length);
291
+ if (keep * cellsPerRow > options.maxCellsToModel) {
292
+ keep = Math.max(0, Math.floor(options.maxCellsToModel / cellsPerRow));
293
+ }
294
+ return {
295
+ data: { columns, rows: result.slice(0, keep).map(toRow) },
296
+ total_rows: totalRows,
297
+ returned_rows: keep,
298
+ truncated: keep < totalRows
299
+ };
300
+ }
301
+ function byteLength(value) {
302
+ return Buffer.byteLength(JSON.stringify(value ?? null), "utf-8");
303
+ }
304
+ function shapeComputationValue(value, options) {
305
+ if (value === null || typeof value !== "object") {
306
+ return { value, truncated: false };
307
+ }
308
+ if (Array.isArray(value)) {
309
+ const elementCount = value.length;
310
+ let preview = value.slice(0, Math.min(elementCount, Math.max(0, options.maxElementsToModel)));
311
+ while (preview.length > 0 && byteLength(preview) > options.maxBytesToModel) {
312
+ preview = preview.slice(0, Math.floor(preview.length / 2));
313
+ }
314
+ return {
315
+ value: null,
316
+ preview,
317
+ element_count: elementCount,
318
+ truncated: preview.length < elementCount
319
+ };
320
+ }
321
+ if (byteLength(value) <= options.maxBytesToModel) {
322
+ return { value, truncated: false };
323
+ }
324
+ return { value: null, truncated: true };
325
+ }
326
+ function storeWithinCap(value, maxOutputBytes, store) {
327
+ if (byteLength(value) > maxOutputBytes) {
328
+ return void 0;
329
+ }
330
+ return store(value);
331
+ }
332
+
333
+ // src/tools.ts
334
+ var DEFAULT_OPTIONS = {
335
+ defaultLimit: 100,
336
+ maxExecutionRows: 1e3,
337
+ maxRowsToModel: 25,
338
+ maxCellsToModel: 250,
339
+ maxElementsToModel: 500,
340
+ maxBytesToModel: 32e3,
341
+ maxOutputBytes: 1e7
342
+ };
343
+ function toErrorOutput(error) {
344
+ if (error instanceof SqaiError) {
345
+ const nearest = error.details["nearest_matches"];
346
+ const nearestMatches = Array.isArray(nearest) && nearest.every((item) => typeof item === "string") ? nearest : void 0;
347
+ return {
348
+ status: "error",
349
+ code: error.code,
350
+ message: error.message,
351
+ retryable: error.retryable,
352
+ request_id: error.requestId,
353
+ ...nearestMatches ? { nearest_matches: nearestMatches } : {}
354
+ };
355
+ }
356
+ return {
357
+ status: "error",
358
+ code: "internal_error",
359
+ message: error instanceof Error ? error.message : String(error),
360
+ retryable: false,
361
+ request_id: null
362
+ };
363
+ }
364
+ async function readyError(toolkit) {
365
+ try {
366
+ await toolkit.ensureReady();
367
+ return null;
368
+ } catch (error) {
369
+ return error instanceof SqaiError ? error : new SqaiError(
370
+ "source_connection_failed",
371
+ `Connecting the configured sources failed: ${error instanceof Error ? error.message : String(error)}`
372
+ );
373
+ }
374
+ }
375
+ function passthroughCandidates(resolution) {
376
+ return (resolution.candidates ?? []).map((candidate) => ({ ...candidate }));
377
+ }
378
+ function clarificationOutput(resolution) {
379
+ const candidates = resolution.candidates ?? [];
380
+ const names = candidates.slice(0, 5).map((candidate) => `${candidate.source}.${candidate.column}`);
381
+ const lead = resolution.explanation?.[0] ?? "The request is ambiguous.";
382
+ const question = names.length > 0 ? `${lead} Did you mean ${names.join(" or ")}?` : lead;
383
+ return {
384
+ status: "needs_clarification",
385
+ question,
386
+ candidates: passthroughCandidates(resolution),
387
+ explanation: resolution.explanation ?? []
388
+ };
389
+ }
390
+ function rejectedOutput(resolution) {
391
+ return {
392
+ status: "rejected",
393
+ rejection_reason: resolution.rejection_reason ?? "rejected",
394
+ candidates: passthroughCandidates(resolution),
395
+ explanation: resolution.explanation ?? []
396
+ };
397
+ }
398
+ function renderSignature(entry) {
399
+ const params = entry.signature.params;
400
+ const rendered = params.map((param) => `${param.name}${param.required === false ? "?" : ""}: ${param.type}`).join(", ");
401
+ return `${entry.name}(${rendered}) -> ${entry.signature.returns}`;
402
+ }
403
+ function splitCapabilityName(name) {
404
+ const separator = name.lastIndexOf(".");
405
+ return { module: name.slice(0, separator), functionName: name.slice(separator + 1) };
406
+ }
407
+ function toQuerySpec(spec, options) {
408
+ const sourceName = spec.source ?? options.source;
409
+ return {
410
+ metric: spec.metric,
411
+ ...spec.aggregation ? { aggregation: spec.aggregation } : {},
412
+ ...spec.group_by ? { group_by: spec.group_by } : {},
413
+ ...spec.filter ? { filter: spec.filter } : {},
414
+ limit: Math.min(spec.limit ?? options.defaultLimit, options.maxExecutionRows),
415
+ ...spec.order ? { order: spec.order } : {},
416
+ ...sourceName ? { source_name: sourceName } : {}
417
+ };
418
+ }
419
+ function toComputationSpec(spec) {
420
+ return {
421
+ module: spec.module,
422
+ function: spec.function,
423
+ args: spec.args ?? [],
424
+ ...spec.kwargs ? { kwargs: spec.kwargs } : {},
425
+ ...spec.bindings ? { bindings: spec.bindings } : {},
426
+ ...spec.seed !== void 0 ? { seed: spec.seed } : {}
427
+ };
428
+ }
429
+ var NUMBER_OPS = [
430
+ "sum",
431
+ "avg",
432
+ "count",
433
+ "min",
434
+ "max",
435
+ "eq",
436
+ "in",
437
+ "gt",
438
+ "gte",
439
+ "lt",
440
+ "lte",
441
+ "is_null",
442
+ "is_not_null"
443
+ ];
444
+ var FILTER_ONLY_OPS = ["eq", "in", "is_null", "is_not_null"];
445
+ function opsForFieldType(type) {
446
+ if (type === "number") {
447
+ return [...NUMBER_OPS];
448
+ }
449
+ return [...FILTER_ONLY_OPS];
450
+ }
451
+ function describeSources(sources) {
452
+ return sources.map((source) => {
453
+ const typedFields = source.typed_fields.length > 0 ? source.typed_fields : source.fields.map((name) => ({ name, type: "unknown" }));
454
+ return {
455
+ name: source.name,
456
+ fields: typedFields.map((field) => ({
457
+ name: field.name,
458
+ type: field.type,
459
+ ops: opsForFieldType(field.type)
460
+ })),
461
+ row_count: source.row_count,
462
+ schema_revision: source.schema_revision
463
+ };
464
+ });
465
+ }
466
+ function searchModules(client, query) {
467
+ const matches = client.searchCapabilities(query, 100);
468
+ const byModule = /* @__PURE__ */ new Map();
469
+ for (const match of matches) {
470
+ const { module, functionName } = splitCapabilityName(match.entry.name);
471
+ let aggregate = byModule.get(module);
472
+ if (!aggregate) {
473
+ if (byModule.size >= 10) {
474
+ continue;
475
+ }
476
+ aggregate = {
477
+ name: module,
478
+ category: match.entry.category,
479
+ deterministic: true,
480
+ function_count: 0,
481
+ sample_functions: []
482
+ };
483
+ byModule.set(module, aggregate);
484
+ }
485
+ aggregate.function_count += 1;
486
+ if (aggregate.sample_functions.length < 5) {
487
+ aggregate.sample_functions.push(functionName);
488
+ }
489
+ }
490
+ return [...byModule.values()];
491
+ }
492
+ function moduleFunctions(client, index, moduleName) {
493
+ const prefix = `${moduleName}.`;
494
+ const entries = client.capabilities().capabilities.filter(
495
+ (entry) => entry.ai_sdk && isReadOnlyEligible(entry) && entry.name.startsWith(prefix)
496
+ );
497
+ if (entries.length === 0) {
498
+ throw new SqaiError("unsupported_operation", `Unknown capability module '${moduleName}'.`, {
499
+ details: { module: moduleName, nearest_matches: index().nearest(moduleName) }
500
+ });
501
+ }
502
+ return entries.map((entry) => ({
503
+ name: entry.name,
504
+ signature: renderSignature(entry),
505
+ params: entry.signature.params.map(
506
+ (param) => ({ name: param.name, type: param.type, required: param.required ?? true })
507
+ ),
508
+ returns: entry.signature.returns,
509
+ deterministic: entry.deterministic,
510
+ seed_required: entry.seed_required ?? false
511
+ }));
512
+ }
513
+ function createSqaiTools(toolkit, options = {}) {
514
+ const opts = { ...DEFAULT_OPTIONS, ...options };
515
+ const client = toolkit.client;
516
+ let cachedIndex = null;
517
+ const contractIndex = () => {
518
+ if (!cachedIndex) {
519
+ cachedIndex = new ContractIndex(client.capabilities());
520
+ }
521
+ return cachedIndex;
522
+ };
523
+ const listSources = tool({
524
+ description: "Discover what SQAI can touch. No arguments: list connected data sources with exact field names, types, and allowed operations \u2014 call this before queryData so specs use exact names. With capabilitySearch: search the deterministic computation catalog and get matching modules. With module: list that module's functions with exact signatures.",
525
+ inputSchema: listSourcesInputSchema,
526
+ outputSchema: listSourcesOutputSchema,
527
+ execute: async (input) => {
528
+ const notReady = await readyError(toolkit);
529
+ if (notReady) {
530
+ return toErrorOutput(notReady);
531
+ }
532
+ try {
533
+ if (input?.capabilitySearch) {
534
+ return { modules: searchModules(client, input.capabilitySearch) };
535
+ }
536
+ if (input?.module) {
537
+ return { functions: moduleFunctions(client, contractIndex, input.module) };
538
+ }
539
+ return { sources: describeSources(client.listSources()) };
540
+ } catch (error) {
541
+ return toErrorOutput(error);
542
+ }
543
+ }
544
+ });
545
+ const queryData = tool({
546
+ description: "Execute one deterministic, read-only SQAI request. Use kind 'query' for tabular questions (aggregations, grouping, filtering) over connected sources \u2014 call listSources first for exact field names. Use kind 'computation' for math (statistics, financial, vector/matrix, simulation) over arrays: never paste large data into args \u2014 use bindings to pull columns from connected sources. Simulation modules require a seed. Large results are truncated for context; the full result stays retrievable via result_id.",
547
+ inputSchema: queryDataInputSchema,
548
+ outputSchema: queryDataOutputSchema,
549
+ execute: async (input) => {
550
+ const notReady = await readyError(toolkit);
551
+ if (notReady) {
552
+ return toErrorOutput(notReady);
553
+ }
554
+ try {
555
+ if (input.kind === "query") {
556
+ return await runQuery(input.spec);
557
+ }
558
+ return await runComputation(input.spec);
559
+ } catch (error) {
560
+ return toErrorOutput(error);
561
+ }
562
+ }
563
+ });
564
+ const explainQuery = tool({
565
+ description: "Dry-run a queryData request without executing it. kind 'query': resolve and verify the plan (resolved_plan, plan steps, plan_hash, confidence, validated). kind 'computation': check the capability exists and get its exact signature, a preview invocation_hash, and whether a seed is required. Use this to debug clarifications and rejections before running queryData.",
566
+ inputSchema: explainQueryInputSchema,
567
+ outputSchema: explainQueryOutputSchema,
568
+ execute: async (input) => {
569
+ const notReady = await readyError(toolkit);
570
+ if (notReady) {
571
+ return toErrorOutput(notReady);
572
+ }
573
+ try {
574
+ if (input.kind === "query") {
575
+ return await explainQueryPlan(input.spec);
576
+ }
577
+ return explainComputation(input.spec);
578
+ } catch (error) {
579
+ return toErrorOutput(error);
580
+ }
581
+ }
582
+ });
583
+ async function runQuery(spec) {
584
+ const querySpec = toQuerySpec(spec, opts);
585
+ const outcome = await client.ask(querySpec);
586
+ if (outcome.status === "needs_clarification") {
587
+ return clarificationOutput(outcome.resolution);
588
+ }
589
+ if (outcome.status === "rejected") {
590
+ return rejectedOutput(outcome.resolution);
591
+ }
592
+ const { data, resolution } = outcome;
593
+ const shaped = shapeQueryResult(data.result, opts);
594
+ const sourceName = data.resolved_source || resolution.resolved_source || null;
595
+ const resultId = storeWithinCap(
596
+ data.result,
597
+ opts.maxOutputBytes,
598
+ (value) => client.storeResult(value, sourceName ? [sourceName] : [])
599
+ );
600
+ return {
601
+ status: "ok",
602
+ kind: "query",
603
+ data: shaped.data,
604
+ total_rows: shaped.total_rows,
605
+ returned_rows: shaped.returned_rows,
606
+ truncated: shaped.truncated,
607
+ ...resultId ? { result_id: resultId } : {},
608
+ plan_hash: data.plan_hash ?? resolution.plan_hash ?? null,
609
+ schema_revision: data.schema_revision ?? resolution.schema_revision ?? null,
610
+ source_name: sourceName,
611
+ intent_signature: resolution.intent_signature ?? null,
612
+ deterministic_scope: data.deterministic_scope ?? resolution.deterministic_scope ?? null,
613
+ decision_path: data.decision_path ?? resolution.decision_path ?? null,
614
+ validated: data.validated ?? resolution.validated ?? null,
615
+ request_id: data.request_id ?? resolution.request_id ?? null,
616
+ explanation: data.explanation ?? resolution.explanation ?? []
617
+ };
618
+ }
619
+ async function runComputation(spec) {
620
+ const result = await client.compute(toComputationSpec(spec));
621
+ const shaped = shapeComputationValue(result.value, opts);
622
+ const sourceIds = result.provenance?.bindings.map((binding) => binding.source_name) ?? [];
623
+ const resultId = storeWithinCap(
624
+ result.value,
625
+ opts.maxOutputBytes,
626
+ (value) => client.storeResult(value, sourceIds)
627
+ );
628
+ return {
629
+ status: "ok",
630
+ kind: "computation",
631
+ value: shaped.value,
632
+ value_type: result.value_type,
633
+ ...shaped.preview !== void 0 ? { preview: shaped.preview } : {},
634
+ ...shaped.element_count !== void 0 ? { element_count: shaped.element_count } : {},
635
+ truncated: shaped.truncated,
636
+ ...resultId ? { result_id: resultId } : {},
637
+ invocation_hash: result.invocation_hash,
638
+ computation_hash: result.computation_hash,
639
+ contract_hash: result.contract_hash,
640
+ determinism: result.determinism,
641
+ ...result.provenance ? { provenance: result.provenance } : {},
642
+ latency_ms: result.latency_ms,
643
+ request_id: result.request_id
644
+ };
645
+ }
646
+ async function explainQueryPlan(spec) {
647
+ const resolution = await client.resolve(toQuerySpec(spec, opts));
648
+ if (resolution.clarification_required) {
649
+ return clarificationOutput(resolution);
650
+ }
651
+ if (resolution.rejection_reason || !resolution.resolved_plan) {
652
+ return rejectedOutput(resolution);
653
+ }
654
+ const verification = await client.verify(resolution);
655
+ return {
656
+ status: "ok",
657
+ kind: "query",
658
+ resolved_plan: resolution.resolved_plan,
659
+ plan: resolution.plan ?? [],
660
+ plan_hash: resolution.plan_hash ?? null,
661
+ confidence: resolution.confidence,
662
+ validated: verification.valid === true
663
+ };
664
+ }
665
+ function explainComputation(spec) {
666
+ const index = contractIndex();
667
+ const entry = lookupCapability(index, spec.module, spec.function);
668
+ const bindings = spec.bindings ?? [];
669
+ const descriptors = bindings.flatMap(
670
+ (binding) => "parameters" in binding ? binding.parameters.map((parameter, position) => ({
671
+ parameter,
672
+ source_name: binding.source,
673
+ fields: [binding.fields[position] ?? ""],
674
+ input_hash: ""
675
+ })) : [
676
+ {
677
+ parameter: binding.parameter,
678
+ source_name: binding.source,
679
+ fields: [binding.field],
680
+ input_hash: ""
681
+ }
682
+ ]
683
+ );
684
+ const previewHash = invocationHash({
685
+ module: spec.module,
686
+ function: spec.function,
687
+ args: spec.args ?? [],
688
+ kwargs: spec.kwargs ?? {},
689
+ resolved_bindings: descriptors,
690
+ seed: spec.seed ?? null,
691
+ contract_hash: index.contract.capability_contract_hash,
692
+ execution_scope: `${currentPlatformKey()}:${client.mode}`
693
+ });
694
+ return {
695
+ status: "ok",
696
+ kind: "computation",
697
+ matched_signature: renderSignature(entry),
698
+ invocation_hash: previewHash,
699
+ seed_required: entry.seed_required ?? false
700
+ };
701
+ }
702
+ return { listSources, queryData, explainQuery };
703
+ }
704
+
705
+ // src/toolkit.ts
706
+ var SQAIToolkit = class {
707
+ client;
708
+ sourceInputs;
709
+ readyPromise = null;
710
+ readyError = null;
711
+ constructor(config = {}) {
712
+ const { sources, ...clientConfig } = config;
713
+ this.client = new SQAI(clientConfig);
714
+ this.sourceInputs = sources ?? [];
715
+ }
716
+ /** Connected sources; connecting starts on first access. */
717
+ get ready() {
718
+ return this.ensureReady();
719
+ }
720
+ /** The stored connection failure, when `ready` rejected. */
721
+ get connectionError() {
722
+ return this.readyError;
723
+ }
724
+ ensureReady() {
725
+ if (!this.readyPromise) {
726
+ this.readyPromise = this.connectAll();
727
+ this.readyPromise.catch((error) => {
728
+ this.readyError = error instanceof SqaiError2 ? error : new SqaiError2(
729
+ "source_connection_failed",
730
+ `Connecting the configured sources failed: ${error instanceof Error ? error.message : String(error)}`
731
+ );
732
+ });
733
+ }
734
+ return this.readyPromise;
735
+ }
736
+ async connect(source, options = {}) {
737
+ return this.client.connect(source, options);
738
+ }
739
+ tools(options = {}) {
740
+ return createSqaiTools(this, options);
741
+ }
742
+ async connectAll() {
743
+ for (const input of this.sourceInputs) {
744
+ if (typeof input === "string" || Array.isArray(input)) {
745
+ await this.client.connect(input);
746
+ } else {
747
+ await this.client.connect(input.data, input.name ? { name: input.name } : {});
748
+ }
749
+ }
750
+ return this.client.listSources();
751
+ }
752
+ };
753
+ function createSQAI(config = {}) {
754
+ return new SQAIToolkit(config);
755
+ }
756
+
757
+ // src/index.ts
758
+ import { SQAI as SQAI2, SqaiError as SqaiError3 } from "@thyn-ai/sqai";
759
+ export {
760
+ SQAI2 as SQAI,
761
+ SQAIToolkit,
762
+ SqaiError3 as SqaiError,
763
+ algentaWireValueSchema,
764
+ bindingProvenanceSchema,
765
+ candidateSchema,
766
+ clarificationOutputSchema,
767
+ computationBindingSchema,
768
+ computationOkOutputSchema,
769
+ computationSpecSchema,
770
+ createSQAI,
771
+ createSqaiTools,
772
+ determinismEnvelopeSchema,
773
+ errorOutputSchema,
774
+ explainQueryInputSchema,
775
+ explainQueryOkComputationOutputSchema,
776
+ explainQueryOkQueryOutputSchema,
777
+ explainQueryOutputSchema,
778
+ filterConditionSchema,
779
+ filterSpecSchema,
780
+ functionListOutputSchema,
781
+ listSourcesInputSchema,
782
+ listSourcesOutputSchema,
783
+ moduleListOutputSchema,
784
+ queryDataInputSchema,
785
+ queryDataOutputSchema,
786
+ queryOkOutputSchema,
787
+ querySpecSchema,
788
+ rejectedOutputSchema,
789
+ shapeComputationValue,
790
+ shapeQueryResult,
791
+ sourceListOutputSchema,
792
+ storeWithinCap
793
+ };
794
+ //# sourceMappingURL=index.js.map