@synova-cloud/sdk 1.7.0 → 1.9.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/README.md +122 -2
- package/dist/index.cjs +144 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +206 -3
- package/dist/index.d.ts +206 -3
- package/dist/index.js +144 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -263,6 +263,116 @@ const topic = await client.prompts.execute('prm_abc123', {
|
|
|
263
263
|
| `@SchemaMaxItems(n)` | Maximum array length |
|
|
264
264
|
| `@SchemaEnum(values)` | Allowed enum values |
|
|
265
265
|
|
|
266
|
+
### Observability
|
|
267
|
+
|
|
268
|
+
Track and group your LLM calls using traces and spans. Each execution creates a span, and multiple spans can be grouped into a trace using `sessionId`.
|
|
269
|
+
|
|
270
|
+
#### Session-Based Tracing
|
|
271
|
+
|
|
272
|
+
Use `sessionId` to group related calls (e.g., a conversation) into a single trace:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
const sessionId = 'chat_user123_conv1';
|
|
276
|
+
|
|
277
|
+
// First message - creates new trace
|
|
278
|
+
const response1 = await client.prompts.execute('prm_abc123', {
|
|
279
|
+
provider: 'openai',
|
|
280
|
+
model: 'gpt-4o',
|
|
281
|
+
sessionId,
|
|
282
|
+
variables: { topic: 'TypeScript' },
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
console.log(response1.traceId); // trc_xxx
|
|
286
|
+
console.log(response1.spanId); // spn_xxx
|
|
287
|
+
|
|
288
|
+
// Follow-up - same sessionId = same trace, new span
|
|
289
|
+
const response2 = await client.prompts.execute('prm_abc123', {
|
|
290
|
+
provider: 'openai',
|
|
291
|
+
model: 'gpt-4o',
|
|
292
|
+
sessionId,
|
|
293
|
+
messages: [
|
|
294
|
+
{ role: 'assistant', content: response1.content },
|
|
295
|
+
{ role: 'user', content: 'Tell me more' },
|
|
296
|
+
],
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// response2.traceId === response1.traceId (same trace)
|
|
300
|
+
// response2.spanId !== response1.spanId (new span)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### Response Properties
|
|
304
|
+
|
|
305
|
+
Every execution returns observability IDs:
|
|
306
|
+
|
|
307
|
+
| Property | Type | Description |
|
|
308
|
+
|----------|------|-------------|
|
|
309
|
+
| `spanDataId` | `string` | Execution data ID (messages, response, usage) |
|
|
310
|
+
| `traceId` | `string` | Trace ID (groups related calls) |
|
|
311
|
+
| `spanId` | `string` | Span ID (this specific call) |
|
|
312
|
+
|
|
313
|
+
#### Custom Span Tracking
|
|
314
|
+
|
|
315
|
+
Track tool calls, retrieval operations, and custom logic as spans within a trace.
|
|
316
|
+
|
|
317
|
+
**Manual approach:**
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// Create span
|
|
321
|
+
const span = await client.spans.create(traceId, {
|
|
322
|
+
type: 'tool',
|
|
323
|
+
toolName: 'fetch_weather',
|
|
324
|
+
toolArguments: { city: 'NYC' },
|
|
325
|
+
parentSpanId: generationSpanId,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Execute
|
|
329
|
+
const weather = await fetchWeather('NYC');
|
|
330
|
+
|
|
331
|
+
// End span
|
|
332
|
+
await client.spans.end(span.id, {
|
|
333
|
+
status: 'completed',
|
|
334
|
+
toolResult: weather,
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Wrapper approach:**
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// wrapTool() - for tools
|
|
342
|
+
const weather = await client.spans.wrapTool(
|
|
343
|
+
{ traceId, toolName: 'fetch_weather', parentSpanId },
|
|
344
|
+
{ city: 'NYC' },
|
|
345
|
+
async (args) => fetchWeather(args.city),
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
// wrap() - for custom/retriever/embedding
|
|
349
|
+
const docs = await client.spans.wrap(
|
|
350
|
+
{ traceId, type: 'retriever', name: 'vector_search' },
|
|
351
|
+
{ query: 'how to...', topK: 5 },
|
|
352
|
+
async () => vectorDb.search(query),
|
|
353
|
+
);
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Wrappers automatically handle errors and set `status: 'error'` with message.
|
|
357
|
+
|
|
358
|
+
#### Span Types
|
|
359
|
+
|
|
360
|
+
| Type | Use Case |
|
|
361
|
+
|------|----------|
|
|
362
|
+
| `generation` | LLM calls (auto-created by `execute()`) |
|
|
363
|
+
| `tool` | Tool/function calls |
|
|
364
|
+
| `retriever` | RAG document retrieval |
|
|
365
|
+
| `embedding` | Embedding generation |
|
|
366
|
+
| `custom` | Any custom operation |
|
|
367
|
+
|
|
368
|
+
#### Viewing Traces
|
|
369
|
+
|
|
370
|
+
View your traces in the [Synova Cloud Dashboard](https://app.synova.cloud) under the Observability section. Each trace shows:
|
|
371
|
+
- All spans (LLM calls) in the session
|
|
372
|
+
- Input/output for each span
|
|
373
|
+
- Token usage and latency
|
|
374
|
+
- Error details if any
|
|
375
|
+
|
|
266
376
|
### Models
|
|
267
377
|
|
|
268
378
|
#### List All Models
|
|
@@ -519,15 +629,25 @@ import type {
|
|
|
519
629
|
ISynovaPromptVariable,
|
|
520
630
|
ISynovaGetPromptOptions,
|
|
521
631
|
// Execution
|
|
522
|
-
ISynovaExecuteOptions,
|
|
632
|
+
ISynovaExecuteOptions, // includes sessionId
|
|
523
633
|
ISynovaExecuteTypedOptions,
|
|
524
|
-
ISynovaExecuteResponse,
|
|
634
|
+
ISynovaExecuteResponse, // includes spanDataId, traceId, spanId
|
|
525
635
|
ISynovaExecutionUsage,
|
|
526
636
|
ISynovaExecutionError,
|
|
527
637
|
// Messages
|
|
528
638
|
ISynovaMessage,
|
|
529
639
|
TSynovaMessageRole,
|
|
530
640
|
TSynovaResponseType,
|
|
641
|
+
// Spans
|
|
642
|
+
ISynovaSpan,
|
|
643
|
+
ISynovaSpanData,
|
|
644
|
+
ISynovaCreateSpanOptions,
|
|
645
|
+
ISynovaEndSpanOptions,
|
|
646
|
+
ISynovaWrapOptions,
|
|
647
|
+
ISynovaWrapToolOptions,
|
|
648
|
+
TSynovaSpanType,
|
|
649
|
+
TSynovaSpanStatus,
|
|
650
|
+
TSynovaSpanLevel,
|
|
531
651
|
// Files
|
|
532
652
|
ISynovaFileAttachment,
|
|
533
653
|
ISynovaFileThumbnails,
|
package/dist/index.cjs
CHANGED
|
@@ -107,7 +107,7 @@ var ValidationSynovaError = class extends SynovaError {
|
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
// src/version.ts
|
|
110
|
-
var SDK_VERSION = "1.
|
|
110
|
+
var SDK_VERSION = "1.9.0" ;
|
|
111
111
|
|
|
112
112
|
// src/utils/http.ts
|
|
113
113
|
var HttpClient = class {
|
|
@@ -342,7 +342,9 @@ var SCHEMA_METADATA_KEYS = {
|
|
|
342
342
|
// Array constraints
|
|
343
343
|
MIN_ITEMS: "synova:schema:minItems",
|
|
344
344
|
MAX_ITEMS: "synova:schema:maxItems",
|
|
345
|
-
UNIQUE_ITEMS: "synova:schema:uniqueItems"
|
|
345
|
+
UNIQUE_ITEMS: "synova:schema:uniqueItems",
|
|
346
|
+
// Object constraints
|
|
347
|
+
ADDITIONAL_PROPERTIES: "synova:schema:additionalProperties"
|
|
346
348
|
};
|
|
347
349
|
function createMetadataDecorator(key, value) {
|
|
348
350
|
return function(target, propertyKey) {
|
|
@@ -733,6 +735,12 @@ var ClassSchema = class {
|
|
|
733
735
|
propertyName
|
|
734
736
|
);
|
|
735
737
|
if (uniqueItems) schema.uniqueItems = uniqueItems;
|
|
738
|
+
const additionalProperties = getSchemaMetadata(
|
|
739
|
+
SCHEMA_METADATA_KEYS.ADDITIONAL_PROPERTIES,
|
|
740
|
+
prototype,
|
|
741
|
+
propertyName
|
|
742
|
+
);
|
|
743
|
+
if (additionalProperties !== void 0) schema.additionalProperties = additionalProperties;
|
|
736
744
|
}
|
|
737
745
|
/**
|
|
738
746
|
* Get required properties (properties without @IsOptional)
|
|
@@ -820,6 +828,7 @@ var PromptsResource = class {
|
|
|
820
828
|
if (options.metadata !== void 0) body.metadata = options.metadata;
|
|
821
829
|
if (options.parameters !== void 0) body.parameters = options.parameters;
|
|
822
830
|
if (options.responseSchema !== void 0) body.responseSchema = options.responseSchema;
|
|
831
|
+
if (options.sessionId !== void 0) body.sessionId = options.sessionId;
|
|
823
832
|
const response = await this.http.request({
|
|
824
833
|
method: "POST",
|
|
825
834
|
path: `/api/v1/prompts/${promptId}/run`,
|
|
@@ -1004,6 +1013,137 @@ var FilesResource = class {
|
|
|
1004
1013
|
}
|
|
1005
1014
|
};
|
|
1006
1015
|
|
|
1016
|
+
// src/resources/spans.ts
|
|
1017
|
+
var SpansResource = class {
|
|
1018
|
+
constructor(http) {
|
|
1019
|
+
this.http = http;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Create a new span within a trace
|
|
1023
|
+
*
|
|
1024
|
+
* @param traceId - The trace ID to create span in
|
|
1025
|
+
* @param options - Span creation options
|
|
1026
|
+
* @returns Created span
|
|
1027
|
+
*/
|
|
1028
|
+
async create(traceId, options) {
|
|
1029
|
+
const body = {
|
|
1030
|
+
type: options.type
|
|
1031
|
+
};
|
|
1032
|
+
if (options.parentSpanId !== void 0) body.parentSpanId = options.parentSpanId;
|
|
1033
|
+
if (options.name !== void 0) body.name = options.name;
|
|
1034
|
+
if (options.input !== void 0) body.input = options.input;
|
|
1035
|
+
if (options.toolName !== void 0) body.toolName = options.toolName;
|
|
1036
|
+
if (options.toolArguments !== void 0) body.toolArguments = options.toolArguments;
|
|
1037
|
+
if (options.metadata !== void 0) body.metadata = options.metadata;
|
|
1038
|
+
return this.http.request({
|
|
1039
|
+
method: "POST",
|
|
1040
|
+
path: `/api/v1/traces/${traceId}/spans`,
|
|
1041
|
+
body
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* End/complete a span
|
|
1046
|
+
*
|
|
1047
|
+
* @param spanId - The span ID to end
|
|
1048
|
+
* @param options - Span end options
|
|
1049
|
+
* @returns Updated span
|
|
1050
|
+
*/
|
|
1051
|
+
async end(spanId, options) {
|
|
1052
|
+
const body = {};
|
|
1053
|
+
if (options?.status !== void 0) body.status = options.status;
|
|
1054
|
+
if (options?.level !== void 0) body.level = options.level;
|
|
1055
|
+
if (options?.statusMessage !== void 0) body.statusMessage = options.statusMessage;
|
|
1056
|
+
if (options?.output !== void 0) body.output = options.output;
|
|
1057
|
+
if (options?.toolResult !== void 0) body.toolResult = options.toolResult;
|
|
1058
|
+
if (options?.durationMs !== void 0) body.durationMs = options.durationMs;
|
|
1059
|
+
return this.http.request({
|
|
1060
|
+
method: "PATCH",
|
|
1061
|
+
path: `/api/v1/spans/${spanId}`,
|
|
1062
|
+
body
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Wrap an async function with automatic span tracking
|
|
1067
|
+
*
|
|
1068
|
+
* @param options - Span options (traceId, type, name, etc.)
|
|
1069
|
+
* @param input - Input data to record in span
|
|
1070
|
+
* @param fn - Async function to execute
|
|
1071
|
+
* @returns Result of the function
|
|
1072
|
+
*
|
|
1073
|
+
* @example
|
|
1074
|
+
* ```ts
|
|
1075
|
+
* const result = await client.spans.wrap(
|
|
1076
|
+
* { traceId: 'trc_123', type: 'retriever', name: 'vector_search' },
|
|
1077
|
+
* { query: 'how to...', topK: 5 },
|
|
1078
|
+
* async () => vectorDb.search(query),
|
|
1079
|
+
* );
|
|
1080
|
+
* ```
|
|
1081
|
+
*/
|
|
1082
|
+
async wrap(options, input, fn) {
|
|
1083
|
+
const span = await this.create(options.traceId, {
|
|
1084
|
+
type: options.type,
|
|
1085
|
+
name: options.name,
|
|
1086
|
+
parentSpanId: options.parentSpanId,
|
|
1087
|
+
input,
|
|
1088
|
+
metadata: options.metadata
|
|
1089
|
+
});
|
|
1090
|
+
try {
|
|
1091
|
+
const result = await fn();
|
|
1092
|
+
await this.end(span.id, {
|
|
1093
|
+
status: "completed",
|
|
1094
|
+
output: result
|
|
1095
|
+
});
|
|
1096
|
+
return result;
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
await this.end(span.id, {
|
|
1099
|
+
status: "error",
|
|
1100
|
+
statusMessage: error instanceof Error ? error.message : String(error)
|
|
1101
|
+
});
|
|
1102
|
+
throw error;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Wrap a tool function with automatic span tracking
|
|
1107
|
+
*
|
|
1108
|
+
* @param options - Tool span options (traceId, toolName, etc.)
|
|
1109
|
+
* @param args - Tool arguments to record
|
|
1110
|
+
* @param fn - Tool function to execute
|
|
1111
|
+
* @returns Result of the tool
|
|
1112
|
+
*
|
|
1113
|
+
* @example
|
|
1114
|
+
* ```ts
|
|
1115
|
+
* const weather = await client.spans.wrapTool(
|
|
1116
|
+
* { traceId: 'trc_123', toolName: 'fetch_weather', parentSpanId: 'spn_abc' },
|
|
1117
|
+
* { city: 'NYC' },
|
|
1118
|
+
* async (args) => fetchWeather(args.city),
|
|
1119
|
+
* );
|
|
1120
|
+
* ```
|
|
1121
|
+
*/
|
|
1122
|
+
async wrapTool(options, args, fn) {
|
|
1123
|
+
const span = await this.create(options.traceId, {
|
|
1124
|
+
type: "tool",
|
|
1125
|
+
toolName: options.toolName,
|
|
1126
|
+
toolArguments: args,
|
|
1127
|
+
parentSpanId: options.parentSpanId,
|
|
1128
|
+
metadata: options.metadata
|
|
1129
|
+
});
|
|
1130
|
+
try {
|
|
1131
|
+
const result = await fn(args);
|
|
1132
|
+
await this.end(span.id, {
|
|
1133
|
+
status: "completed",
|
|
1134
|
+
toolResult: result
|
|
1135
|
+
});
|
|
1136
|
+
return result;
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
await this.end(span.id, {
|
|
1139
|
+
status: "error",
|
|
1140
|
+
statusMessage: error instanceof Error ? error.message : String(error)
|
|
1141
|
+
});
|
|
1142
|
+
throw error;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1007
1147
|
// src/client.ts
|
|
1008
1148
|
var DEFAULT_BASE_URL = "https://api.synova.cloud";
|
|
1009
1149
|
var DEFAULT_TIMEOUT = 3e4;
|
|
@@ -1024,6 +1164,7 @@ var SynovaCloudSdk = class {
|
|
|
1024
1164
|
prompts;
|
|
1025
1165
|
models;
|
|
1026
1166
|
files;
|
|
1167
|
+
spans;
|
|
1027
1168
|
http;
|
|
1028
1169
|
/**
|
|
1029
1170
|
* Create a new Synova Cloud SDK client
|
|
@@ -1052,6 +1193,7 @@ var SynovaCloudSdk = class {
|
|
|
1052
1193
|
this.prompts = new PromptsResource(this.http);
|
|
1053
1194
|
this.models = new ModelsResource(this.http);
|
|
1054
1195
|
this.files = new FilesResource(this.http);
|
|
1196
|
+
this.spans = new SpansResource(this.http);
|
|
1055
1197
|
}
|
|
1056
1198
|
};
|
|
1057
1199
|
|