@tryvira/sdk 0.1.12 → 0.1.14

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 CHANGED
@@ -1,831 +1,840 @@
1
- // ../../sdks/js-client.ts
2
- var ViraApiError = class extends Error {
3
- status;
4
- body;
5
- requestId;
6
- constructor(message, status, body, requestId) {
7
- super(message);
8
- this.name = "ViraApiError";
9
- this.status = status;
10
- this.body = body;
11
- this.requestId = requestId;
12
- }
13
- };
14
- var required = (value, code) => {
15
- if (typeof value !== "string" || !value.trim()) throw new Error(code);
16
- return value;
17
- };
18
- var wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
19
- var ViraClient = class {
20
- baseUrl;
21
- apiKey;
22
- fetcher;
23
- timeoutMs;
24
- retries;
25
- failureMode;
26
- defaultHeaders;
27
- constructor(options) {
28
- this.baseUrl = required(options.baseUrl, "SDK_BASE_URL_REQUIRED").replace(
29
- /\/$/,
30
- ""
31
- );
32
- this.apiKey = options.apiKey;
33
- this.fetcher = options.fetcher ?? fetch;
34
- this.timeoutMs = Math.max(
35
- 1e3,
36
- Math.min(options.timeoutMs ?? 15e3, 12e4)
37
- );
38
- this.retries = Math.max(0, Math.min(options.retries ?? 2, 5));
39
- this.failureMode = options.failureMode ?? "throw";
40
- this.defaultHeaders = options.defaultHeaders ?? {};
41
- }
42
- async request(request, options = {}) {
43
- const url = new URL(this.baseUrl + request.path);
44
- for (const [key, value] of Object.entries(request.query ?? {}))
45
- url.searchParams.set(key, value);
46
- const headers = {
47
- accept: "application/json",
48
- ...this.defaultHeaders
49
- };
50
- if (request.body) headers["content-type"] = "application/json";
51
- if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;
52
- if (options.idempotencyKey)
53
- headers["idempotency-key"] = options.idempotencyKey;
54
- const retryable = request.method === "GET" || Boolean(options.idempotencyKey);
55
- const attempts = retryable ? this.retries + 1 : 1;
56
- let lastError;
57
- for (let attempt = 0; attempt < attempts; attempt += 1) {
58
- const controller = new AbortController();
59
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
60
- try {
61
- const response = await this.fetcher(url, {
62
- method: request.method,
63
- headers,
64
- body: request.body ? JSON.stringify(request.body) : void 0,
65
- signal: controller.signal
66
- });
67
- const raw = await response.text();
68
- let body = null;
69
- try {
70
- body = raw ? JSON.parse(raw) : null;
71
- } catch {
72
- body = raw;
73
- }
74
- const requestId = response.headers.get("x-request-id") ?? "";
75
- if (!response.ok) {
76
- const error = new ViraApiError(
77
- `VIRA_API_${response.status}`,
78
- response.status,
79
- body,
80
- requestId
81
- );
82
- if ((response.status >= 500 || response.status === 429) && attempt + 1 < attempts) {
83
- const retryAfter = Number(response.headers.get("retry-after") ?? "");
84
- const serverDelay = Number.isFinite(retryAfter) && retryAfter >= 0 ? Math.min(retryAfter * 1e3, 12e4) : 0;
85
- const jitter = Math.floor(Math.random() * 25);
86
- await wait(Math.max(serverDelay, 25 * 2 ** attempt) + jitter);
87
- continue;
88
- }
89
- if (this.failureMode === "open" && !options.enforcing && response.status >= 500)
90
- return null;
91
- throw error;
92
- }
93
- return { status: response.status, body, requestId };
94
- } catch (error) {
95
- lastError = error;
96
- if (error instanceof ViraApiError) throw error;
97
- if (attempt + 1 < attempts) {
98
- await wait(25 * 2 ** attempt);
99
- continue;
100
- }
101
- if (this.failureMode === "open" && !options.enforcing) return null;
102
- throw error;
103
- } finally {
104
- clearTimeout(timer);
105
- }
106
- }
107
- throw lastError;
108
- }
109
- connectSystem(input) {
110
- const request = buildAISystemRequest(input);
111
- return this.request(request, {
112
- idempotencyKey: input.idempotencyKey
113
- });
114
- }
115
- listAISystems() {
116
- return this.request({ method: "GET", path: "/v1/ai-systems" });
117
- }
118
- deleteAISystem(systemId, options = {}) {
119
- required(systemId, "SDK_SYSTEM_ID_REQUIRED");
120
- return this.request({ method: "DELETE", path: `/v1/ai-systems/${encodeURIComponent(systemId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:ai-system:${systemId}` });
121
- }
122
- getAISystem(systemId) {
123
- required(systemId, "SDK_SYSTEM_ID_REQUIRED");
124
- return this.request({ method: "GET", path: `/v1/ai-systems/${encodeURIComponent(systemId)}` });
125
- }
126
- connectAdapter(systemId, input) {
127
- required(systemId, "SDK_SYSTEM_ID_REQUIRED");
128
- const body = {
129
- ...input,
130
- capabilities: [...input.capabilities ?? []]
131
- };
132
- delete body.idempotencyKey;
133
- return this.request(
134
- {
135
- method: "POST",
136
- path: `/v1/ai-systems/${encodeURIComponent(systemId)}/connections`,
137
- body
138
- },
139
- { idempotencyKey: input.idempotencyKey }
140
- );
141
- }
142
- async connectOnce(input) {
143
- const systemResult = await this.connectSystem(input);
144
- if (!systemResult) return null;
145
- const systemId = String(systemResult.body.system.id ?? "");
146
- required(systemId, "SDK_SYSTEM_ID_MISSING");
147
- const connectionResult = await this.connectAdapter(systemId, {
148
- adapterType: input.adapterType,
149
- adapterVersion: input.adapterVersion,
150
- capabilities: input.capabilities,
151
- config: input.config,
152
- idempotencyKey: input.idempotencyKey
153
- });
154
- if (!connectionResult) return null;
155
- return {
156
- status: connectionResult.status,
157
- requestId: connectionResult.requestId,
158
- body: {
159
- system: systemResult.body.system,
160
- connection: connectionResult.body.connection,
161
- handshake: connectionResult.body.handshake
162
- }
163
- };
164
- }
165
- observe(event, options = {}) {
166
- return this.request(buildObservationRequest(event), {
167
- idempotencyKey: options.idempotencyKey ?? event.eventId
168
- });
169
- }
170
- trace(event, options = {}) {
171
- return this.observe({ ...event, eventType: "model.response" }, options);
172
- }
173
- outcome(event, options = {}) {
174
- return this.observe({ ...event, eventType: "business.outcome" }, options);
175
- }
176
- feedback(event, options = {}) {
177
- return this.observe({ ...event, eventType: "feedback.user" }, options);
178
- }
179
- observeBatch(events, options = {}) {
180
- if (!Array.isArray(events) || events.length < 1 || events.length > 100)
181
- throw new Error("SDK_OBSERVATION_BATCH_INVALID");
182
- return this.request(
183
- {
184
- method: "POST",
185
- path: "/v1/observations/batch",
186
- body: { events: [...events] }
187
- },
188
- { idempotencyKey: options.idempotencyKey }
189
- );
190
- }
191
- observeSdk(delivery, options = {}) {
192
- return this.request(
193
- { method: "POST", path: "/v1/observations/sdk", body: delivery },
194
- { idempotencyKey: options.idempotencyKey }
195
- );
196
- }
197
- discover(reviewState) {
198
- return this.request({
199
- method: "GET",
200
- path: "/v1/discovery/candidates",
201
- query: reviewState ? { reviewState } : void 0
202
- });
203
- }
204
- createSignalDiscoveryProposal(input, options = {}) {
205
- return this.request({ method: "POST", path: "/v1/signals/discovery-proposals", body: input }, { idempotencyKey: options.idempotencyKey ?? String(input.signalStableKey ?? "") });
206
- }
207
- reviewSignalDiscoveryProposal(proposalId, decision, options = {}) {
208
- required(proposalId, "SDK_SIGNAL_PROPOSAL_ID_REQUIRED");
209
- return this.request({ method: "POST", path: `/v1/signals/discovery-proposals/${encodeURIComponent(proposalId)}/review`, body: { decision } }, { idempotencyKey: options.idempotencyKey ?? `signal-review:${proposalId}` });
210
- }
211
- materializeSignalDiscovery(proposalId, input = {}, options = {}) {
212
- required(proposalId, "SDK_SIGNAL_PROPOSAL_ID_REQUIRED");
213
- return this.request({ method: "POST", path: `/v1/signals/discovery-proposals/${encodeURIComponent(proposalId)}/materialize`, body: input }, { idempotencyKey: options.idempotencyKey ?? `signal-materialize:${proposalId}` });
214
- }
215
- createSignalMapping(input, options = {}) {
216
- return this.request({ method: "POST", path: "/v1/signals/mappings", body: input }, { idempotencyKey: options.idempotencyKey ?? String(input.signalStableKey ?? "") });
217
- }
218
- getSignalMapping(mappingId) {
219
- required(mappingId, "SDK_SIGNAL_MAPPING_ID_REQUIRED");
220
- return this.request({ method: "GET", path: `/v1/signals/mappings/${encodeURIComponent(mappingId)}` });
221
- }
222
- reviewSignalMapping(mappingId, input = {}, options = {}) {
223
- required(mappingId, "SDK_SIGNAL_MAPPING_ID_REQUIRED");
224
- return this.request({ method: "POST", path: `/v1/signals/mappings/${encodeURIComponent(mappingId)}/review`, body: input }, { idempotencyKey: options.idempotencyKey ?? `signal-mapping-review:${mappingId}` });
225
- }
226
- connectionHealth(connectionId) {
227
- required(connectionId, "SDK_CONNECTION_ID_REQUIRED");
228
- return this.request({
229
- method: "GET",
230
- path: `/v1/connections/${encodeURIComponent(connectionId)}/health`
231
- });
232
- }
233
- inventory(systemId) {
234
- required(systemId, "SDK_SYSTEM_ID_REQUIRED");
235
- return this.request({
236
- method: "GET",
237
- path: `/v1/ai-systems/${encodeURIComponent(systemId)}/inventory`
238
- });
239
- }
240
- listPacks() {
241
- return this.request({
242
- method: "GET",
243
- path: "/v1/packs"
244
- });
245
- }
246
- importPack(input) {
247
- if (!input?.manifest && !input?.archiveBase64)
248
- throw new Error("SDK_PACK_MANIFEST_OR_ARCHIVE_REQUIRED");
249
- if (input.archiveBase64 && !input.fileName)
250
- throw new Error("SDK_PACK_FILE_NAME_REQUIRED");
251
- return this.request(
252
- {
253
- method: "POST",
254
- path: "/v1/packs/import",
255
- body: {
256
- ...input.manifest ? { manifest: input.manifest } : {},
257
- objects: input.objects ?? {},
258
- ...input.archiveBase64 ? { archiveBase64: input.archiveBase64, fileName: input.fileName } : {}
259
- }
260
- },
261
- { idempotencyKey: input.idempotencyKey ?? `sdk:pack:${Date.now()}` }
262
- );
263
- }
264
- installPack(packId, variables = {}) {
265
- required(packId, "SDK_PACK_ID_REQUIRED");
266
- return this.request(
267
- {
268
- method: "POST",
269
- path: `/v1/packs/${encodeURIComponent(packId)}/install`,
270
- body: { variables }
271
- },
272
- { idempotencyKey: `sdk:pack:install:${packId}` }
273
- );
274
- }
275
- evaluatePack(packId, input) {
276
- required(packId, "SDK_PACK_ID_REQUIRED");
277
- return this.request(
278
- {
279
- method: "POST",
280
- path: `/v1/packs/${encodeURIComponent(packId)}/evaluate`,
281
- body: { ...input }
282
- },
283
- { idempotencyKey: `sdk:pack:evaluate:${packId}` }
284
- );
285
- }
286
- approvePack(packId) {
287
- required(packId, "SDK_PACK_ID_REQUIRED");
288
- return this.request(
289
- {
290
- method: "POST",
291
- path: `/v1/packs/${encodeURIComponent(packId)}/approve`,
292
- body: {}
293
- },
294
- { idempotencyKey: `sdk:pack:approve:${packId}` }
295
- );
296
- }
297
- releasePack(packId) {
298
- required(packId, "SDK_PACK_ID_REQUIRED");
299
- return this.request(
300
- {
301
- method: "POST",
302
- path: `/v1/packs/${encodeURIComponent(packId)}/release`,
303
- body: {}
304
- },
305
- { idempotencyKey: `sdk:pack:release:${packId}` }
306
- );
307
- }
308
- previewPackUpgrade(packId, incoming) {
309
- required(packId, "SDK_PACK_ID_REQUIRED");
310
- if (!incoming || typeof incoming !== "object")
311
- throw new Error("SDK_PACK_UPGRADE_INPUT_REQUIRED");
312
- return this.request(
313
- {
314
- method: "POST",
315
- path: `/v1/packs/${encodeURIComponent(packId)}/upgrade-preview`,
316
- body: { incoming }
317
- },
318
- { idempotencyKey: `sdk:pack:upgrade-preview:${packId}` }
319
- );
320
- }
321
- executeRuntime(input) {
322
- return this.request(
323
- {
324
- method: "POST",
325
- path: "/v1/runtime/execute",
326
- body: buildRuntimeRequest(
327
- input
328
- )
329
- },
330
- { idempotencyKey: input.idempotencyKey, enforcing: true }
331
- );
332
- }
333
- resolveRuntime(input) {
334
- if (!input.behaviorPoint && !input.executionBoundary && !input.semanticContext)
335
- throw new Error("SDK_RUNTIME_ROUTE_REQUIRED");
336
- return this.request(
337
- {
338
- method: "POST",
339
- path: "/v1/runtime/resolve",
340
- body: {
341
- ...input.behaviorPoint ? { behaviorPoint: input.behaviorPoint } : {},
342
- ...input.executionBoundary ? { executionBoundary: input.executionBoundary } : {},
343
- ...input.semanticContext ? { semanticContext: input.semanticContext } : {}
344
- }
345
- },
346
- {
347
- idempotencyKey: input.idempotencyKey ?? `sdk:resolve:${input.behaviorPoint ?? "boundary"}`,
348
- enforcing: true
349
- }
350
- );
351
- }
352
- /** Resolve a runtime route from a governed execution boundary and semantic context. */
353
- resolveBoundary(input) {
354
- if (!input.executionBoundary || typeof input.executionBoundary !== "object")
355
- throw new Error("SDK_EXECUTION_BOUNDARY_REQUIRED");
356
- return this.resolveRuntime({
357
- executionBoundary: input.executionBoundary,
358
- ...input.semanticContext ? { semanticContext: input.semanticContext } : {},
359
- idempotencyKey: input.idempotencyKey
360
- });
361
- }
362
- resolveSemantic(input) {
363
- required(input.input, "SDK_SEMANTIC_INPUT_REQUIRED");
364
- const { idempotencyKey, requestId, ...body } = input;
365
- const resolvedRequestId = requestId ?? `sdk-semantic-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
366
- return this.request(
367
- {
368
- method: "POST",
369
- path: "/v1/semantic/resolve",
370
- body: { ...body, requestId: resolvedRequestId }
371
- },
372
- { idempotencyKey: idempotencyKey ?? `sdk:semantic:${resolvedRequestId}` }
373
- );
374
- }
375
- async resolveSemanticRuntime(input) {
376
- const semantic = await this.resolveSemantic(input);
377
- if (!semantic) return null;
378
- const body = semantic.body;
379
- const receipt = body.receipt && typeof body.receipt === "object" ? body.receipt : {};
380
- if (receipt.outcome !== "select" || typeof receipt.taskKey !== "string")
381
- return { semantic, runtime: null };
382
- const capsules = Array.isArray(body.capsules) ? body.capsules : [];
383
- const firstCapsule = capsules[0] && typeof capsules[0] === "object" ? capsules[0] : {};
384
- const behaviorPoint = typeof firstCapsule.behaviorKey === "string" && firstCapsule.behaviorKey.trim() ? firstCapsule.behaviorKey : receipt.taskKey;
385
- const runtime = input.executionBoundary ? await this.resolveBoundary({
386
- executionBoundary: input.executionBoundary,
387
- semanticContext: {
388
- taskKey: receipt.taskKey,
389
- behaviorPoint,
390
- capsule: firstCapsule
391
- },
392
- idempotencyKey: input.idempotencyKey ? `sdk:runtime:${input.idempotencyKey}` : void 0
393
- }) : await this.resolveRuntime({
394
- semanticContext: { taskKey: receipt.taskKey, behaviorPoint, capsule: firstCapsule },
395
- idempotencyKey: input.idempotencyKey ? `sdk:runtime:${input.idempotencyKey}` : void 0
396
- });
397
- return { semantic, runtime };
398
- }
399
- listBehaviorStrategies() {
400
- return this.request({
401
- method: "GET",
402
- path: "/v1/behavior-strategies"
403
- });
404
- }
405
- deleteBehaviorStrategy(strategyId, options = {}) {
406
- required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
407
- return this.request({ method: "DELETE", path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:strategy:${strategyId}` });
408
- }
409
- getBehaviorStrategy(strategyId) {
410
- required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
411
- return this.request({
412
- method: "GET",
413
- path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}`
414
- });
415
- }
416
- createBehaviorStrategy(definition, id) {
417
- if (!definition) throw new Error("SDK_STRATEGY_DEFINITION_REQUIRED");
418
- return this.request({
419
- method: "POST",
420
- path: "/v1/behavior-strategies",
421
- body: { definition, ...id ? { id } : {} }
422
- });
423
- }
424
- listSemanticTasks() {
425
- return this.request({ method: "GET", path: "/v1/semantic-tasks" });
426
- }
427
- deleteSemanticTask(taskId, options = {}) {
428
- required(taskId, "SDK_SEMANTIC_TASK_ID_REQUIRED");
429
- return this.request({ method: "DELETE", path: `/v1/semantic-tasks/${encodeURIComponent(taskId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:semantic-task:${taskId}` });
430
- }
431
- createSemanticTask(task, options = {}) {
432
- required(task?.taskKey, "SDK_SEMANTIC_TASK_KEY_REQUIRED");
433
- return this.request({ method: "POST", path: "/v1/semantic-tasks", body: { ...task, ...options.id ? { id: options.id } : {} } }, { idempotencyKey: options.idempotencyKey ?? `sdk:semantic-task:${task.taskKey}` });
434
- }
435
- listBehaviorPoints() {
436
- return this.request({ method: "GET", path: "/v1/behavior-points" });
437
- }
438
- deleteBehaviorPoint(pointId, options = {}) {
439
- required(pointId, "SDK_BEHAVIOR_POINT_ID_REQUIRED");
440
- return this.request({ method: "DELETE", path: `/v1/behavior-points/${encodeURIComponent(pointId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:behavior-point:${pointId}` });
441
- }
442
- createBehaviorPoint(point, options = {}) {
443
- required(point?.key, "SDK_BEHAVIOR_POINT_KEY_REQUIRED");
444
- if (!point.taskId && !point.taskIds?.length) throw new Error("SDK_BEHAVIOR_POINT_TASK_REQUIRED");
445
- return this.request({ method: "POST", path: "/v1/behavior-points", body: { ...point, ...options.id ? { id: options.id } : {} } }, { idempotencyKey: options.idempotencyKey ?? `sdk:behavior-point:${point.key}` });
446
- }
447
- createBehaviorStrategyVariant(strategyId, variant, options = {}) {
448
- required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
449
- if (!variant || typeof variant !== "object")
450
- throw new Error("SDK_STRATEGY_VARIANT_REQUIRED");
451
- return this.request(
452
- {
453
- method: "POST",
454
- path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/variants`,
455
- body: variant
456
- },
457
- { idempotencyKey: options.idempotencyKey }
458
- );
459
- }
460
- validateBehaviorStrategy(strategyId) {
461
- required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
462
- return this.request({
463
- method: "POST",
464
- path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/validate`,
465
- body: {}
466
- });
467
- }
468
- activateBehaviorStrategy(strategyId) {
469
- required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
470
- return this.request({ method: "POST", path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/activate`, body: {} });
471
- }
472
- simulateBehaviorStrategy(strategyId, initialState = {}) {
473
- required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
474
- return this.request({
475
- method: "POST",
476
- path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/simulate`,
477
- body: { initialState }
478
- });
479
- }
480
- startStrategyExecution(input) {
481
- required(input.artifactDigest, "SDK_ARTIFACT_DIGEST_REQUIRED");
482
- for (const value of [
483
- input.organizationId,
484
- input.projectId,
485
- input.environmentId,
486
- input.revisionId,
487
- input.idempotencyKey,
488
- input.nonce,
489
- input.decisionPlanId,
490
- input.policy
491
- ])
492
- required(value, "SDK_STRATEGY_START_FIELD_REQUIRED");
493
- if (input.behaviorPoint !== void 0)
494
- required(input.behaviorPoint, "SDK_BEHAVIOR_POINT_REQUIRED");
495
- if (!Array.isArray(input.candidates) || input.candidates.length === 0)
496
- throw new Error("SDK_STRATEGY_CANDIDATES_REQUIRED");
497
- if (!Number.isFinite(input.expiresAt))
498
- throw new Error("SDK_EXPIRY_REQUIRED");
499
- const body = {
500
- ...buildRuntimeRequest(input),
501
- artifactDigest: input.artifactDigest,
502
- ...input.behaviorPoint ? { behaviorPoint: input.behaviorPoint } : {},
503
- ...input.executionBoundary ? { executionBoundary: input.executionBoundary } : {},
504
- ...input.traceId ? { traceId: input.traceId } : {},
505
- ...input.executionId ? { executionId: input.executionId } : {},
506
- ...input.state ? { state: input.state } : {}
507
- };
508
- return this.request(
509
- { method: "POST", path: "/v1/runtime/strategy-executions", body },
510
- { idempotencyKey: input.idempotencyKey }
511
- );
512
- }
513
- getStrategyExecution(executionId) {
514
- required(executionId, "SDK_EXECUTION_ID_REQUIRED");
515
- return this.request({
516
- method: "GET",
517
- path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}`
518
- });
519
- }
520
- getStrategyExecutionTrace(executionId) {
521
- required(executionId, "SDK_EXECUTION_ID_REQUIRED");
522
- return this.request({
523
- method: "GET",
524
- path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}/trace`
525
- });
526
- }
527
- continueStrategyExecution(executionId, continuation) {
528
- required(executionId, "SDK_EXECUTION_ID_REQUIRED");
529
- const input = typeof continuation === "string" ? { authorityDigest: continuation } : continuation ?? {};
530
- return this.request({
531
- method: "POST",
532
- path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}/continue`,
533
- body: {
534
- ...input.authorityDigest ? { authorityDigest: input.authorityDigest } : {},
535
- ...input.state ? { state: input.state } : {},
536
- ...input.references ? { references: input.references } : {}
537
- }
538
- });
539
- }
540
- cancelStrategyExecution(executionId) {
541
- required(executionId, "SDK_EXECUTION_ID_REQUIRED");
542
- return this.request({
543
- method: "POST",
544
- path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}/cancel`,
545
- body: {}
546
- });
547
- }
548
- listBehaviorPrograms() {
549
- return this.request({
550
- method: "GET",
551
- path: "/v1/behavior-programs"
552
- });
553
- }
554
- listCapabilities(options = {}) {
555
- const query = options.surface ? `?surface=${encodeURIComponent(options.surface)}` : "";
556
- return this.request({ method: "GET", path: `/v1/capabilities${query}` });
557
- }
558
- getBehaviorProgram(programId) {
559
- required(programId, "SDK_PROGRAM_ID_REQUIRED");
560
- return this.request({
561
- method: "GET",
562
- path: `/v1/behavior-programs/${encodeURIComponent(programId)}`
563
- });
564
- }
565
- createBehaviorProgram(program, options = {}) {
566
- if (!program || typeof program !== "object")
567
- throw new Error("SDK_PROGRAM_REQUIRED");
568
- return this.request(
569
- { method: "POST", path: "/v1/behavior-programs", body: program },
570
- {
571
- idempotencyKey: options.idempotencyKey ?? `sdk:program:${String(program.id ?? "")}`
572
- }
573
- );
574
- }
575
- attestCapabilities(attestation, options = {}) {
576
- return this.request(
577
- {
578
- method: "POST",
579
- path: "/v1/runtime/capabilities/attest",
580
- body: attestation
581
- },
582
- { idempotencyKey: options.idempotencyKey }
583
- );
584
- }
585
- resolveCapabilities(attestationId, request, options = {}) {
586
- required(attestationId, "SDK_ATTESTATION_ID_REQUIRED");
587
- return this.request(
588
- {
589
- method: "POST",
590
- path: "/v1/runtime/capabilities/resolve",
591
- body: { attestationId, request }
592
- },
593
- { idempotencyKey: options.idempotencyKey, enforcing: true }
594
- );
595
- }
596
- recordCapabilityTrace(decisionDigest, trace, options = {}) {
597
- required(decisionDigest, "SDK_DECISION_DIGEST_REQUIRED");
598
- return this.request(
599
- {
600
- method: "POST",
601
- path: "/v1/runtime/capabilities/traces",
602
- body: { decisionDigest, trace }
603
- },
604
- { idempotencyKey: options.idempotencyKey }
605
- );
606
- }
607
- resolveModelServing(request, options = {}) {
608
- return this.request(
609
- { method: "POST", path: "/v1/model-serving/resolve", body: request },
610
- { idempotencyKey: options.idempotencyKey, enforcing: true }
611
- );
612
- }
613
- recordModelServingTrace(trace, selection, options = {}) {
614
- return this.request(
615
- {
616
- method: "POST",
617
- path: "/v1/model-serving/traces",
618
- body: { trace, selection }
619
- },
620
- { idempotencyKey: options.idempotencyKey }
621
- );
622
- }
623
- submitTeachEvidence(evidence, options = {}) {
624
- return this.request(
625
- { method: "POST", path: "/v1/teach/evidence", body: evidence },
626
- { idempotencyKey: options.idempotencyKey }
627
- );
628
- }
629
- createTeachProposal(input, options = {}) {
630
- return this.request({ method: "POST", path: "/v1/teach/proposals", body: input }, { idempotencyKey: options.idempotencyKey });
631
- }
632
- transitionTeachProposal(proposalId, transition, input = {}, options = {}) {
633
- required(proposalId, "SDK_TEACH_PROPOSAL_ID_REQUIRED");
634
- return this.request({ method: "POST", path: `/v1/teach/proposals/${encodeURIComponent(proposalId)}/${transition}`, body: input }, { idempotencyKey: options.idempotencyKey ?? `sdk:teach:${transition}:${proposalId}` });
635
- }
636
- startEvaluation(input, options = {}) {
637
- return this.request(
638
- { method: "POST", path: "/v1/evaluations", body: input },
639
- { idempotencyKey: options.idempotencyKey }
640
- );
641
- }
642
- evaluateQuality(input, options = {}) {
643
- return this.request(
644
- { method: "POST", path: "/v1/quality/evaluate", body: input },
645
- { idempotencyKey: options.idempotencyKey }
646
- );
647
- }
648
- getEvaluation(evaluationId) {
649
- required(evaluationId, "SDK_EVALUATION_ID_REQUIRED");
650
- return this.request({
651
- method: "GET",
652
- path: `/v1/evaluations/${encodeURIComponent(evaluationId)}`
653
- });
654
- }
655
- createRelease(input, options = {}) {
656
- return this.request(
657
- { method: "POST", path: "/v1/releases", body: input },
658
- { idempotencyKey: options.idempotencyKey }
659
- );
660
- }
661
- recordDeploymentComparison(deploymentId, comparison, options = {}) {
662
- required(deploymentId, "SDK_DEPLOYMENT_ID_REQUIRED");
663
- return this.request(
664
- {
665
- method: "POST",
666
- path: `/v1/deployments/${encodeURIComponent(deploymentId)}/comparisons`,
667
- body: comparison
668
- },
669
- { idempotencyKey: options.idempotencyKey }
670
- );
671
- }
672
- recordDeploymentHealth(deploymentId, health, options = {}) {
673
- required(deploymentId, "SDK_DEPLOYMENT_ID_REQUIRED");
674
- return this.request(
675
- {
676
- method: "POST",
677
- path: `/v1/deployments/${encodeURIComponent(deploymentId)}/authoritative-health`,
678
- body: health
679
- },
680
- { idempotencyKey: options.idempotencyKey }
681
- );
682
- }
683
- compileBehaviorCapsule(input) {
684
- required(input.programId, "SDK_PROGRAM_ID_REQUIRED");
685
- required(input.input, "SDK_RUNTIME_INPUT_REQUIRED");
686
- return this.request(
687
- {
688
- method: "POST",
689
- path: "/v1/runtime/behavior-capsule",
690
- body: { ...input }
691
- },
692
- {
693
- idempotencyKey: input.idempotencyKey ?? `sdk:capsule:${input.programId}`
694
- }
695
- );
696
- }
697
- serveBehaviorProjection(input) {
698
- required(input.input, "SDK_RUNTIME_INPUT_REQUIRED");
699
- required(input.provider, "SDK_PROVIDER_REQUIRED");
700
- return this.request(
701
- {
702
- method: "POST",
703
- path: "/v1/runtime/behavior-projection",
704
- body: { ...input }
705
- },
706
- {
707
- idempotencyKey: input.idempotencyKey ?? `sdk:projection:${input.programId ?? "active"}`
708
- }
709
- );
710
- }
711
- async testConnection(connectionId) {
712
- required(connectionId, "SDK_CONNECTION_ID_REQUIRED");
713
- return this.request({
714
- method: "POST",
715
- path: `/v1/connections/${encodeURIComponent(connectionId)}/test`,
716
- body: {}
717
- });
718
- }
719
- };
720
- function buildRuntimeRequest(input) {
721
- const {
722
- organizationId,
723
- projectId,
724
- environmentId,
725
- revisionId,
726
- idempotencyKey,
727
- nonce,
728
- expiresAt,
729
- decisionPlanId,
730
- calibrationId,
731
- candidates,
732
- allowedIds,
733
- policy,
734
- postModelJudge,
735
- shadow
736
- } = input;
737
- for (const value of [
738
- organizationId,
739
- projectId,
740
- environmentId,
741
- revisionId,
742
- idempotencyKey,
743
- nonce
744
- ])
745
- if (typeof value !== "string" || !value.trim())
746
- throw new Error("SDK_REQUEST_FIELD_REQUIRED");
747
- if (!Number.isFinite(expiresAt)) throw new Error("SDK_EXPIRY_REQUIRED");
748
- const boundary = {
749
- ...typeof decisionPlanId === "string" ? { decisionPlanId } : {},
750
- ...typeof calibrationId === "string" ? { calibrationId } : {},
751
- ...Array.isArray(candidates) ? { candidates } : {},
752
- ...Array.isArray(allowedIds) ? { allowedIds } : {},
753
- ...typeof policy === "string" ? { policy } : {},
754
- ...postModelJudge !== void 0 ? { postModelJudge } : {},
755
- ...shadow !== void 0 ? { shadow } : {}
756
- };
757
- return Object.freeze({
758
- organizationId,
759
- projectId,
760
- environmentId,
761
- revisionId,
762
- idempotencyKey,
763
- nonce,
764
- expiresAt,
765
- ...boundary
766
- });
767
- }
768
- function buildPublicContentRequest(input) {
769
- const { slug, version = "v1" } = input;
770
- if (typeof slug !== "string" || !slug.trim())
771
- throw new Error("SDK_SLUG_REQUIRED");
772
- if (version !== "v1") throw new Error("SDK_VERSION_UNSUPPORTED");
773
- return Object.freeze({
774
- method: "GET",
775
- path: "/v1/content",
776
- query: Object.freeze({ slug })
777
- });
778
- }
779
- function buildDocsQueryRequest(input) {
780
- const { query, operation = "search" } = input;
781
- if (typeof query !== "string" || !query.trim())
782
- throw new Error("SDK_QUERY_REQUIRED");
783
- if (!["search", "ask"].includes(operation))
784
- throw new Error("SDK_OPERATION_UNSUPPORTED");
785
- return Object.freeze({
786
- method: "GET",
787
- path: `/docs/${operation}`,
788
- query: Object.freeze({ query })
789
- });
790
- }
791
- function buildAISystemRequest(input) {
792
- const { name, systemType, organizationId, projectId, environmentId } = input;
793
- for (const value of [
794
- name,
795
- systemType,
796
- organizationId,
797
- projectId,
798
- environmentId
799
- ])
800
- if (typeof value !== "string" || !value.trim())
801
- throw new Error("SDK_AI_SYSTEM_FIELD_REQUIRED");
802
- return Object.freeze({
803
- method: "POST",
804
- path: "/v1/ai-systems",
805
- body: Object.freeze({
806
- name,
807
- systemType,
808
- organizationId,
809
- projectId,
810
- environmentId
811
- })
812
- });
813
- }
814
- function buildObservationRequest(event) {
815
- if (!event?.eventId || !event.eventType || !event.aiSystemId || !event.connectionId)
816
- throw new Error("SDK_OBSERVATION_FIELD_REQUIRED");
817
- return Object.freeze({
818
- method: "POST",
819
- path: "/v1/observations",
820
- body: Object.freeze({ ...event })
821
- });
822
- }
823
- export {
824
- ViraApiError,
825
- ViraClient,
826
- buildAISystemRequest,
827
- buildDocsQueryRequest,
828
- buildObservationRequest,
829
- buildPublicContentRequest,
830
- buildRuntimeRequest
831
- };
1
+ // sdks/js-client.ts
2
+ var ViraApiError = class extends Error {
3
+ status;
4
+ body;
5
+ requestId;
6
+ constructor(message, status, body, requestId) {
7
+ super(message);
8
+ this.name = "ViraApiError";
9
+ this.status = status;
10
+ this.body = body;
11
+ this.requestId = requestId;
12
+ }
13
+ };
14
+ var required = (value, code) => {
15
+ if (typeof value !== "string" || !value.trim()) throw new Error(code);
16
+ return value;
17
+ };
18
+ var wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
19
+ var ViraClient = class {
20
+ baseUrl;
21
+ apiKey;
22
+ fetcher;
23
+ timeoutMs;
24
+ retries;
25
+ failureMode;
26
+ defaultHeaders;
27
+ constructor(options) {
28
+ this.baseUrl = required(options.baseUrl, "SDK_BASE_URL_REQUIRED").replace(
29
+ /\/$/,
30
+ ""
31
+ );
32
+ this.apiKey = options.apiKey;
33
+ this.fetcher = options.fetcher ?? fetch;
34
+ this.timeoutMs = Math.max(
35
+ 1e3,
36
+ Math.min(options.timeoutMs ?? 15e3, 12e4)
37
+ );
38
+ this.retries = Math.max(0, Math.min(options.retries ?? 2, 5));
39
+ this.failureMode = options.failureMode ?? "throw";
40
+ this.defaultHeaders = options.defaultHeaders ?? {};
41
+ }
42
+ async request(request, options = {}) {
43
+ const url = new URL(this.baseUrl + request.path);
44
+ for (const [key, value] of Object.entries(request.query ?? {}))
45
+ url.searchParams.set(key, value);
46
+ const headers = {
47
+ accept: "application/json",
48
+ ...this.defaultHeaders
49
+ };
50
+ if (request.body) headers["content-type"] = "application/json";
51
+ if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;
52
+ if (options.idempotencyKey)
53
+ headers["idempotency-key"] = options.idempotencyKey;
54
+ const retryable = request.method === "GET" || Boolean(options.idempotencyKey);
55
+ const attempts = retryable ? this.retries + 1 : 1;
56
+ let lastError;
57
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
58
+ const controller = new AbortController();
59
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
60
+ try {
61
+ const response = await this.fetcher(url, {
62
+ method: request.method,
63
+ headers,
64
+ body: request.body ? JSON.stringify(request.body) : void 0,
65
+ signal: controller.signal
66
+ });
67
+ const raw = await response.text();
68
+ let body = null;
69
+ try {
70
+ body = raw ? JSON.parse(raw) : null;
71
+ } catch {
72
+ body = raw;
73
+ }
74
+ const requestId = response.headers.get("x-request-id") ?? "";
75
+ if (!response.ok) {
76
+ const error = new ViraApiError(
77
+ `VIRA_API_${response.status}`,
78
+ response.status,
79
+ body,
80
+ requestId
81
+ );
82
+ if ((response.status >= 500 || response.status === 429) && attempt + 1 < attempts) {
83
+ const retryAfter = Number(response.headers.get("retry-after") ?? "");
84
+ const serverDelay = Number.isFinite(retryAfter) && retryAfter >= 0 ? Math.min(retryAfter * 1e3, 12e4) : 0;
85
+ const jitter = Math.floor(Math.random() * 25);
86
+ await wait(Math.max(serverDelay, 25 * 2 ** attempt) + jitter);
87
+ continue;
88
+ }
89
+ if (this.failureMode === "open" && !options.enforcing && response.status >= 500)
90
+ return null;
91
+ throw error;
92
+ }
93
+ return { status: response.status, body, requestId };
94
+ } catch (error) {
95
+ lastError = error;
96
+ if (error instanceof ViraApiError) throw error;
97
+ if (attempt + 1 < attempts) {
98
+ await wait(25 * 2 ** attempt);
99
+ continue;
100
+ }
101
+ if (this.failureMode === "open" && !options.enforcing) return null;
102
+ throw error;
103
+ } finally {
104
+ clearTimeout(timer);
105
+ }
106
+ }
107
+ throw lastError;
108
+ }
109
+ connectSystem(input) {
110
+ const request = buildAISystemRequest(input);
111
+ return this.request(request, {
112
+ idempotencyKey: input.idempotencyKey
113
+ });
114
+ }
115
+ listAISystems() {
116
+ return this.request({ method: "GET", path: "/v1/ai-systems" });
117
+ }
118
+ deleteAISystem(systemId, options = {}) {
119
+ required(systemId, "SDK_SYSTEM_ID_REQUIRED");
120
+ return this.request({ method: "DELETE", path: `/v1/ai-systems/${encodeURIComponent(systemId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:ai-system:${systemId}` });
121
+ }
122
+ getAISystem(systemId) {
123
+ required(systemId, "SDK_SYSTEM_ID_REQUIRED");
124
+ return this.request({ method: "GET", path: `/v1/ai-systems/${encodeURIComponent(systemId)}` });
125
+ }
126
+ connectAdapter(systemId, input) {
127
+ required(systemId, "SDK_SYSTEM_ID_REQUIRED");
128
+ const body = {
129
+ ...input,
130
+ capabilities: [...input.capabilities ?? []]
131
+ };
132
+ delete body.idempotencyKey;
133
+ return this.request(
134
+ {
135
+ method: "POST",
136
+ path: `/v1/ai-systems/${encodeURIComponent(systemId)}/connections`,
137
+ body
138
+ },
139
+ { idempotencyKey: input.idempotencyKey }
140
+ );
141
+ }
142
+ async connectOnce(input) {
143
+ const systemResult = await this.connectSystem(input);
144
+ if (!systemResult) return null;
145
+ const systemId = String(systemResult.body.system.id ?? "");
146
+ required(systemId, "SDK_SYSTEM_ID_MISSING");
147
+ const connectionResult = await this.connectAdapter(systemId, {
148
+ adapterType: input.adapterType,
149
+ adapterVersion: input.adapterVersion,
150
+ capabilities: input.capabilities,
151
+ config: input.config,
152
+ idempotencyKey: input.idempotencyKey
153
+ });
154
+ if (!connectionResult) return null;
155
+ return {
156
+ status: connectionResult.status,
157
+ requestId: connectionResult.requestId,
158
+ body: {
159
+ system: systemResult.body.system,
160
+ connection: connectionResult.body.connection,
161
+ handshake: connectionResult.body.handshake
162
+ }
163
+ };
164
+ }
165
+ observe(event, options = {}) {
166
+ return this.request(buildObservationRequest(event), {
167
+ idempotencyKey: options.idempotencyKey ?? event.eventId
168
+ });
169
+ }
170
+ trace(event, options = {}) {
171
+ return this.observe({ ...event, eventType: "model.response" }, options);
172
+ }
173
+ outcome(event, options = {}) {
174
+ return this.observe({ ...event, eventType: "business.outcome" }, options);
175
+ }
176
+ feedback(event, options = {}) {
177
+ return this.observe({ ...event, eventType: "feedback.user" }, options);
178
+ }
179
+ observeBatch(events, options = {}) {
180
+ if (!Array.isArray(events) || events.length < 1 || events.length > 100)
181
+ throw new Error("SDK_OBSERVATION_BATCH_INVALID");
182
+ return this.request(
183
+ {
184
+ method: "POST",
185
+ path: "/v1/observations/batch",
186
+ body: { events: [...events] }
187
+ },
188
+ { idempotencyKey: options.idempotencyKey }
189
+ );
190
+ }
191
+ observeSdk(delivery, options = {}) {
192
+ return this.request(
193
+ { method: "POST", path: "/v1/observations/sdk", body: delivery },
194
+ { idempotencyKey: options.idempotencyKey }
195
+ );
196
+ }
197
+ discover(reviewState) {
198
+ return this.request({
199
+ method: "GET",
200
+ path: "/v1/discovery/candidates",
201
+ query: reviewState ? { reviewState } : void 0
202
+ });
203
+ }
204
+ createSignalDiscoveryProposal(input, options = {}) {
205
+ return this.request({ method: "POST", path: "/v1/signals/discovery-proposals", body: input }, { idempotencyKey: options.idempotencyKey ?? String(input.signalStableKey ?? "") });
206
+ }
207
+ reviewSignalDiscoveryProposal(proposalId, decision, options = {}) {
208
+ required(proposalId, "SDK_SIGNAL_PROPOSAL_ID_REQUIRED");
209
+ return this.request({ method: "POST", path: `/v1/signals/discovery-proposals/${encodeURIComponent(proposalId)}/review`, body: { decision } }, { idempotencyKey: options.idempotencyKey ?? `signal-review:${proposalId}` });
210
+ }
211
+ materializeSignalDiscovery(proposalId, input = {}, options = {}) {
212
+ required(proposalId, "SDK_SIGNAL_PROPOSAL_ID_REQUIRED");
213
+ return this.request({ method: "POST", path: `/v1/signals/discovery-proposals/${encodeURIComponent(proposalId)}/materialize`, body: input }, { idempotencyKey: options.idempotencyKey ?? `signal-materialize:${proposalId}` });
214
+ }
215
+ createSignalMapping(input, options = {}) {
216
+ return this.request({ method: "POST", path: "/v1/signals/mappings", body: input }, { idempotencyKey: options.idempotencyKey ?? String(input.signalStableKey ?? "") });
217
+ }
218
+ getSignalMapping(mappingId) {
219
+ required(mappingId, "SDK_SIGNAL_MAPPING_ID_REQUIRED");
220
+ return this.request({ method: "GET", path: `/v1/signals/mappings/${encodeURIComponent(mappingId)}` });
221
+ }
222
+ reviewSignalMapping(mappingId, input = {}, options = {}) {
223
+ required(mappingId, "SDK_SIGNAL_MAPPING_ID_REQUIRED");
224
+ return this.request({ method: "POST", path: `/v1/signals/mappings/${encodeURIComponent(mappingId)}/review`, body: input }, { idempotencyKey: options.idempotencyKey ?? `signal-mapping-review:${mappingId}` });
225
+ }
226
+ connectionHealth(connectionId) {
227
+ required(connectionId, "SDK_CONNECTION_ID_REQUIRED");
228
+ return this.request({
229
+ method: "GET",
230
+ path: `/v1/connections/${encodeURIComponent(connectionId)}/health`
231
+ });
232
+ }
233
+ inventory(systemId) {
234
+ required(systemId, "SDK_SYSTEM_ID_REQUIRED");
235
+ return this.request({
236
+ method: "GET",
237
+ path: `/v1/ai-systems/${encodeURIComponent(systemId)}/inventory`
238
+ });
239
+ }
240
+ listPacks() {
241
+ return this.request({
242
+ method: "GET",
243
+ path: "/v1/packs"
244
+ });
245
+ }
246
+ importPack(input) {
247
+ if (!input?.manifest && !input?.archiveBase64)
248
+ throw new Error("SDK_PACK_MANIFEST_OR_ARCHIVE_REQUIRED");
249
+ if (input.archiveBase64 && !input.fileName)
250
+ throw new Error("SDK_PACK_FILE_NAME_REQUIRED");
251
+ return this.request(
252
+ {
253
+ method: "POST",
254
+ path: "/v1/packs/import",
255
+ body: {
256
+ ...input.manifest ? { manifest: input.manifest } : {},
257
+ objects: input.objects ?? {},
258
+ ...input.archiveBase64 ? { archiveBase64: input.archiveBase64, fileName: input.fileName } : {}
259
+ }
260
+ },
261
+ { idempotencyKey: input.idempotencyKey ?? `sdk:pack:${Date.now()}` }
262
+ );
263
+ }
264
+ installPack(packId, variables = {}) {
265
+ required(packId, "SDK_PACK_ID_REQUIRED");
266
+ return this.request(
267
+ {
268
+ method: "POST",
269
+ path: `/v1/packs/${encodeURIComponent(packId)}/install`,
270
+ body: { variables }
271
+ },
272
+ { idempotencyKey: `sdk:pack:install:${packId}` }
273
+ );
274
+ }
275
+ evaluatePack(packId, input) {
276
+ required(packId, "SDK_PACK_ID_REQUIRED");
277
+ return this.request(
278
+ {
279
+ method: "POST",
280
+ path: `/v1/packs/${encodeURIComponent(packId)}/evaluate`,
281
+ body: { ...input }
282
+ },
283
+ { idempotencyKey: `sdk:pack:evaluate:${packId}` }
284
+ );
285
+ }
286
+ approvePack(packId) {
287
+ required(packId, "SDK_PACK_ID_REQUIRED");
288
+ return this.request(
289
+ {
290
+ method: "POST",
291
+ path: `/v1/packs/${encodeURIComponent(packId)}/approve`,
292
+ body: {}
293
+ },
294
+ { idempotencyKey: `sdk:pack:approve:${packId}` }
295
+ );
296
+ }
297
+ releasePack(packId) {
298
+ required(packId, "SDK_PACK_ID_REQUIRED");
299
+ return this.request(
300
+ {
301
+ method: "POST",
302
+ path: `/v1/packs/${encodeURIComponent(packId)}/release`,
303
+ body: {}
304
+ },
305
+ { idempotencyKey: `sdk:pack:release:${packId}` }
306
+ );
307
+ }
308
+ previewPackUpgrade(packId, incoming) {
309
+ required(packId, "SDK_PACK_ID_REQUIRED");
310
+ if (!incoming || typeof incoming !== "object")
311
+ throw new Error("SDK_PACK_UPGRADE_INPUT_REQUIRED");
312
+ return this.request(
313
+ {
314
+ method: "POST",
315
+ path: `/v1/packs/${encodeURIComponent(packId)}/upgrade-preview`,
316
+ body: { incoming }
317
+ },
318
+ { idempotencyKey: `sdk:pack:upgrade-preview:${packId}` }
319
+ );
320
+ }
321
+ executeRuntime(input) {
322
+ return this.request(
323
+ {
324
+ method: "POST",
325
+ path: "/v1/runtime/execute",
326
+ body: buildRuntimeRequest(
327
+ input
328
+ )
329
+ },
330
+ { idempotencyKey: input.idempotencyKey, enforcing: true }
331
+ );
332
+ }
333
+ resolveRuntime(input) {
334
+ if (!input.behaviorPoint && !input.executionBoundary && !input.semanticContext)
335
+ throw new Error("SDK_RUNTIME_ROUTE_REQUIRED");
336
+ return this.request(
337
+ {
338
+ method: "POST",
339
+ path: "/v1/runtime/resolve",
340
+ body: {
341
+ ...input.behaviorPoint ? { behaviorPoint: input.behaviorPoint } : {},
342
+ ...input.executionBoundary ? { executionBoundary: input.executionBoundary } : {},
343
+ ...input.semanticContext ? { semanticContext: input.semanticContext } : {}
344
+ }
345
+ },
346
+ {
347
+ idempotencyKey: input.idempotencyKey ?? `sdk:resolve:${input.behaviorPoint ?? "boundary"}`,
348
+ enforcing: true
349
+ }
350
+ );
351
+ }
352
+ /** Resolve a runtime route from a governed execution boundary and semantic context. */
353
+ resolveBoundary(input) {
354
+ if (!input.executionBoundary || typeof input.executionBoundary !== "object")
355
+ throw new Error("SDK_EXECUTION_BOUNDARY_REQUIRED");
356
+ return this.resolveRuntime({
357
+ executionBoundary: input.executionBoundary,
358
+ ...input.semanticContext ? { semanticContext: input.semanticContext } : {},
359
+ idempotencyKey: input.idempotencyKey
360
+ });
361
+ }
362
+ resolveSemantic(input) {
363
+ required(input.input, "SDK_SEMANTIC_INPUT_REQUIRED");
364
+ const { idempotencyKey, requestId, ...body } = input;
365
+ const resolvedRequestId = requestId ?? `sdk-semantic-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
366
+ return this.request(
367
+ {
368
+ method: "POST",
369
+ path: "/v1/semantic/resolve",
370
+ body: { ...body, requestId: resolvedRequestId }
371
+ },
372
+ { idempotencyKey: idempotencyKey ?? `sdk:semantic:${resolvedRequestId}` }
373
+ );
374
+ }
375
+ async resolveSemanticRuntime(input) {
376
+ const semantic = await this.resolveSemantic(input);
377
+ if (!semantic) return null;
378
+ const body = semantic.body;
379
+ const receipt = body.receipt && typeof body.receipt === "object" ? body.receipt : {};
380
+ if (receipt.outcome !== "select" || typeof receipt.taskKey !== "string")
381
+ return { semantic, runtime: null };
382
+ const capsules = Array.isArray(body.capsules) ? body.capsules : [];
383
+ const firstCapsule = capsules[0] && typeof capsules[0] === "object" ? capsules[0] : {};
384
+ const behaviorPoint = typeof firstCapsule.behaviorKey === "string" && firstCapsule.behaviorKey.trim() ? firstCapsule.behaviorKey : receipt.taskKey;
385
+ const runtime = input.executionBoundary ? await this.resolveBoundary({
386
+ executionBoundary: input.executionBoundary,
387
+ semanticContext: {
388
+ taskKey: receipt.taskKey,
389
+ behaviorPoint,
390
+ capsule: firstCapsule
391
+ },
392
+ idempotencyKey: input.idempotencyKey ? `sdk:runtime:${input.idempotencyKey}` : void 0
393
+ }) : await this.resolveRuntime({
394
+ semanticContext: { taskKey: receipt.taskKey, behaviorPoint, capsule: firstCapsule },
395
+ idempotencyKey: input.idempotencyKey ? `sdk:runtime:${input.idempotencyKey}` : void 0
396
+ });
397
+ return { semantic, runtime };
398
+ }
399
+ listBehaviorStrategies() {
400
+ return this.request({
401
+ method: "GET",
402
+ path: "/v1/behavior-strategies"
403
+ });
404
+ }
405
+ deleteBehaviorStrategy(strategyId, options = {}) {
406
+ required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
407
+ return this.request({ method: "DELETE", path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:strategy:${strategyId}` });
408
+ }
409
+ getBehaviorStrategy(strategyId) {
410
+ required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
411
+ return this.request({
412
+ method: "GET",
413
+ path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}`
414
+ });
415
+ }
416
+ createBehaviorStrategy(definition, id) {
417
+ if (!definition) throw new Error("SDK_STRATEGY_DEFINITION_REQUIRED");
418
+ return this.request({
419
+ method: "POST",
420
+ path: "/v1/behavior-strategies",
421
+ body: { definition, ...id ? { id } : {} }
422
+ });
423
+ }
424
+ listSemanticTasks() {
425
+ return this.request({ method: "GET", path: "/v1/semantic-tasks" });
426
+ }
427
+ deleteSemanticTask(taskId, options = {}) {
428
+ required(taskId, "SDK_SEMANTIC_TASK_ID_REQUIRED");
429
+ return this.request({ method: "DELETE", path: `/v1/semantic-tasks/${encodeURIComponent(taskId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:semantic-task:${taskId}` });
430
+ }
431
+ createSemanticTask(task, options = {}) {
432
+ required(task?.taskKey, "SDK_SEMANTIC_TASK_KEY_REQUIRED");
433
+ return this.request({ method: "POST", path: "/v1/semantic-tasks", body: { ...task, ...options.id ? { id: options.id } : {} } }, { idempotencyKey: options.idempotencyKey ?? `sdk:semantic-task:${task.taskKey}` });
434
+ }
435
+ listBehaviorPoints() {
436
+ return this.request({ method: "GET", path: "/v1/behavior-points" });
437
+ }
438
+ deleteBehaviorPoint(pointId, options = {}) {
439
+ required(pointId, "SDK_BEHAVIOR_POINT_ID_REQUIRED");
440
+ return this.request({ method: "DELETE", path: `/v1/behavior-points/${encodeURIComponent(pointId)}`, body: { confirm: options.confirm === true } }, { idempotencyKey: options.idempotencyKey ?? `sdk:delete:behavior-point:${pointId}` });
441
+ }
442
+ createBehaviorPoint(point, options = {}) {
443
+ required(point?.key, "SDK_BEHAVIOR_POINT_KEY_REQUIRED");
444
+ if (!point.taskId && !point.taskIds?.length) throw new Error("SDK_BEHAVIOR_POINT_TASK_REQUIRED");
445
+ return this.request({ method: "POST", path: "/v1/behavior-points", body: { ...point, ...options.id ? { id: options.id } : {} } }, { idempotencyKey: options.idempotencyKey ?? `sdk:behavior-point:${point.key}` });
446
+ }
447
+ createBehaviorStrategyVariant(strategyId, variant, options = {}) {
448
+ required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
449
+ if (!variant || typeof variant !== "object")
450
+ throw new Error("SDK_STRATEGY_VARIANT_REQUIRED");
451
+ return this.request(
452
+ {
453
+ method: "POST",
454
+ path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/variants`,
455
+ body: variant
456
+ },
457
+ { idempotencyKey: options.idempotencyKey }
458
+ );
459
+ }
460
+ validateBehaviorStrategy(strategyId) {
461
+ required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
462
+ return this.request({
463
+ method: "POST",
464
+ path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/validate`,
465
+ body: {}
466
+ });
467
+ }
468
+ activateBehaviorStrategy(strategyId) {
469
+ required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
470
+ return this.request({ method: "POST", path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/activate`, body: {} });
471
+ }
472
+ simulateBehaviorStrategy(strategyId, initialState = {}) {
473
+ required(strategyId, "SDK_STRATEGY_ID_REQUIRED");
474
+ return this.request({
475
+ method: "POST",
476
+ path: `/v1/behavior-strategies/${encodeURIComponent(strategyId)}/simulate`,
477
+ body: { initialState }
478
+ });
479
+ }
480
+ startStrategyExecution(input) {
481
+ required(input.artifactDigest, "SDK_ARTIFACT_DIGEST_REQUIRED");
482
+ for (const value of [
483
+ input.organizationId,
484
+ input.projectId,
485
+ input.environmentId,
486
+ input.revisionId,
487
+ input.idempotencyKey,
488
+ input.nonce,
489
+ input.decisionPlanId,
490
+ input.policy
491
+ ])
492
+ required(value, "SDK_STRATEGY_START_FIELD_REQUIRED");
493
+ if (input.behaviorPoint !== void 0)
494
+ required(input.behaviorPoint, "SDK_BEHAVIOR_POINT_REQUIRED");
495
+ if (!Array.isArray(input.candidates) || input.candidates.length === 0)
496
+ throw new Error("SDK_STRATEGY_CANDIDATES_REQUIRED");
497
+ if (!Number.isFinite(input.expiresAt))
498
+ throw new Error("SDK_EXPIRY_REQUIRED");
499
+ const body = {
500
+ ...buildRuntimeRequest(input),
501
+ artifactDigest: input.artifactDigest,
502
+ ...input.behaviorPoint ? { behaviorPoint: input.behaviorPoint } : {},
503
+ ...input.executionBoundary ? { executionBoundary: input.executionBoundary } : {},
504
+ ...input.traceId ? { traceId: input.traceId } : {},
505
+ ...input.executionId ? { executionId: input.executionId } : {},
506
+ ...input.state ? { state: input.state } : {}
507
+ };
508
+ return this.request(
509
+ { method: "POST", path: "/v1/runtime/strategy-executions", body },
510
+ { idempotencyKey: input.idempotencyKey }
511
+ );
512
+ }
513
+ getStrategyExecution(executionId) {
514
+ required(executionId, "SDK_EXECUTION_ID_REQUIRED");
515
+ return this.request({
516
+ method: "GET",
517
+ path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}`
518
+ });
519
+ }
520
+ getStrategyExecutionTrace(executionId) {
521
+ required(executionId, "SDK_EXECUTION_ID_REQUIRED");
522
+ return this.request({
523
+ method: "GET",
524
+ path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}/trace`
525
+ });
526
+ }
527
+ continueStrategyExecution(executionId, continuation) {
528
+ required(executionId, "SDK_EXECUTION_ID_REQUIRED");
529
+ const input = typeof continuation === "string" ? { authorityDigest: continuation } : continuation ?? {};
530
+ return this.request({
531
+ method: "POST",
532
+ path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}/continue`,
533
+ body: {
534
+ ...input.authorityDigest ? { authorityDigest: input.authorityDigest } : {},
535
+ ...input.state ? { state: input.state } : {},
536
+ ...input.references ? { references: input.references } : {}
537
+ }
538
+ });
539
+ }
540
+ cancelStrategyExecution(executionId) {
541
+ required(executionId, "SDK_EXECUTION_ID_REQUIRED");
542
+ return this.request({
543
+ method: "POST",
544
+ path: `/v1/runtime/strategy-executions/${encodeURIComponent(executionId)}/cancel`,
545
+ body: {}
546
+ });
547
+ }
548
+ listBehaviorPrograms() {
549
+ return this.request({
550
+ method: "GET",
551
+ path: "/v1/behavior-programs"
552
+ });
553
+ }
554
+ listCapabilities(options = {}) {
555
+ const query = options.surface ? `?surface=${encodeURIComponent(options.surface)}` : "";
556
+ return this.request({ method: "GET", path: `/v1/capabilities${query}` });
557
+ }
558
+ getBehaviorProgram(programId) {
559
+ required(programId, "SDK_PROGRAM_ID_REQUIRED");
560
+ return this.request({
561
+ method: "GET",
562
+ path: `/v1/behavior-programs/${encodeURIComponent(programId)}`
563
+ });
564
+ }
565
+ createBehaviorProgram(program, options = {}) {
566
+ if (!program || typeof program !== "object")
567
+ throw new Error("SDK_PROGRAM_REQUIRED");
568
+ return this.request(
569
+ { method: "POST", path: "/v1/behavior-programs", body: program },
570
+ {
571
+ idempotencyKey: options.idempotencyKey ?? `sdk:program:${String(program.id ?? "")}`
572
+ }
573
+ );
574
+ }
575
+ attestCapabilities(attestation, options = {}) {
576
+ return this.request(
577
+ {
578
+ method: "POST",
579
+ path: "/v1/runtime/capabilities/attest",
580
+ body: attestation
581
+ },
582
+ { idempotencyKey: options.idempotencyKey }
583
+ );
584
+ }
585
+ resolveCapabilities(attestationId, request, options = {}) {
586
+ required(attestationId, "SDK_ATTESTATION_ID_REQUIRED");
587
+ return this.request(
588
+ {
589
+ method: "POST",
590
+ path: "/v1/runtime/capabilities/resolve",
591
+ body: { attestationId, request }
592
+ },
593
+ { idempotencyKey: options.idempotencyKey, enforcing: true }
594
+ );
595
+ }
596
+ recordCapabilityTrace(decisionDigest, trace, options = {}) {
597
+ required(decisionDigest, "SDK_DECISION_DIGEST_REQUIRED");
598
+ return this.request(
599
+ {
600
+ method: "POST",
601
+ path: "/v1/runtime/capabilities/traces",
602
+ body: { decisionDigest, trace }
603
+ },
604
+ { idempotencyKey: options.idempotencyKey }
605
+ );
606
+ }
607
+ resolveModelServing(request, options = {}) {
608
+ return this.request(
609
+ { method: "POST", path: "/v1/model-serving/resolve", body: request },
610
+ { idempotencyKey: options.idempotencyKey, enforcing: true }
611
+ );
612
+ }
613
+ recordModelServingTrace(trace, selection, options = {}) {
614
+ return this.request(
615
+ {
616
+ method: "POST",
617
+ path: "/v1/model-serving/traces",
618
+ body: { trace, selection }
619
+ },
620
+ { idempotencyKey: options.idempotencyKey }
621
+ );
622
+ }
623
+ submitTeachEvidence(evidence, options = {}) {
624
+ return this.request(
625
+ { method: "POST", path: "/v1/teach/evidence", body: evidence },
626
+ { idempotencyKey: options.idempotencyKey }
627
+ );
628
+ }
629
+ createTeachProposal(input, options = {}) {
630
+ return this.request({ method: "POST", path: "/v1/teach/proposals", body: input }, { idempotencyKey: options.idempotencyKey });
631
+ }
632
+ transitionTeachProposal(proposalId, transition, input = {}, options = {}) {
633
+ required(proposalId, "SDK_TEACH_PROPOSAL_ID_REQUIRED");
634
+ return this.request({ method: "POST", path: `/v1/teach/proposals/${encodeURIComponent(proposalId)}/${transition}`, body: input }, { idempotencyKey: options.idempotencyKey ?? `sdk:teach:${transition}:${proposalId}` });
635
+ }
636
+ startEvaluation(input, options = {}) {
637
+ return this.request(
638
+ { method: "POST", path: "/v1/evaluations", body: input },
639
+ { idempotencyKey: options.idempotencyKey }
640
+ );
641
+ }
642
+ evaluateQuality(input, options = {}) {
643
+ return this.request(
644
+ { method: "POST", path: "/v1/quality/evaluate", body: input },
645
+ { idempotencyKey: options.idempotencyKey }
646
+ );
647
+ }
648
+ getEvaluation(evaluationId) {
649
+ required(evaluationId, "SDK_EVALUATION_ID_REQUIRED");
650
+ return this.request({
651
+ method: "GET",
652
+ path: `/v1/evaluations/${encodeURIComponent(evaluationId)}`
653
+ });
654
+ }
655
+ createRelease(input, options = {}) {
656
+ return this.request(
657
+ { method: "POST", path: "/v1/releases", body: input },
658
+ { idempotencyKey: options.idempotencyKey }
659
+ );
660
+ }
661
+ createManualRelease(input, options = {}) {
662
+ if (!input || typeof input !== "object" || !input.manualApproval) throw new Error("SDK_MANUAL_RELEASE_APPROVAL_REQUIRED");
663
+ return this.createRelease(input, { idempotencyKey: options.idempotencyKey });
664
+ }
665
+ releaseProgramManually(input, options = {}) {
666
+ required(input?.programId, "SDK_MANUAL_RELEASE_PROGRAM_REQUIRED");
667
+ required(input?.reason, "SDK_MANUAL_RELEASE_REASON_REQUIRED");
668
+ return this.request({ method: "POST", path: "/v1/releases/manual-program", body: { programId: input.programId, reason: input.reason } }, { idempotencyKey: options.idempotencyKey ?? `sdk:manual-release:${input.programId}` });
669
+ }
670
+ recordDeploymentComparison(deploymentId, comparison, options = {}) {
671
+ required(deploymentId, "SDK_DEPLOYMENT_ID_REQUIRED");
672
+ return this.request(
673
+ {
674
+ method: "POST",
675
+ path: `/v1/deployments/${encodeURIComponent(deploymentId)}/comparisons`,
676
+ body: comparison
677
+ },
678
+ { idempotencyKey: options.idempotencyKey }
679
+ );
680
+ }
681
+ recordDeploymentHealth(deploymentId, health, options = {}) {
682
+ required(deploymentId, "SDK_DEPLOYMENT_ID_REQUIRED");
683
+ return this.request(
684
+ {
685
+ method: "POST",
686
+ path: `/v1/deployments/${encodeURIComponent(deploymentId)}/authoritative-health`,
687
+ body: health
688
+ },
689
+ { idempotencyKey: options.idempotencyKey }
690
+ );
691
+ }
692
+ compileBehaviorCapsule(input) {
693
+ required(input.programId, "SDK_PROGRAM_ID_REQUIRED");
694
+ required(input.input, "SDK_RUNTIME_INPUT_REQUIRED");
695
+ return this.request(
696
+ {
697
+ method: "POST",
698
+ path: "/v1/runtime/behavior-capsule",
699
+ body: { ...input }
700
+ },
701
+ {
702
+ idempotencyKey: input.idempotencyKey ?? `sdk:capsule:${input.programId}`
703
+ }
704
+ );
705
+ }
706
+ serveBehaviorProjection(input) {
707
+ required(input.input, "SDK_RUNTIME_INPUT_REQUIRED");
708
+ required(input.provider, "SDK_PROVIDER_REQUIRED");
709
+ return this.request(
710
+ {
711
+ method: "POST",
712
+ path: "/v1/runtime/behavior-projection",
713
+ body: { ...input }
714
+ },
715
+ {
716
+ idempotencyKey: input.idempotencyKey ?? `sdk:projection:${input.programId ?? "active"}`
717
+ }
718
+ );
719
+ }
720
+ async testConnection(connectionId) {
721
+ required(connectionId, "SDK_CONNECTION_ID_REQUIRED");
722
+ return this.request({
723
+ method: "POST",
724
+ path: `/v1/connections/${encodeURIComponent(connectionId)}/test`,
725
+ body: {}
726
+ });
727
+ }
728
+ };
729
+ function buildRuntimeRequest(input) {
730
+ const {
731
+ organizationId,
732
+ projectId,
733
+ environmentId,
734
+ revisionId,
735
+ idempotencyKey,
736
+ nonce,
737
+ expiresAt,
738
+ decisionPlanId,
739
+ calibrationId,
740
+ candidates,
741
+ allowedIds,
742
+ policy,
743
+ postModelJudge,
744
+ shadow
745
+ } = input;
746
+ for (const value of [
747
+ organizationId,
748
+ projectId,
749
+ environmentId,
750
+ revisionId,
751
+ idempotencyKey,
752
+ nonce
753
+ ])
754
+ if (typeof value !== "string" || !value.trim())
755
+ throw new Error("SDK_REQUEST_FIELD_REQUIRED");
756
+ if (!Number.isFinite(expiresAt)) throw new Error("SDK_EXPIRY_REQUIRED");
757
+ const boundary = {
758
+ ...typeof decisionPlanId === "string" ? { decisionPlanId } : {},
759
+ ...typeof calibrationId === "string" ? { calibrationId } : {},
760
+ ...Array.isArray(candidates) ? { candidates } : {},
761
+ ...Array.isArray(allowedIds) ? { allowedIds } : {},
762
+ ...typeof policy === "string" ? { policy } : {},
763
+ ...postModelJudge !== void 0 ? { postModelJudge } : {},
764
+ ...shadow !== void 0 ? { shadow } : {}
765
+ };
766
+ return Object.freeze({
767
+ organizationId,
768
+ projectId,
769
+ environmentId,
770
+ revisionId,
771
+ idempotencyKey,
772
+ nonce,
773
+ expiresAt,
774
+ ...boundary
775
+ });
776
+ }
777
+ function buildPublicContentRequest(input) {
778
+ const { slug, version = "v1" } = input;
779
+ if (typeof slug !== "string" || !slug.trim())
780
+ throw new Error("SDK_SLUG_REQUIRED");
781
+ if (version !== "v1") throw new Error("SDK_VERSION_UNSUPPORTED");
782
+ return Object.freeze({
783
+ method: "GET",
784
+ path: "/v1/content",
785
+ query: Object.freeze({ slug })
786
+ });
787
+ }
788
+ function buildDocsQueryRequest(input) {
789
+ const { query, operation = "search" } = input;
790
+ if (typeof query !== "string" || !query.trim())
791
+ throw new Error("SDK_QUERY_REQUIRED");
792
+ if (!["search", "ask"].includes(operation))
793
+ throw new Error("SDK_OPERATION_UNSUPPORTED");
794
+ return Object.freeze({
795
+ method: "GET",
796
+ path: `/docs/${operation}`,
797
+ query: Object.freeze({ query })
798
+ });
799
+ }
800
+ function buildAISystemRequest(input) {
801
+ const { name, systemType, organizationId, projectId, environmentId } = input;
802
+ for (const value of [
803
+ name,
804
+ systemType,
805
+ organizationId,
806
+ projectId,
807
+ environmentId
808
+ ])
809
+ if (typeof value !== "string" || !value.trim())
810
+ throw new Error("SDK_AI_SYSTEM_FIELD_REQUIRED");
811
+ return Object.freeze({
812
+ method: "POST",
813
+ path: "/v1/ai-systems",
814
+ body: Object.freeze({
815
+ name,
816
+ systemType,
817
+ organizationId,
818
+ projectId,
819
+ environmentId
820
+ })
821
+ });
822
+ }
823
+ function buildObservationRequest(event) {
824
+ if (!event?.eventId || !event.eventType || !event.aiSystemId || !event.connectionId)
825
+ throw new Error("SDK_OBSERVATION_FIELD_REQUIRED");
826
+ return Object.freeze({
827
+ method: "POST",
828
+ path: "/v1/observations",
829
+ body: Object.freeze({ ...event })
830
+ });
831
+ }
832
+ export {
833
+ ViraApiError,
834
+ ViraClient,
835
+ buildAISystemRequest,
836
+ buildDocsQueryRequest,
837
+ buildObservationRequest,
838
+ buildPublicContentRequest,
839
+ buildRuntimeRequest
840
+ };