@strands-agents/sdk 1.9.0 → 1.10.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/src/agent/agent.js +1 -1
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/errors.d.ts +15 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +18 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/models/bedrock.d.ts.map +1 -1
- package/dist/src/models/bedrock.js +23 -1
- package/dist/src/models/bedrock.js.map +1 -1
- package/dist/src/models/openai/mantle.d.ts +6 -2
- package/dist/src/models/openai/mantle.d.ts.map +1 -1
- package/dist/src/models/openai/mantle.js +17 -3
- package/dist/src/models/openai/mantle.js.map +1 -1
- package/dist/src/models/openai/model.d.ts.map +1 -1
- package/dist/src/models/openai/model.js +4 -3
- package/dist/src/models/openai/model.js.map +1 -1
- package/dist/src/multiagent/graph.d.ts.map +1 -1
- package/dist/src/multiagent/graph.js +1 -1
- package/dist/src/multiagent/graph.js.map +1 -1
- package/dist/src/{multiagent/queue.d.ts → queue.d.ts} +12 -27
- package/dist/src/queue.d.ts.map +1 -0
- package/dist/src/{multiagent/queue.js → queue.js} +4 -2
- package/dist/src/queue.js.map +1 -0
- package/dist/src/session/file-storage.d.ts +3 -0
- package/dist/src/session/file-storage.d.ts.map +1 -1
- package/dist/src/session/file-storage.js +3 -0
- package/dist/src/session/file-storage.js.map +1 -1
- package/dist/src/session/s3-storage.d.ts +3 -0
- package/dist/src/session/s3-storage.d.ts.map +1 -1
- package/dist/src/session/s3-storage.js +3 -0
- package/dist/src/session/s3-storage.js.map +1 -1
- package/dist/src/session/session-manager.d.ts +11 -2
- package/dist/src/session/session-manager.d.ts.map +1 -1
- package/dist/src/session/session-manager.js +19 -8
- package/dist/src/session/session-manager.js.map +1 -1
- package/dist/src/session/snapshot-storage-adapter.d.ts +93 -0
- package/dist/src/session/snapshot-storage-adapter.d.ts.map +1 -0
- package/dist/src/session/snapshot-storage-adapter.js +157 -0
- package/dist/src/session/snapshot-storage-adapter.js.map +1 -0
- package/dist/src/session/storage.d.ts +3 -6
- package/dist/src/session/storage.d.ts.map +1 -1
- package/dist/src/storage/in-memory-storage.d.ts +64 -0
- package/dist/src/storage/in-memory-storage.d.ts.map +1 -0
- package/dist/src/storage/in-memory-storage.js +85 -0
- package/dist/src/storage/in-memory-storage.js.map +1 -0
- package/dist/src/storage/index.d.ts +20 -0
- package/dist/src/storage/index.d.ts.map +1 -0
- package/dist/src/storage/index.js +18 -0
- package/dist/src/storage/index.js.map +1 -0
- package/dist/src/storage/local-file-storage.d.ts +81 -0
- package/dist/src/storage/local-file-storage.d.ts.map +1 -0
- package/dist/src/storage/local-file-storage.js +244 -0
- package/dist/src/storage/local-file-storage.js.map +1 -0
- package/dist/src/storage/s3-storage.d.ts +73 -0
- package/dist/src/storage/s3-storage.d.ts.map +1 -0
- package/dist/src/storage/s3-storage.js +146 -0
- package/dist/src/storage/s3-storage.js.map +1 -0
- package/dist/src/storage/storage.d.ts +102 -0
- package/dist/src/storage/storage.d.ts.map +1 -0
- package/dist/src/storage/storage.js +68 -0
- package/dist/src/storage/storage.js.map +1 -0
- package/dist/src/telemetry/tracer.d.ts +18 -0
- package/dist/src/telemetry/tracer.d.ts.map +1 -1
- package/dist/src/telemetry/tracer.js +31 -11
- package/dist/src/telemetry/tracer.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/types/agent.d.ts +5 -4
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/agent.js.map +1 -1
- package/dist/src/vended-plugins/context-offloader/plugin.d.ts +37 -5
- package/dist/src/vended-plugins/context-offloader/plugin.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/plugin.js +116 -17
- package/dist/src/vended-plugins/context-offloader/plugin.js.map +1 -1
- package/dist/src/vended-plugins/context-offloader/storage.d.ts +23 -9
- package/dist/src/vended-plugins/context-offloader/storage.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/storage.js +17 -6
- package/dist/src/vended-plugins/context-offloader/storage.js.map +1 -1
- package/dist/src/vended-tools/notebook/notebook.d.ts +1 -1
- package/package.json +5 -2
- package/dist/src/conversation-manager/index.d.ts +0 -10
- package/dist/src/conversation-manager/index.d.ts.map +0 -1
- package/dist/src/conversation-manager/index.js +0 -10
- package/dist/src/conversation-manager/index.js.map +0 -1
- package/dist/src/multiagent/queue.d.ts.map +0 -1
- package/dist/src/multiagent/queue.js.map +0 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { StorageError } from '../errors.js';
|
|
2
|
+
import { namespace, normalizeKey, normalizePrefix } from './storage.js';
|
|
3
|
+
const S3_PAGE_SIZE = 1000;
|
|
4
|
+
/**
|
|
5
|
+
* Amazon S3 {@link Storage} backend.
|
|
6
|
+
*
|
|
7
|
+
* Stores each key as an S3 object under an optional prefix. The AWS SDK is loaded
|
|
8
|
+
* lazily on first use and declared as an optional peer dependency, so consumers that
|
|
9
|
+
* never construct an `S3Storage` are not required to install `@aws-sdk/client-s3`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { S3Storage } from '@strands-agents/sdk/storage'
|
|
14
|
+
*
|
|
15
|
+
* const storage = new S3Storage('my-bucket', { prefix: 'agents/' })
|
|
16
|
+
* await storage.write('sessions/abc/snapshot.json', bytes)
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export class S3Storage {
|
|
20
|
+
_bucket;
|
|
21
|
+
_prefix;
|
|
22
|
+
_region;
|
|
23
|
+
_client;
|
|
24
|
+
/**
|
|
25
|
+
* @param bucket - Target S3 bucket name
|
|
26
|
+
* @param config - Optional prefix, region, or pre-configured client
|
|
27
|
+
* @throws {@link StorageError} if both `region` and `s3Client` are provided
|
|
28
|
+
*/
|
|
29
|
+
constructor(bucket, config) {
|
|
30
|
+
if (config?.s3Client && config.region) {
|
|
31
|
+
throw new StorageError('Cannot specify both s3Client and region. Configure the region on the S3Client instead.');
|
|
32
|
+
}
|
|
33
|
+
this._bucket = bucket;
|
|
34
|
+
this._prefix = config?.prefix ? config.prefix.split('/').filter(Boolean).join('/') + '/' : '';
|
|
35
|
+
this._region = config?.region;
|
|
36
|
+
this._client = config?.s3Client;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Stores `data` under `key`, overwriting any existing value.
|
|
40
|
+
*
|
|
41
|
+
* @param key - Opaque, `/`-separated key identifying the value
|
|
42
|
+
* @param data - Raw bytes to persist
|
|
43
|
+
* @throws {@link StorageError} if the key is invalid or the upload fails
|
|
44
|
+
*/
|
|
45
|
+
async write(key, data) {
|
|
46
|
+
const normalized = normalizeKey(key);
|
|
47
|
+
const client = await this._getClient();
|
|
48
|
+
const { PutObjectCommand } = await import('@aws-sdk/client-s3');
|
|
49
|
+
try {
|
|
50
|
+
await client.send(new PutObjectCommand({ Bucket: this._bucket, Key: this._objectKey(normalized), Body: data }));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw new StorageError(`Failed to write '${normalized}' to S3 bucket '${this._bucket}'`, { cause: error });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Retrieves the bytes previously stored under `key`.
|
|
58
|
+
*
|
|
59
|
+
* @param key - The key to read
|
|
60
|
+
* @returns The stored bytes, or `null` if no value exists for `key`
|
|
61
|
+
* @throws {@link StorageError} if the key is invalid or the download fails
|
|
62
|
+
*/
|
|
63
|
+
async read(key) {
|
|
64
|
+
const normalized = normalizeKey(key);
|
|
65
|
+
const client = await this._getClient();
|
|
66
|
+
const { GetObjectCommand } = await import('@aws-sdk/client-s3');
|
|
67
|
+
try {
|
|
68
|
+
const response = await client.send(new GetObjectCommand({ Bucket: this._bucket, Key: this._objectKey(normalized) }));
|
|
69
|
+
const body = await response.Body?.transformToByteArray();
|
|
70
|
+
return body ? new Uint8Array(body) : null;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error instanceof Error && (error.name === 'NoSuchKey' || error.name === 'NotFound')) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
throw new StorageError(`Failed to read '${normalized}' from S3 bucket '${this._bucket}'`, { cause: error });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Deletes the value stored under `key`. A no-op if the key does not exist.
|
|
81
|
+
*
|
|
82
|
+
* @param key - The key to delete
|
|
83
|
+
* @throws {@link StorageError} if the key is invalid or the delete request fails
|
|
84
|
+
*/
|
|
85
|
+
async delete(key) {
|
|
86
|
+
const normalized = normalizeKey(key);
|
|
87
|
+
const client = await this._getClient();
|
|
88
|
+
const { DeleteObjectCommand } = await import('@aws-sdk/client-s3');
|
|
89
|
+
try {
|
|
90
|
+
await client.send(new DeleteObjectCommand({ Bucket: this._bucket, Key: this._objectKey(normalized) }));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new StorageError(`Failed to delete '${normalized}' from S3 bucket '${this._bucket}'`, { cause: error });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Lists the keys whose names begin with `prefix`, sorted lexicographically.
|
|
98
|
+
*
|
|
99
|
+
* @param prefix - Key prefix to match. An empty string matches all keys.
|
|
100
|
+
* @returns The matching keys, sorted ascending
|
|
101
|
+
* @throws {@link StorageError} if the prefix is invalid or the list request fails
|
|
102
|
+
*/
|
|
103
|
+
async list(prefix) {
|
|
104
|
+
const normalized = normalizePrefix(prefix);
|
|
105
|
+
const client = await this._getClient();
|
|
106
|
+
const { ListObjectsV2Command } = await import('@aws-sdk/client-s3');
|
|
107
|
+
const listPrefix = `${this._prefix}${normalized}`;
|
|
108
|
+
const keys = [];
|
|
109
|
+
let continuationToken;
|
|
110
|
+
try {
|
|
111
|
+
do {
|
|
112
|
+
const response = await client.send(new ListObjectsV2Command({
|
|
113
|
+
Bucket: this._bucket,
|
|
114
|
+
Prefix: listPrefix,
|
|
115
|
+
MaxKeys: S3_PAGE_SIZE,
|
|
116
|
+
ContinuationToken: continuationToken,
|
|
117
|
+
}));
|
|
118
|
+
for (const object of response.Contents ?? []) {
|
|
119
|
+
if (object.Key === undefined)
|
|
120
|
+
continue;
|
|
121
|
+
keys.push(this._prefix ? object.Key.slice(this._prefix.length) : object.Key);
|
|
122
|
+
}
|
|
123
|
+
continuationToken = response.IsTruncated ? response.NextContinuationToken : undefined;
|
|
124
|
+
} while (continuationToken);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
throw new StorageError(`Failed to list S3 bucket '${this._bucket}' under '${normalized}'`, { cause: error });
|
|
128
|
+
}
|
|
129
|
+
return keys.sort();
|
|
130
|
+
}
|
|
131
|
+
async _getClient() {
|
|
132
|
+
if (this._client)
|
|
133
|
+
return this._client;
|
|
134
|
+
const { S3Client } = await import('@aws-sdk/client-s3');
|
|
135
|
+
this._client = new S3Client(this._region ? { region: this._region } : {});
|
|
136
|
+
return this._client;
|
|
137
|
+
}
|
|
138
|
+
/** Returns a prefixed view of this storage without mutating the original. */
|
|
139
|
+
namespace(prefix) {
|
|
140
|
+
return namespace(this, prefix);
|
|
141
|
+
}
|
|
142
|
+
_objectKey(key) {
|
|
143
|
+
return `${this._prefix}${key}`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=s3-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-storage.js","sourceRoot":"","sources":["../../../src/storage/s3-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbol present on namespaced storage views. Constructs use this to detect
|
|
3
|
+
* whether the caller already scoped the storage, skipping the default prefix.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare const NAMESPACED: unique symbol;
|
|
8
|
+
/**
|
|
9
|
+
* Validates and normalizes a storage key: collapses runs of `/`, strips leading
|
|
10
|
+
* and trailing `/`, and rejects empty keys and any `..` segment.
|
|
11
|
+
*
|
|
12
|
+
* @param key - The raw key to normalize
|
|
13
|
+
* @returns The normalized key
|
|
14
|
+
* @throws {@link StorageError} if the key is empty or contains a `..` segment
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeKey(key: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Normalizes a list prefix: collapses slash runs, strips leading slashes.
|
|
19
|
+
* Unlike a key, an empty prefix is valid and matches everything.
|
|
20
|
+
*
|
|
21
|
+
* @param prefix - The raw prefix to normalize
|
|
22
|
+
* @returns The normalized prefix
|
|
23
|
+
* @throws {@link StorageError} if the prefix contains a `..` segment
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizePrefix(prefix: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* A backend for storing and retrieving raw bytes under string keys.
|
|
28
|
+
*
|
|
29
|
+
* The interface is deliberately minimal — four operations over opaque `Uint8Array`
|
|
30
|
+
* values. Implementations must treat keys as opaque path-like strings (segments
|
|
31
|
+
* separated by `/`) and must round-trip the bytes they are given unchanged.
|
|
32
|
+
*
|
|
33
|
+
* The `ListQuery` type parameter controls what `list` accepts. It defaults to
|
|
34
|
+
* `string` (a key prefix), which every backend supports. Implementations may
|
|
35
|
+
* widen it to accept a richer query object (e.g. a DynamoDB partition/sort-key
|
|
36
|
+
* filter) while still accepting a plain string for SDK-internal callers.
|
|
37
|
+
*
|
|
38
|
+
* Implement this to add a custom backend; the SDK ships {@link InMemoryStorage},
|
|
39
|
+
* {@link LocalFileStorage}, and {@link S3Storage}.
|
|
40
|
+
*/
|
|
41
|
+
export interface Storage<ListQuery = string> {
|
|
42
|
+
/**
|
|
43
|
+
* Stores `data` under `key`, overwriting any existing value.
|
|
44
|
+
*
|
|
45
|
+
* @param key - Opaque, `/`-separated key identifying the value
|
|
46
|
+
* @param data - Raw bytes to persist
|
|
47
|
+
* @throws {@link StorageError} if the write fails
|
|
48
|
+
*/
|
|
49
|
+
write(key: string, data: Uint8Array): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Retrieves the bytes previously stored under `key`.
|
|
52
|
+
*
|
|
53
|
+
* @param key - The key to read
|
|
54
|
+
* @returns The stored bytes, or `null` if no value exists for `key`
|
|
55
|
+
* @throws {@link StorageError} if the read fails for a reason other than a missing key
|
|
56
|
+
*/
|
|
57
|
+
read(key: string): Promise<Uint8Array | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Deletes the value stored under `key`. A no-op if the key does not exist.
|
|
60
|
+
*
|
|
61
|
+
* @param key - The key to delete
|
|
62
|
+
* @throws {@link StorageError} if the delete fails
|
|
63
|
+
*/
|
|
64
|
+
delete(key: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Lists keys matching the given query.
|
|
67
|
+
*
|
|
68
|
+
* When `ListQuery` is `string` (the default), this is a prefix match — returns
|
|
69
|
+
* full keys (not the suffix after the prefix), sorted lexicographically. An empty
|
|
70
|
+
* string lists every key.
|
|
71
|
+
*
|
|
72
|
+
* Implementations may accept richer query objects (e.g. partition + sort-key filters)
|
|
73
|
+
* while still supporting a plain string prefix for SDK-internal callers.
|
|
74
|
+
*
|
|
75
|
+
* @param query - A string prefix or backend-specific query object
|
|
76
|
+
* @returns The matching keys, sorted ascending
|
|
77
|
+
* @throws {@link StorageError} if the listing fails
|
|
78
|
+
*/
|
|
79
|
+
list(query: ListQuery): Promise<string[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Returns a view of this storage with all keys prefixed by `prefix`.
|
|
82
|
+
* The original storage is not mutated.
|
|
83
|
+
*
|
|
84
|
+
* Optional — shipped backends implement this, custom backends may omit it.
|
|
85
|
+
*
|
|
86
|
+
* @param prefix - Prefix to prepend to all keys
|
|
87
|
+
* @returns A Storage view scoped to the given prefix
|
|
88
|
+
*/
|
|
89
|
+
namespace?(prefix: string): Storage;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns a {@link Storage} view with all keys prefixed by `prefix`.
|
|
93
|
+
*
|
|
94
|
+
* Composable — calling `namespace()` on the result nests prefixes.
|
|
95
|
+
*
|
|
96
|
+
* @internal
|
|
97
|
+
* @param storage - The underlying storage to delegate to
|
|
98
|
+
* @param prefix - Prefix to prepend to all keys
|
|
99
|
+
* @returns A namespaced Storage view
|
|
100
|
+
*/
|
|
101
|
+
export declare function namespace(storage: Storage, prefix: string): Storage;
|
|
102
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/storage/storage.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,MAAiD,CAAA;AAEjF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAShD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAStD;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,OAAO,CAAC,SAAS,GAAG,MAAM;IACzC;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEnD;;;;;;OAMG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;IAE7C;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAElC;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAEzC;;;;;;;;OAQG;IACH,SAAS,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;CACpC;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAYnE"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { StorageError } from '../errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Symbol present on namespaced storage views. Constructs use this to detect
|
|
4
|
+
* whether the caller already scoped the storage, skipping the default prefix.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export const NAMESPACED = Symbol.for('strands.storage.namespaced');
|
|
9
|
+
/**
|
|
10
|
+
* Validates and normalizes a storage key: collapses runs of `/`, strips leading
|
|
11
|
+
* and trailing `/`, and rejects empty keys and any `..` segment.
|
|
12
|
+
*
|
|
13
|
+
* @param key - The raw key to normalize
|
|
14
|
+
* @returns The normalized key
|
|
15
|
+
* @throws {@link StorageError} if the key is empty or contains a `..` segment
|
|
16
|
+
*/
|
|
17
|
+
export function normalizeKey(key) {
|
|
18
|
+
const segments = key.split('/').filter(Boolean);
|
|
19
|
+
if (segments.length === 0) {
|
|
20
|
+
throw new StorageError('Storage key must not be empty');
|
|
21
|
+
}
|
|
22
|
+
if (segments.includes('..')) {
|
|
23
|
+
throw new StorageError(`Invalid storage key '${key}': '..' path segments are not allowed`);
|
|
24
|
+
}
|
|
25
|
+
return segments.join('/');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Normalizes a list prefix: collapses slash runs, strips leading slashes.
|
|
29
|
+
* Unlike a key, an empty prefix is valid and matches everything.
|
|
30
|
+
*
|
|
31
|
+
* @param prefix - The raw prefix to normalize
|
|
32
|
+
* @returns The normalized prefix
|
|
33
|
+
* @throws {@link StorageError} if the prefix contains a `..` segment
|
|
34
|
+
*/
|
|
35
|
+
export function normalizePrefix(prefix) {
|
|
36
|
+
const parts = prefix.split('/');
|
|
37
|
+
const segments = parts.filter(Boolean);
|
|
38
|
+
if (segments.includes('..')) {
|
|
39
|
+
throw new StorageError(`Invalid storage prefix '${prefix}': '..' path segments are not allowed`);
|
|
40
|
+
}
|
|
41
|
+
const joined = segments.join('/');
|
|
42
|
+
const normalized = parts[parts.length - 1] === '' && joined ? joined + '/' : joined;
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Returns a {@link Storage} view with all keys prefixed by `prefix`.
|
|
47
|
+
*
|
|
48
|
+
* Composable — calling `namespace()` on the result nests prefixes.
|
|
49
|
+
*
|
|
50
|
+
* @internal
|
|
51
|
+
* @param storage - The underlying storage to delegate to
|
|
52
|
+
* @param prefix - Prefix to prepend to all keys
|
|
53
|
+
* @returns A namespaced Storage view
|
|
54
|
+
*/
|
|
55
|
+
export function namespace(storage, prefix) {
|
|
56
|
+
const normalized = normalizePrefix(prefix);
|
|
57
|
+
const p = normalized ? `${normalized}/` : '';
|
|
58
|
+
const view = {
|
|
59
|
+
write: (key, data) => storage.write(`${p}${key}`, data),
|
|
60
|
+
read: (key) => storage.read(`${p}${key}`),
|
|
61
|
+
delete: (key) => storage.delete(`${p}${key}`),
|
|
62
|
+
list: (query) => storage.list(`${p}${query}`).then((keys) => keys.map((key) => key.slice(p.length))),
|
|
63
|
+
namespace: (sub) => namespace(storage, `${p}${sub}`),
|
|
64
|
+
[NAMESPACED]: true,
|
|
65
|
+
};
|
|
66
|
+
return view;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/storage/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAkB,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAA;AAEjF;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,YAAY,CAAC,+BAA+B,CAAC,CAAA;IACzD,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,YAAY,CAAC,wBAAwB,GAAG,uCAAuC,CAAC,CAAA;IAC5F,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,YAAY,CAAC,2BAA2B,MAAM,uCAAuC,CAAC,CAAA;IAClG,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,CAAA;IACnF,OAAO,UAAU,CAAA;AACnB,CAAC;AAwED;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAAC,OAAgB,EAAE,MAAc;IACxD,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;IAC1C,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IAC5C,MAAM,IAAI,GAAqC;QAC7C,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,EAAE,IAAI,CAAC;QACvD,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC;QACzC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC;QAC7C,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACpG,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC;QACpD,CAAC,UAAU,CAAC,EAAE,IAAI;KACnB,CAAA;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -135,6 +135,20 @@ export declare class Tracer {
|
|
|
135
135
|
* or LANGFUSE_BASE_URL environment variables.
|
|
136
136
|
*/
|
|
137
137
|
private readonly _isLangfuse;
|
|
138
|
+
/**
|
|
139
|
+
* Whether to record message content as span attributes instead of span events.
|
|
140
|
+
*
|
|
141
|
+
* True when the backend cannot read span events (Langfuse) or the opt-in is set via
|
|
142
|
+
* `OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_span_attributes_only`. Per OpenTelemetry the span-event
|
|
143
|
+
* recording API is deprecated, and non-timestamped span details such as the canonical
|
|
144
|
+
* `gen_ai.*.messages` attributes should be recorded as span attributes instead. This flag is
|
|
145
|
+
* passed by the aggregated content paths (latest-convention `gen_ai.*` messages and the
|
|
146
|
+
* `memory.query`/`memory.content` events); it never reaches the legacy per-message events
|
|
147
|
+
* (which reuse a `content` key and would collide as attributes).
|
|
148
|
+
*
|
|
149
|
+
* @see https://opentelemetry.io/blog/2026/deprecating-span-events/
|
|
150
|
+
*/
|
|
151
|
+
private readonly _spanAttributesOnly;
|
|
138
152
|
/** In-memory execution trace state, collected independently of OTEL. */
|
|
139
153
|
private readonly _traceState;
|
|
140
154
|
/**
|
|
@@ -337,6 +351,10 @@ export declare class Tracer {
|
|
|
337
351
|
private _endSpan;
|
|
338
352
|
/**
|
|
339
353
|
* Add an event to a span.
|
|
354
|
+
*
|
|
355
|
+
* Per OpenTelemetry the span-event recording API is deprecated. When `toSpanAttributes` is set,
|
|
356
|
+
* the attributes are recorded directly on the span and the event is skipped, so the content is
|
|
357
|
+
* recorded once rather than duplicated across both; otherwise the event is emitted.
|
|
340
358
|
*/
|
|
341
359
|
private _addEvent;
|
|
342
360
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../../../src/telemetry/tracer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../../../src/telemetry/tracer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAqC,cAAc,EAAQ,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEpH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,4BAA4B,EAC5B,0BAA0B,EAC1B,yBAAyB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,6BAA6B,EAC7B,2BAA2B,EAG5B,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAgB,OAAO,EAAgB,MAAM,sBAAsB,CAAA;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAIxD;;GAEG;AACH,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;CACxB;AAED;;;;GAIG;AACH,qBAAa,UAAW,YAAW,gBAAgB,CAAC,cAAc,CAAC;IACjE,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,uEAAuE;IACvE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAO;IAC7B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAI;IACpB,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAK;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAK;IAC9C,uFAAuF;IACvF,OAAO,EAAE,OAAO,GAAG,IAAI,CAAO;IAE9B;;;OAGG;gBACS,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,UAAU,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;IAW/E;;OAEG;IACH,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAK3B,MAAM,IAAI,cAAc;CAazB;AAiBD;;;;;;;;;GASG;AACH,qBAAa,MAAM;IACjB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IAEpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAE/C;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAS;IAEjD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgC;IAEjE,kDAAkD;IAClD,OAAO,CAAC,UAAU,CAAkB;IAEpC,kFAAkF;IAClF,OAAO,CAAC,SAAS,CAAkB;IAEnC,sFAAsF;IACtF,OAAO,CAAC,eAAe,CAAkB;IAEzC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAE7C,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkC;IAE9D;;;;;;;OAOG;gBACS,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC;IAe5D;;OAEG;IACH,IAAI,WAAW,IAAI,UAAU,EAAE,CAE9B;IAED;;;;;;OAMG;IACH,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,GAAG,IAAI;IA4C3D;;;;;OAKG;IACH,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,mBAAwB,GAAG,IAAI;IA+BxE;;;;;OAKG;IACH,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,IAAI,GAAG,IAAI;IA6BvE;;;;;OAKG;IACH,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,mBAAwB,GAAG,IAAI;IA6B9E;;;;;OAKG;IACH,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,GAAG,IAAI;IAwDjE;;;;;OAKG;IACH,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,sBAA2B,GAAG,IAAI;IAgD9E;;;;;;OAMG;IACH,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,IAAI,GAAG,IAAI;IAuBrE;;;;;OAKG;IACH,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,wBAA6B,GAAG,IAAI;IAgBlF;;;;;;OAMG;IACH,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI;IAyBzD;;;;;OAKG;IACH,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,kBAAuB,GAAG,IAAI;IAetE;;;;;;;;OAQG;IACH,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,IAAI,GAAG,IAAI;IAgBzE;;;;;;;;OAQG;IACH,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,0BAA+B,GAAG,IAAI;IA+BtF;;;;;;;;OAQG;IACH,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,IAAI,GAAG,IAAI;IAoBnE;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,uBAA4B,GAAG,IAAI;IAYhF;;;;OAIG;IACH,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG,IAAI,GAAG,IAAI;IAY9E;;;;;;;;OAQG;IACH,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,0BAA0B,GAAG,IAAI;IAcjF;;;;;;;;OAQG;IACH,sBAAsB,CAAC,OAAO,EAAE,6BAA6B,GAAG,IAAI,GAAG,IAAI;IAiC3E;;;;;OAKG;IACH,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,2BAAgC,GAAG,IAAI;IAWxF;;;;;;;;OAQG;IACH,kBAAkB,IAAI,WAAW,GAAG,SAAS;IAY7C;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAKrD;;;;;OAKG;IACH,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,IAAI,GAAG,IAAI;IAyBnE;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,uBAA4B,GAAG,IAAI;IAgBhF;;OAEG;IACH,OAAO,CAAC,UAAU;IA4ClB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAoBhB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IA2BjB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAc5B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgCzB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiCvB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAUjC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAW9B;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB;IAsB7B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,2BAA2B;IAgB1C;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAiB3C;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,+BAA+B;CAkB/C"}
|
|
@@ -141,6 +141,20 @@ export class Tracer {
|
|
|
141
141
|
* or LANGFUSE_BASE_URL environment variables.
|
|
142
142
|
*/
|
|
143
143
|
_isLangfuse;
|
|
144
|
+
/**
|
|
145
|
+
* Whether to record message content as span attributes instead of span events.
|
|
146
|
+
*
|
|
147
|
+
* True when the backend cannot read span events (Langfuse) or the opt-in is set via
|
|
148
|
+
* `OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_span_attributes_only`. Per OpenTelemetry the span-event
|
|
149
|
+
* recording API is deprecated, and non-timestamped span details such as the canonical
|
|
150
|
+
* `gen_ai.*.messages` attributes should be recorded as span attributes instead. This flag is
|
|
151
|
+
* passed by the aggregated content paths (latest-convention `gen_ai.*` messages and the
|
|
152
|
+
* `memory.query`/`memory.content` events); it never reaches the legacy per-message events
|
|
153
|
+
* (which reuse a `content` key and would collide as attributes).
|
|
154
|
+
*
|
|
155
|
+
* @see https://opentelemetry.io/blog/2026/deprecating-span-events/
|
|
156
|
+
*/
|
|
157
|
+
_spanAttributesOnly;
|
|
144
158
|
/** In-memory execution trace state, collected independently of OTEL. */
|
|
145
159
|
_traceState = { traces: [] };
|
|
146
160
|
/**
|
|
@@ -158,6 +172,7 @@ export class Tracer {
|
|
|
158
172
|
this._useLatestConventions = optInValues.has('gen_ai_latest_experimental');
|
|
159
173
|
this._includeToolDefinitions = optInValues.has('gen_ai_tool_definitions');
|
|
160
174
|
this._isLangfuse = Tracer._detectLangfuse();
|
|
175
|
+
this._spanAttributesOnly = this._isLangfuse || optInValues.has('gen_ai_span_attributes_only');
|
|
161
176
|
// Get tracer from global API to ensure ground truth
|
|
162
177
|
this._tracer = trace.getTracer(getServiceName());
|
|
163
178
|
}
|
|
@@ -340,7 +355,7 @@ export class Tracer {
|
|
|
340
355
|
parts: [{ type: 'tool_call', name: tool.name, id: tool.toolUseId, arguments: tool.input }],
|
|
341
356
|
},
|
|
342
357
|
], jsonReplacer),
|
|
343
|
-
});
|
|
358
|
+
}, this._spanAttributesOnly);
|
|
344
359
|
}
|
|
345
360
|
else {
|
|
346
361
|
this._addEvent(span, 'gen_ai.tool.message', {
|
|
@@ -384,7 +399,7 @@ export class Tracer {
|
|
|
384
399
|
parts: [{ type: 'tool_call_response', id: toolResult.toolUseId, response: toolResult.content }],
|
|
385
400
|
},
|
|
386
401
|
], jsonReplacer),
|
|
387
|
-
});
|
|
402
|
+
}, this._spanAttributesOnly);
|
|
388
403
|
}
|
|
389
404
|
else {
|
|
390
405
|
this._addEvent(span, 'gen_ai.choice', {
|
|
@@ -520,7 +535,7 @@ export class Tracer {
|
|
|
520
535
|
if (options.maxSearchResults !== undefined)
|
|
521
536
|
attributes['memory.max_search_results'] = options.maxSearchResults;
|
|
522
537
|
const span = this._startSpan({ name: 'memory.search', attributes, spanKind: SpanKind.INTERNAL });
|
|
523
|
-
this._addEvent(span, 'memory.query', { content: options.query }, this.
|
|
538
|
+
this._addEvent(span, 'memory.query', { content: options.query }, this._spanAttributesOnly);
|
|
524
539
|
return span;
|
|
525
540
|
}
|
|
526
541
|
catch (error) {
|
|
@@ -553,7 +568,7 @@ export class Tracer {
|
|
|
553
568
|
storeName: entry.storeName,
|
|
554
569
|
metadata: entry.metadata,
|
|
555
570
|
})), jsonReplacer),
|
|
556
|
-
}, this.
|
|
571
|
+
}, this._spanAttributesOnly);
|
|
557
572
|
}
|
|
558
573
|
this._endSpan(span, attributes, options.error);
|
|
559
574
|
}
|
|
@@ -581,7 +596,7 @@ export class Tracer {
|
|
|
581
596
|
spanKind: SpanKind.INTERNAL,
|
|
582
597
|
...(options.forceRoot && { forceRoot: true }),
|
|
583
598
|
});
|
|
584
|
-
this._addEvent(span, 'memory.content', { content: options.content }, this.
|
|
599
|
+
this._addEvent(span, 'memory.content', { content: options.content }, this._spanAttributesOnly);
|
|
585
600
|
return span;
|
|
586
601
|
}
|
|
587
602
|
catch (error) {
|
|
@@ -851,6 +866,10 @@ export class Tracer {
|
|
|
851
866
|
}
|
|
852
867
|
/**
|
|
853
868
|
* Add an event to a span.
|
|
869
|
+
*
|
|
870
|
+
* Per OpenTelemetry the span-event recording API is deprecated. When `toSpanAttributes` is set,
|
|
871
|
+
* the attributes are recorded directly on the span and the event is skipped, so the content is
|
|
872
|
+
* recorded once rather than duplicated across both; otherwise the event is emitted.
|
|
854
873
|
*/
|
|
855
874
|
_addEvent(span, eventName, eventAttributes, toSpanAttributes = false) {
|
|
856
875
|
try {
|
|
@@ -863,10 +882,11 @@ export class Tracer {
|
|
|
863
882
|
if (value !== undefined && value !== null)
|
|
864
883
|
otelAttributes[key] = value;
|
|
865
884
|
}
|
|
866
|
-
// Some backends (e.g. Langfuse) don't surface span events, so
|
|
867
|
-
//
|
|
885
|
+
// Some backends (e.g. Langfuse) don't surface span events, so record the attributes on the
|
|
886
|
+
// span instead of as an event.
|
|
868
887
|
if (toSpanAttributes) {
|
|
869
888
|
span.setAttributes(otelAttributes);
|
|
889
|
+
return;
|
|
870
890
|
}
|
|
871
891
|
span.addEvent(eventName, otelAttributes);
|
|
872
892
|
}
|
|
@@ -909,7 +929,7 @@ export class Tracer {
|
|
|
909
929
|
}));
|
|
910
930
|
this._addEvent(span, 'gen_ai.client.inference.operation.details', {
|
|
911
931
|
'gen_ai.input.messages': JSON.stringify(inputMessages, jsonReplacer),
|
|
912
|
-
});
|
|
932
|
+
}, this._spanAttributesOnly);
|
|
913
933
|
}
|
|
914
934
|
else {
|
|
915
935
|
for (const message of messages) {
|
|
@@ -982,7 +1002,7 @@ export class Tracer {
|
|
|
982
1002
|
if (this._useLatestConventions) {
|
|
983
1003
|
this._addEvent(span, 'gen_ai.client.inference.operation.details', {
|
|
984
1004
|
'gen_ai.output.messages': JSON.stringify([{ role: 'assistant', parts: [{ type: 'text', content: messageText }], finish_reason: finishReason }], jsonReplacer),
|
|
985
|
-
});
|
|
1005
|
+
}, this._spanAttributesOnly);
|
|
986
1006
|
}
|
|
987
1007
|
else {
|
|
988
1008
|
this._addEvent(span, 'gen_ai.choice', { message: messageText, finish_reason: finishReason });
|
|
@@ -1007,7 +1027,7 @@ export class Tracer {
|
|
|
1007
1027
|
finish_reason: finishReason,
|
|
1008
1028
|
},
|
|
1009
1029
|
], jsonReplacer),
|
|
1010
|
-
});
|
|
1030
|
+
}, this._spanAttributesOnly);
|
|
1011
1031
|
}
|
|
1012
1032
|
else {
|
|
1013
1033
|
this._addEvent(span, 'gen_ai.choice', {
|
|
@@ -1061,7 +1081,7 @@ export class Tracer {
|
|
|
1061
1081
|
const parts = Tracer._mapSystemPromptToOtelParts(systemPrompt);
|
|
1062
1082
|
this._addEvent(span, 'gen_ai.client.inference.operation.details', {
|
|
1063
1083
|
'gen_ai.system_instructions': JSON.stringify(parts, jsonReplacer),
|
|
1064
|
-
});
|
|
1084
|
+
}, this._spanAttributesOnly);
|
|
1065
1085
|
}
|
|
1066
1086
|
else {
|
|
1067
1087
|
// Normalize string prompts to an array of text blocks for consistent format
|