@xandout/libra-harness 0.1.8
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/LICENSE +21 -0
- package/README.md +486 -0
- package/dist/agent.d.ts +174 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +575 -0
- package/dist/agent.js.map +1 -0
- package/dist/ai-sdk-model.d.ts +26 -0
- package/dist/ai-sdk-model.d.ts.map +1 -0
- package/dist/ai-sdk-model.js +260 -0
- package/dist/ai-sdk-model.js.map +1 -0
- package/dist/context.d.ts +75 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +2 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/extension.d.ts +63 -0
- package/dist/extension.d.ts.map +1 -0
- package/dist/extension.js +2 -0
- package/dist/extension.js.map +1 -0
- package/dist/extras/extension-loader.d.ts +205 -0
- package/dist/extras/extension-loader.d.ts.map +1 -0
- package/dist/extras/extension-loader.js +315 -0
- package/dist/extras/extension-loader.js.map +1 -0
- package/dist/extras/extensions/auto-steer/extension.d.ts +46 -0
- package/dist/extras/extensions/auto-steer/extension.d.ts.map +1 -0
- package/dist/extras/extensions/auto-steer/extension.js +52 -0
- package/dist/extras/extensions/auto-steer/extension.js.map +1 -0
- package/dist/extras/extensions/auto-steer/extension.json +7 -0
- package/dist/extras/extensions/auto-steer/index.d.ts +3 -0
- package/dist/extras/extensions/auto-steer/index.d.ts.map +1 -0
- package/dist/extras/extensions/auto-steer/index.js +2 -0
- package/dist/extras/extensions/auto-steer/index.js.map +1 -0
- package/dist/extras/extensions/disk-session/extension.d.ts +167 -0
- package/dist/extras/extensions/disk-session/extension.d.ts.map +1 -0
- package/dist/extras/extensions/disk-session/extension.js +492 -0
- package/dist/extras/extensions/disk-session/extension.js.map +1 -0
- package/dist/extras/extensions/disk-session/extension.json +6 -0
- package/dist/extras/extensions/disk-session/extension.test.d.ts +2 -0
- package/dist/extras/extensions/disk-session/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/disk-session/extension.test.js +672 -0
- package/dist/extras/extensions/disk-session/extension.test.js.map +1 -0
- package/dist/extras/extensions/disk-session/index.d.ts +3 -0
- package/dist/extras/extensions/disk-session/index.d.ts.map +1 -0
- package/dist/extras/extensions/disk-session/index.js +2 -0
- package/dist/extras/extensions/disk-session/index.js.map +1 -0
- package/dist/extras/extensions/emoji/extension.d.ts +20 -0
- package/dist/extras/extensions/emoji/extension.d.ts.map +1 -0
- package/dist/extras/extensions/emoji/extension.js +22 -0
- package/dist/extras/extensions/emoji/extension.js.map +1 -0
- package/dist/extras/extensions/emoji/extension.json +7 -0
- package/dist/extras/extensions/emoji/index.d.ts +3 -0
- package/dist/extras/extensions/emoji/index.d.ts.map +1 -0
- package/dist/extras/extensions/emoji/index.js +2 -0
- package/dist/extras/extensions/emoji/index.js.map +1 -0
- package/dist/extras/extensions/filesystem/extension.d.ts +53 -0
- package/dist/extras/extensions/filesystem/extension.d.ts.map +1 -0
- package/dist/extras/extensions/filesystem/extension.js +350 -0
- package/dist/extras/extensions/filesystem/extension.js.map +1 -0
- package/dist/extras/extensions/filesystem/extension.json +6 -0
- package/dist/extras/extensions/filesystem/extension.test.d.ts +2 -0
- package/dist/extras/extensions/filesystem/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/filesystem/extension.test.js +387 -0
- package/dist/extras/extensions/filesystem/extension.test.js.map +1 -0
- package/dist/extras/extensions/filesystem/index.d.ts +2 -0
- package/dist/extras/extensions/filesystem/index.d.ts.map +1 -0
- package/dist/extras/extensions/filesystem/index.js +2 -0
- package/dist/extras/extensions/filesystem/index.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.d.ts +53 -0
- package/dist/extras/extensions/keyword-extractor/extension.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.js +61 -0
- package/dist/extras/extensions/keyword-extractor/extension.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.json +6 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.d.ts +2 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.js +105 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/index.d.ts +5 -0
- package/dist/extras/extensions/keyword-extractor/index.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/index.js +3 -0
- package/dist/extras/extensions/keyword-extractor/index.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.d.ts +68 -0
- package/dist/extras/extensions/keyword-extractor/nlp.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.js +156 -0
- package/dist/extras/extensions/keyword-extractor/nlp.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.d.ts +2 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.js +176 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.js.map +1 -0
- package/dist/extras/extensions/logger/extension.d.ts +52 -0
- package/dist/extras/extensions/logger/extension.d.ts.map +1 -0
- package/dist/extras/extensions/logger/extension.js +68 -0
- package/dist/extras/extensions/logger/extension.js.map +1 -0
- package/dist/extras/extensions/logger/extension.json +7 -0
- package/dist/extras/extensions/logger/index.d.ts +3 -0
- package/dist/extras/extensions/logger/index.d.ts.map +1 -0
- package/dist/extras/extensions/logger/index.js +2 -0
- package/dist/extras/extensions/logger/index.js.map +1 -0
- package/dist/extras/extensions/mcp/extension.d.ts +63 -0
- package/dist/extras/extensions/mcp/extension.d.ts.map +1 -0
- package/dist/extras/extensions/mcp/extension.js +437 -0
- package/dist/extras/extensions/mcp/extension.js.map +1 -0
- package/dist/extras/extensions/mcp/extension.json +7 -0
- package/dist/extras/extensions/mcp/extension.test.d.ts +2 -0
- package/dist/extras/extensions/mcp/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/mcp/extension.test.js +286 -0
- package/dist/extras/extensions/mcp/extension.test.js.map +1 -0
- package/dist/extras/extensions/mcp/index.d.ts +3 -0
- package/dist/extras/extensions/mcp/index.d.ts.map +1 -0
- package/dist/extras/extensions/mcp/index.js +2 -0
- package/dist/extras/extensions/mcp/index.js.map +1 -0
- package/dist/extras/extensions/mem-session/extension.d.ts +24 -0
- package/dist/extras/extensions/mem-session/extension.d.ts.map +1 -0
- package/dist/extras/extensions/mem-session/extension.js +49 -0
- package/dist/extras/extensions/mem-session/extension.js.map +1 -0
- package/dist/extras/extensions/mem-session/extension.json +6 -0
- package/dist/extras/extensions/mem-session/index.d.ts +2 -0
- package/dist/extras/extensions/mem-session/index.d.ts.map +1 -0
- package/dist/extras/extensions/mem-session/index.js +2 -0
- package/dist/extras/extensions/mem-session/index.js.map +1 -0
- package/dist/extras/extensions/memory/extension.d.ts +54 -0
- package/dist/extras/extensions/memory/extension.d.ts.map +1 -0
- package/dist/extras/extensions/memory/extension.js +143 -0
- package/dist/extras/extensions/memory/extension.js.map +1 -0
- package/dist/extras/extensions/memory/extension.json +7 -0
- package/dist/extras/extensions/memory/index.d.ts +5 -0
- package/dist/extras/extensions/memory/index.d.ts.map +1 -0
- package/dist/extras/extensions/memory/index.js +3 -0
- package/dist/extras/extensions/memory/index.js.map +1 -0
- package/dist/extras/extensions/memory/llm-extractor.d.ts +42 -0
- package/dist/extras/extensions/memory/llm-extractor.d.ts.map +1 -0
- package/dist/extras/extensions/memory/llm-extractor.js +89 -0
- package/dist/extras/extensions/memory/llm-extractor.js.map +1 -0
- package/dist/extras/extensions/memory/types.d.ts +142 -0
- package/dist/extras/extensions/memory/types.d.ts.map +1 -0
- package/dist/extras/extensions/memory/types.js +2 -0
- package/dist/extras/extensions/memory/types.js.map +1 -0
- package/dist/extras/extensions/otel/extension.d.ts +57 -0
- package/dist/extras/extensions/otel/extension.d.ts.map +1 -0
- package/dist/extras/extensions/otel/extension.js +253 -0
- package/dist/extras/extensions/otel/extension.js.map +1 -0
- package/dist/extras/extensions/otel/extension.json +7 -0
- package/dist/extras/extensions/otel/extension.test.d.ts +2 -0
- package/dist/extras/extensions/otel/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/otel/extension.test.js +399 -0
- package/dist/extras/extensions/otel/extension.test.js.map +1 -0
- package/dist/extras/extensions/otel/index.d.ts +4 -0
- package/dist/extras/extensions/otel/index.d.ts.map +1 -0
- package/dist/extras/extensions/otel/index.js +3 -0
- package/dist/extras/extensions/otel/index.js.map +1 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.d.ts +60 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.d.ts.map +1 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.js +134 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.js.map +1 -0
- package/dist/extras/extensions/scripts/extension.d.ts +180 -0
- package/dist/extras/extensions/scripts/extension.d.ts.map +1 -0
- package/dist/extras/extensions/scripts/extension.js +618 -0
- package/dist/extras/extensions/scripts/extension.js.map +1 -0
- package/dist/extras/extensions/scripts/extension.json +7 -0
- package/dist/extras/extensions/scripts/extension.test.d.ts +2 -0
- package/dist/extras/extensions/scripts/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/scripts/extension.test.js +552 -0
- package/dist/extras/extensions/scripts/extension.test.js.map +1 -0
- package/dist/extras/extensions/scripts/index.d.ts +3 -0
- package/dist/extras/extensions/scripts/index.d.ts.map +1 -0
- package/dist/extras/extensions/scripts/index.js +2 -0
- package/dist/extras/extensions/scripts/index.js.map +1 -0
- package/dist/extras/extensions/skills/extension.d.ts +105 -0
- package/dist/extras/extensions/skills/extension.d.ts.map +1 -0
- package/dist/extras/extensions/skills/extension.js +419 -0
- package/dist/extras/extensions/skills/extension.js.map +1 -0
- package/dist/extras/extensions/skills/extension.json +7 -0
- package/dist/extras/extensions/skills/extension.test.d.ts +2 -0
- package/dist/extras/extensions/skills/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/skills/extension.test.js +184 -0
- package/dist/extras/extensions/skills/extension.test.js.map +1 -0
- package/dist/extras/extensions/skills/index.d.ts +4 -0
- package/dist/extras/extensions/skills/index.d.ts.map +1 -0
- package/dist/extras/extensions/skills/index.js +3 -0
- package/dist/extras/extensions/skills/index.js.map +1 -0
- package/dist/extras/extensions/streaming/extension.d.ts +15 -0
- package/dist/extras/extensions/streaming/extension.d.ts.map +1 -0
- package/dist/extras/extensions/streaming/extension.js +41 -0
- package/dist/extras/extensions/streaming/extension.js.map +1 -0
- package/dist/extras/extensions/streaming/extension.json +6 -0
- package/dist/extras/extensions/streaming/index.d.ts +2 -0
- package/dist/extras/extensions/streaming/index.d.ts.map +1 -0
- package/dist/extras/extensions/streaming/index.js +2 -0
- package/dist/extras/extensions/streaming/index.js.map +1 -0
- package/dist/extras/extensions/structured-output/extension.d.ts +11 -0
- package/dist/extras/extensions/structured-output/extension.d.ts.map +1 -0
- package/dist/extras/extensions/structured-output/extension.js +102 -0
- package/dist/extras/extensions/structured-output/extension.js.map +1 -0
- package/dist/extras/extensions/structured-output/extension.json +7 -0
- package/dist/extras/extensions/structured-output/index.d.ts +3 -0
- package/dist/extras/extensions/structured-output/index.d.ts.map +1 -0
- package/dist/extras/extensions/structured-output/index.js +2 -0
- package/dist/extras/extensions/structured-output/index.js.map +1 -0
- package/dist/extras/extensions/timestamp/extension.d.ts +11 -0
- package/dist/extras/extensions/timestamp/extension.d.ts.map +1 -0
- package/dist/extras/extensions/timestamp/extension.js +21 -0
- package/dist/extras/extensions/timestamp/extension.js.map +1 -0
- package/dist/extras/extensions/timestamp/extension.json +6 -0
- package/dist/extras/extensions/timestamp/index.d.ts +2 -0
- package/dist/extras/extensions/timestamp/index.d.ts.map +1 -0
- package/dist/extras/extensions/timestamp/index.js +2 -0
- package/dist/extras/extensions/timestamp/index.js.map +1 -0
- package/dist/extras/extensions/token-stats/extension.d.ts +50 -0
- package/dist/extras/extensions/token-stats/extension.d.ts.map +1 -0
- package/dist/extras/extensions/token-stats/extension.js +99 -0
- package/dist/extras/extensions/token-stats/extension.js.map +1 -0
- package/dist/extras/extensions/token-stats/extension.json +7 -0
- package/dist/extras/extensions/token-stats/extension.test.d.ts +2 -0
- package/dist/extras/extensions/token-stats/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/token-stats/extension.test.js +197 -0
- package/dist/extras/extensions/token-stats/extension.test.js.map +1 -0
- package/dist/extras/extensions/token-stats/index.d.ts +3 -0
- package/dist/extras/extensions/token-stats/index.d.ts.map +1 -0
- package/dist/extras/extensions/token-stats/index.js +2 -0
- package/dist/extras/extensions/token-stats/index.js.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.d.ts +89 -0
- package/dist/extras/extensions/tool-buffer/extension.d.ts.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.js +182 -0
- package/dist/extras/extensions/tool-buffer/extension.js.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.json +7 -0
- package/dist/extras/extensions/tool-buffer/extension.test.d.ts +2 -0
- package/dist/extras/extensions/tool-buffer/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.test.js +549 -0
- package/dist/extras/extensions/tool-buffer/extension.test.js.map +1 -0
- package/dist/extras/extensions/tool-buffer/index.d.ts +3 -0
- package/dist/extras/extensions/tool-buffer/index.d.ts.map +1 -0
- package/dist/extras/extensions/tool-buffer/index.js +2 -0
- package/dist/extras/extensions/tool-buffer/index.js.map +1 -0
- package/dist/extras/extensions/weather-tool/extension.d.ts +22 -0
- package/dist/extras/extensions/weather-tool/extension.d.ts.map +1 -0
- package/dist/extras/extensions/weather-tool/extension.js +33 -0
- package/dist/extras/extensions/weather-tool/extension.js.map +1 -0
- package/dist/extras/extensions/weather-tool/extension.json +7 -0
- package/dist/extras/extensions/weather-tool/index.d.ts +3 -0
- package/dist/extras/extensions/weather-tool/index.d.ts.map +1 -0
- package/dist/extras/extensions/weather-tool/index.js +2 -0
- package/dist/extras/extensions/weather-tool/index.js.map +1 -0
- package/dist/extras/models/ai-sdk-resolver.d.ts +15 -0
- package/dist/extras/models/ai-sdk-resolver.d.ts.map +1 -0
- package/dist/extras/models/ai-sdk-resolver.js +57 -0
- package/dist/extras/models/ai-sdk-resolver.js.map +1 -0
- package/dist/extras/models/index.d.ts +5 -0
- package/dist/extras/models/index.d.ts.map +1 -0
- package/dist/extras/models/index.js +3 -0
- package/dist/extras/models/index.js.map +1 -0
- package/dist/extras/models/routing-model.d.ts +18 -0
- package/dist/extras/models/routing-model.d.ts.map +1 -0
- package/dist/extras/models/routing-model.js +24 -0
- package/dist/extras/models/routing-model.js.map +1 -0
- package/dist/extras/openai-provider/index.d.ts +3 -0
- package/dist/extras/openai-provider/index.d.ts.map +1 -0
- package/dist/extras/openai-provider/index.js +2 -0
- package/dist/extras/openai-provider/index.js.map +1 -0
- package/dist/extras/openai-provider/server.d.ts +34 -0
- package/dist/extras/openai-provider/server.d.ts.map +1 -0
- package/dist/extras/openai-provider/server.js +335 -0
- package/dist/extras/openai-provider/server.js.map +1 -0
- package/dist/handle.d.ts +56 -0
- package/dist/handle.d.ts.map +1 -0
- package/dist/handle.js +2 -0
- package/dist/handle.js.map +1 -0
- package/dist/hooks.d.ts +98 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +53 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/model.d.ts +75 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +2 -0
- package/dist/model.js.map +1 -0
- package/dist/tool.d.ts +78 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +78 -0
- package/dist/tool.js.map +1 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +178 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as createMemoryExtension } from './extension.js';
|
|
2
|
+
export { createLlmExtractor } from './llm-extractor.js';
|
|
3
|
+
export type { LlmExtractorConfig } from './llm-extractor.js';
|
|
4
|
+
export type { Memory, MemoryInput, MemoryPatch, MemoryQuery, MemoryStore, ExtractorInput, ExtractedMemory, MemoryExtractor, RetrievalInput, MemoryRetriever, MemoryExtensionConfig, } from './types.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EACV,MAAM,EACN,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,cAAc,EACd,eAAe,EACf,eAAe,EACf,cAAc,EACd,eAAe,EACf,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Model } from '../../../model.js';
|
|
2
|
+
import type { MemoryExtractor } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for the LLM-based memory extractor.
|
|
5
|
+
*/
|
|
6
|
+
export interface LlmExtractorConfig {
|
|
7
|
+
/**
|
|
8
|
+
* System prompt for the extraction call. Override to customize what
|
|
9
|
+
* the extractor considers memorable.
|
|
10
|
+
*/
|
|
11
|
+
systemPrompt?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Max tokens for the extraction response. Default: 2000.
|
|
14
|
+
* Keep this modest — extraction output is a JSON array, not prose.
|
|
15
|
+
*/
|
|
16
|
+
maxTokens?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Temperature for the extraction call. Default: 0 (deterministic).
|
|
19
|
+
*/
|
|
20
|
+
temperature?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create an LLM-based memory extractor.
|
|
24
|
+
*
|
|
25
|
+
* This is the recommended extractor. It makes a single LLM call per turn
|
|
26
|
+
* (in `afterTurn`) with a focused prompt that asks the model to decide
|
|
27
|
+
* what to create, update, or delete from the conversation.
|
|
28
|
+
*
|
|
29
|
+
* It does not need to be a full `Agent` — a direct model call with
|
|
30
|
+
* structured output is sufficient and far cheaper.
|
|
31
|
+
*
|
|
32
|
+
* The extractor is resilient to malformed output: if the model returns
|
|
33
|
+
* invalid JSON, the extraction is treated as empty (nothing persisted).
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const extractor = createLlmExtractor(model);
|
|
38
|
+
* const memoryExt = createMemoryExtension({ store, extractor });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function createLlmExtractor(model: Model, config?: LlmExtractorConfig): MemoryExtractor;
|
|
42
|
+
//# sourceMappingURL=llm-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-extractor.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/llm-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAmC,MAAM,YAAY,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,KAAK,EACZ,MAAM,CAAC,EAAE,kBAAkB,GAC1B,eAAe,CAuEjB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { messageContentToText } from '../../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create an LLM-based memory extractor.
|
|
4
|
+
*
|
|
5
|
+
* This is the recommended extractor. It makes a single LLM call per turn
|
|
6
|
+
* (in `afterTurn`) with a focused prompt that asks the model to decide
|
|
7
|
+
* what to create, update, or delete from the conversation.
|
|
8
|
+
*
|
|
9
|
+
* It does not need to be a full `Agent` — a direct model call with
|
|
10
|
+
* structured output is sufficient and far cheaper.
|
|
11
|
+
*
|
|
12
|
+
* The extractor is resilient to malformed output: if the model returns
|
|
13
|
+
* invalid JSON, the extraction is treated as empty (nothing persisted).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const extractor = createLlmExtractor(model);
|
|
18
|
+
* const memoryExt = createMemoryExtension({ store, extractor });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function createLlmExtractor(model, config) {
|
|
22
|
+
const systemPrompt = config?.systemPrompt ??
|
|
23
|
+
'You are a memory extraction system. Analyze conversations and decide what memories to create, update, or delete. Return only a JSON array.';
|
|
24
|
+
const maxTokens = config?.maxTokens ?? 2000;
|
|
25
|
+
const temperature = config?.temperature ?? 0;
|
|
26
|
+
return {
|
|
27
|
+
async extract(input) {
|
|
28
|
+
const conversationText = input.messages
|
|
29
|
+
.filter((m) => m.role !== 'system')
|
|
30
|
+
.map((m) => {
|
|
31
|
+
if (m.role === 'assistant' && m.toolCalls?.length) {
|
|
32
|
+
return `[assistant] ${messageContentToText(m.content)} (requested tools: ${m.toolCalls.map((t) => t.name).join(', ')})`;
|
|
33
|
+
}
|
|
34
|
+
return `[${m.role}] ${messageContentToText(m.content)}`;
|
|
35
|
+
})
|
|
36
|
+
.join('\n');
|
|
37
|
+
const existingText = input.existingMemories.length > 0
|
|
38
|
+
? input.existingMemories
|
|
39
|
+
.map((m) => `ID: ${m.id} | ${m.content}`)
|
|
40
|
+
.join('\n')
|
|
41
|
+
: '(none)';
|
|
42
|
+
const prompt = `Analyze the following conversation and decide what memories to create, update, or delete.
|
|
43
|
+
|
|
44
|
+
Existing memories for this session:
|
|
45
|
+
${existingText}
|
|
46
|
+
|
|
47
|
+
Conversation:
|
|
48
|
+
${conversationText}
|
|
49
|
+
|
|
50
|
+
Return a JSON array of operations. Each operation has:
|
|
51
|
+
- "action": "create" | "update" | "delete"
|
|
52
|
+
- "content": the memory text (for create/update)
|
|
53
|
+
- "targetId": existing memory ID (required for update/delete)
|
|
54
|
+
- "metadata": optional object
|
|
55
|
+
|
|
56
|
+
Guidelines:
|
|
57
|
+
- Memories should be concise, self-contained facts (1-3 sentences).
|
|
58
|
+
- Deduplicate: if a new memory overlaps with an existing one, update it.
|
|
59
|
+
- Delete memories that are contradicted by the conversation.
|
|
60
|
+
- If nothing is worth remembering, return an empty array [].
|
|
61
|
+
|
|
62
|
+
Return only the JSON array, no other text.`;
|
|
63
|
+
let response;
|
|
64
|
+
try {
|
|
65
|
+
response = await model.generate({
|
|
66
|
+
messages: [{ role: 'user', content: prompt }],
|
|
67
|
+
systemPrompt,
|
|
68
|
+
maxTokens,
|
|
69
|
+
temperature,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Model call failed — skip extraction.
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(messageContentToText(response.message.content));
|
|
78
|
+
if (!Array.isArray(parsed))
|
|
79
|
+
return [];
|
|
80
|
+
return parsed;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Malformed JSON — skip extraction.
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=llm-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-extractor.js","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/llm-extractor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAuBzD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAY,EACZ,MAA2B;IAE3B,MAAM,YAAY,GAChB,MAAM,EAAE,YAAY;QACpB,4IAA4I,CAAC;IAC/I,MAAM,SAAS,GAAG,MAAM,EAAE,SAAS,IAAI,IAAI,CAAC;IAC5C,MAAM,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC;IAE7C,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,KAAqB;YACjC,MAAM,gBAAgB,GAAG,KAAK,CAAC,QAAQ;iBACpC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;iBAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACT,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;oBAClD,OAAO,eAAe,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1H,CAAC;gBACD,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1D,CAAC,CAAC;iBACD,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,MAAM,YAAY,GAChB,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC;gBAC/B,CAAC,CAAC,KAAK,CAAC,gBAAgB;qBACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;qBACxC,IAAI,CAAC,IAAI,CAAC;gBACf,CAAC,CAAC,QAAQ,CAAC;YAEf,MAAM,MAAM,GAAG;;;EAGnB,YAAY;;;EAGZ,gBAAgB;;;;;;;;;;;;;;2CAcyB,CAAC;YAEtC,IAAI,QAAQ,CAAC;YACb,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC;oBAC9B,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;oBAC7C,YAAY;oBACZ,SAAS;oBACT,WAAW;iBACZ,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,uCAAuC;gBACvC,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC1E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;oBAAE,OAAO,EAAE,CAAC;gBACtC,OAAO,MAA2B,CAAC;YACrC,CAAC;YAAC,MAAM,CAAC;gBACP,oCAAoC;gBACpC,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { Message } from '../../../types.js';
|
|
2
|
+
import type { AgentResponse } from '../../../context.js';
|
|
3
|
+
/**
|
|
4
|
+
* A discrete piece of knowledge extracted from a conversation.
|
|
5
|
+
*
|
|
6
|
+
* Memories are natural language, not structured records. They should be
|
|
7
|
+
* concise (1-3 sentences) and self-contained.
|
|
8
|
+
*/
|
|
9
|
+
export interface Memory {
|
|
10
|
+
/** Unique identifier assigned by the store on creation. */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Natural language text, 1-3 sentences, self-contained. */
|
|
13
|
+
content: string;
|
|
14
|
+
/** Session ID this memory belongs to. */
|
|
15
|
+
scope: string;
|
|
16
|
+
/** ISO timestamp — when the memory was first created. */
|
|
17
|
+
createdAt: string;
|
|
18
|
+
/** ISO timestamp — when the memory was last updated. */
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
/** Optional metadata: tags, source, confidence, category, etc. */
|
|
21
|
+
metadata?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
/** Input for creating a new memory. */
|
|
24
|
+
export interface MemoryInput {
|
|
25
|
+
content: string;
|
|
26
|
+
scope: string;
|
|
27
|
+
metadata?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
/** Patch for updating an existing memory. */
|
|
30
|
+
export interface MemoryPatch {
|
|
31
|
+
content?: string;
|
|
32
|
+
metadata?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
/** Query for searching memories. */
|
|
35
|
+
export interface MemoryQuery {
|
|
36
|
+
/** Session ID to search within. */
|
|
37
|
+
scope: string;
|
|
38
|
+
/** Natural language search text (typically the user's message). */
|
|
39
|
+
text: string;
|
|
40
|
+
/** Maximum results to return. */
|
|
41
|
+
maxResults?: number;
|
|
42
|
+
/** Optional metadata filters (implementation-specific). */
|
|
43
|
+
filter?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Abstract storage backend.
|
|
47
|
+
*
|
|
48
|
+
* The memory extension depends on this interface; the host provides a
|
|
49
|
+
* concrete implementation (vector DB, SQLite, Postgres, etc.).
|
|
50
|
+
*
|
|
51
|
+
* The search ranking algorithm is implementation-specific. A vector DB
|
|
52
|
+
* would use cosine similarity; a simple KV store might do keyword matching.
|
|
53
|
+
* The contract is: given a scope and text, return the most relevant
|
|
54
|
+
* memories, best first.
|
|
55
|
+
*/
|
|
56
|
+
export interface MemoryStore {
|
|
57
|
+
/** Create a new memory. Returns the stored memory with id/timestamps. */
|
|
58
|
+
save(input: MemoryInput): Promise<Memory>;
|
|
59
|
+
/** Get a single memory by ID. Returns null if not found. */
|
|
60
|
+
get(id: string): Promise<Memory | null>;
|
|
61
|
+
/** Search memories within a scope. Returns results ranked by relevance. */
|
|
62
|
+
search(query: MemoryQuery): Promise<Memory[]>;
|
|
63
|
+
/** Update a memory's content and/or metadata. */
|
|
64
|
+
update(id: string, patch: MemoryPatch): Promise<Memory>;
|
|
65
|
+
/** Delete a memory by ID. */
|
|
66
|
+
delete(id: string): Promise<void>;
|
|
67
|
+
/** List all memories for a scope (for extractor dedup context). */
|
|
68
|
+
listByScope(scope: string): Promise<Memory[]>;
|
|
69
|
+
/** Optional: prune memories according to a store-defined policy. */
|
|
70
|
+
prune?(scope: string): Promise<number>;
|
|
71
|
+
}
|
|
72
|
+
/** Input passed to the extractor. */
|
|
73
|
+
export interface ExtractorInput {
|
|
74
|
+
/** Session ID. */
|
|
75
|
+
scope: string;
|
|
76
|
+
/** The full conversation messages from this turn. */
|
|
77
|
+
messages: Message[];
|
|
78
|
+
/** The agent's final response. */
|
|
79
|
+
response: AgentResponse;
|
|
80
|
+
/** Existing memories for this scope (for dedup/update/delete decisions). */
|
|
81
|
+
existingMemories: Memory[];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A single extraction operation — what the extractor decided to do with
|
|
85
|
+
* one piece of information from the conversation.
|
|
86
|
+
*/
|
|
87
|
+
export interface ExtractedMemory {
|
|
88
|
+
/** The memory text (for create) or new text (for update). */
|
|
89
|
+
content: string;
|
|
90
|
+
/** What to do with this extraction. */
|
|
91
|
+
action: 'create' | 'update' | 'delete';
|
|
92
|
+
/** Required for update/delete — the existing memory ID to modify. */
|
|
93
|
+
targetId?: string;
|
|
94
|
+
/** Optional metadata to attach or merge. */
|
|
95
|
+
metadata?: Record<string, unknown>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Decides what to remember from a completed turn.
|
|
99
|
+
*
|
|
100
|
+
* Called in the `afterTurn` hook. Receives the full conversation and
|
|
101
|
+
* existing memories so it can deduplicate, update, or delete as well as
|
|
102
|
+
* create. Returns a list of operations to apply to the store.
|
|
103
|
+
*/
|
|
104
|
+
export interface MemoryExtractor {
|
|
105
|
+
extract(input: ExtractorInput): Promise<ExtractedMemory[]>;
|
|
106
|
+
}
|
|
107
|
+
/** Input passed to the retriever. */
|
|
108
|
+
export interface RetrievalInput {
|
|
109
|
+
/** Session ID. */
|
|
110
|
+
scope: string;
|
|
111
|
+
/** The user's message (search query). */
|
|
112
|
+
text: string;
|
|
113
|
+
/** The store to search against. */
|
|
114
|
+
store: MemoryStore;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Formats and filters search results before injection.
|
|
118
|
+
*
|
|
119
|
+
* Separated from the store so retrieval logic (formatting, truncation,
|
|
120
|
+
* relevance thresholds) can vary independently of storage.
|
|
121
|
+
*/
|
|
122
|
+
export interface MemoryRetriever {
|
|
123
|
+
retrieve(input: RetrievalInput): Promise<Memory[]>;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Configuration for the memory extension.
|
|
127
|
+
*/
|
|
128
|
+
export interface MemoryExtensionConfig {
|
|
129
|
+
/** Storage backend (required). */
|
|
130
|
+
store: MemoryStore;
|
|
131
|
+
/** Extraction strategy (required). */
|
|
132
|
+
extractor: MemoryExtractor;
|
|
133
|
+
/** Retrieval strategy (optional — defaults to pass-through to store.search). */
|
|
134
|
+
retriever?: MemoryRetriever;
|
|
135
|
+
/** Max memories to inject per turn (default: 10). */
|
|
136
|
+
maxRecall?: number;
|
|
137
|
+
/** Metadata key for session ID (default: 'sessionId'). */
|
|
138
|
+
scopeKey?: string;
|
|
139
|
+
/** Extension load priority (default: -95). */
|
|
140
|
+
priority?: number;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Extension } from '../../../extension.js';
|
|
2
|
+
import { type Tracer } from '@opentelemetry/api';
|
|
3
|
+
/**
|
|
4
|
+
* Config for the OpenTelemetry extension.
|
|
5
|
+
*
|
|
6
|
+
* The extension codes against `@opentelemetry/api` only. The host is
|
|
7
|
+
* responsible for setting up an SDK and exporter (e.g.
|
|
8
|
+
* `@opentelemetry/sdk-node`) before creating the agent — the extension
|
|
9
|
+
* just acquires a tracer and creates spans.
|
|
10
|
+
*/
|
|
11
|
+
export interface OtelExtensionConfig {
|
|
12
|
+
/**
|
|
13
|
+
* Tracer to use. If omitted, acquires the global tracer registered
|
|
14
|
+
* with `@opentelemetry/api` under the given `tracerName` (default:
|
|
15
|
+
* `'libra'`). Most hosts register a global tracer provider and never
|
|
16
|
+
* need to pass this.
|
|
17
|
+
*/
|
|
18
|
+
tracer?: Tracer;
|
|
19
|
+
/** Tracer name used with `trace.getTracer()`. Default: `'libra'`. */
|
|
20
|
+
tracerName?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Service name set as an attribute on the root turn span. Useful for
|
|
23
|
+
* distinguishing multiple agents in the same process (e.g.
|
|
24
|
+
* `'slack-bot'`, `'research-agent'`). Default: not set.
|
|
25
|
+
*/
|
|
26
|
+
serviceName?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Whether to record tool call arguments as span attributes. Default:
|
|
29
|
+
* `false` — arguments may contain sensitive data. Enable only in
|
|
30
|
+
* trusted environments.
|
|
31
|
+
*/
|
|
32
|
+
recordToolArgs?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Max length for tool result content recorded as a span event.
|
|
35
|
+
* Default: 500. Set to 0 to disable result recording.
|
|
36
|
+
*/
|
|
37
|
+
maxResultLength?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Metadata keys to record as span attributes on the root `agent.turn`
|
|
40
|
+
* span. This is how turns are correlated to sessions, channels, users,
|
|
41
|
+
* etc. The extension reads `ctx.turn.metadata[key]` and sets
|
|
42
|
+
* `libra.turn.<key>` on the span.
|
|
43
|
+
*
|
|
44
|
+
* Nested keys are supported via dot notation — e.g. `'slack.channelId'`
|
|
45
|
+
* reads `metadata.slack.channelId` and records it as
|
|
46
|
+
* `libra.turn.slack.channelId`.
|
|
47
|
+
*
|
|
48
|
+
* Default: `['sessionId']` — records the session ID if present.
|
|
49
|
+
* The slack-bot overrides this to also record channel/thread/user info.
|
|
50
|
+
*
|
|
51
|
+
* Only string, number, and boolean values are recorded; objects and
|
|
52
|
+
* arrays are skipped (OTel attributes are primitives).
|
|
53
|
+
*/
|
|
54
|
+
metadataKeys?: string[];
|
|
55
|
+
}
|
|
56
|
+
export default function createOtelExtension(config?: OtelExtensionConfig): Extension;
|
|
57
|
+
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/otel/extension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAkC,KAAK,MAAM,EAAa,MAAM,oBAAoB,CAAC;AAE5F;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAqED,MAAM,CAAC,OAAO,UAAU,mBAAmB,CACzC,MAAM,CAAC,EAAE,mBAAmB,GAC3B,SAAS,CAsNX"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { messageContentToText } from '../../../types.js';
|
|
2
|
+
import { trace, context, SpanStatusCode } from '@opentelemetry/api';
|
|
3
|
+
/**
|
|
4
|
+
* OpenTelemetry observability extension.
|
|
5
|
+
*
|
|
6
|
+
* Creates a span hierarchy that mirrors the agent turn lifecycle:
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* agent.turn (root span)
|
|
10
|
+
* ├── llm.request (per LLM call)
|
|
11
|
+
* ├── llm.request
|
|
12
|
+
* │ ├── tool.<name> (per tool call)
|
|
13
|
+
* │ └── tool.<name>
|
|
14
|
+
* └── llm.request
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Spans are created using `@opentelemetry/api` — the host must register
|
|
18
|
+
* a tracer provider (e.g. via `@opentelemetry/sdk-node`) for spans to
|
|
19
|
+
* be collected and exported. If no provider is registered, the
|
|
20
|
+
* extension is a no-op (the API returns no-op spans).
|
|
21
|
+
*
|
|
22
|
+
* ## Span attributes
|
|
23
|
+
*
|
|
24
|
+
* **agent.turn** (root):
|
|
25
|
+
* - `libra.turn.finish_reason` — stop, halted, max_iterations, error
|
|
26
|
+
* - `libra.turn.iterations` — number of LLM iterations
|
|
27
|
+
* - `libra.turn.tool_calls` — total tool calls made
|
|
28
|
+
* - `libra.turn.message_length` — input message length
|
|
29
|
+
* - `libra.turn.duration_ms` — total turn duration
|
|
30
|
+
* - `libra.service` — service name (if configured)
|
|
31
|
+
* - `libra.turn.<key>` — one per configured `metadataKeys` (default:
|
|
32
|
+
* `libra.turn.sessionId`). Used to correlate turns to sessions,
|
|
33
|
+
* channels, users, etc. Supports dot notation (e.g.
|
|
34
|
+
* `slack.channelId` → `libra.turn.slack.channelId`).
|
|
35
|
+
*
|
|
36
|
+
* **llm.request**:
|
|
37
|
+
* - `libra.llm.message_count` — messages sent to the model
|
|
38
|
+
* - `libra.llm.tool_count` — tools available to the model
|
|
39
|
+
* - `libra.llm.has_tool_calls` — whether the response requested tools
|
|
40
|
+
* - `libra.llm.prompt_tokens` — prompt tokens (if reported by provider)
|
|
41
|
+
* - `libra.llm.completion_tokens` — completion tokens (if reported)
|
|
42
|
+
* - `libra.llm.cached_prompt_tokens` — cached prompt tokens (if reported)
|
|
43
|
+
* - `libra.llm.reasoning_tokens` — reasoning tokens (if reported)
|
|
44
|
+
*
|
|
45
|
+
* **tool.\<name\>**:
|
|
46
|
+
* - `libra.tool.name` — tool name
|
|
47
|
+
* - `libra.tool.is_error` — whether the tool returned an error
|
|
48
|
+
* - `libra.tool.args` — tool arguments JSON (if `recordToolArgs` enabled)
|
|
49
|
+
*
|
|
50
|
+
* ## Priority
|
|
51
|
+
*
|
|
52
|
+
* Uses priority 200 (higher than logger at 100) so spans start before
|
|
53
|
+
* other extensions mutate state — timing reflects raw lifecycle cost.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a dot-notation path from a metadata object.
|
|
57
|
+
* e.g. 'slack.channelId' → metadata.slack.channelId
|
|
58
|
+
* Returns undefined if any segment is missing or not an object.
|
|
59
|
+
*/
|
|
60
|
+
function resolveMetaPath(meta, path) {
|
|
61
|
+
const parts = path.split('.');
|
|
62
|
+
let current = meta;
|
|
63
|
+
for (const part of parts) {
|
|
64
|
+
if (current === null || typeof current !== 'object')
|
|
65
|
+
return undefined;
|
|
66
|
+
current = current[part];
|
|
67
|
+
}
|
|
68
|
+
return current;
|
|
69
|
+
}
|
|
70
|
+
export default function createOtelExtension(config) {
|
|
71
|
+
const tracer = config?.tracer ?? trace.getTracer(config?.tracerName ?? 'libra');
|
|
72
|
+
const serviceName = config?.serviceName;
|
|
73
|
+
const recordToolArgs = config?.recordToolArgs ?? false;
|
|
74
|
+
const maxResultLength = config?.maxResultLength ?? 500;
|
|
75
|
+
const metadataKeys = config?.metadataKeys ?? ['sessionId'];
|
|
76
|
+
// Per-turn span state, keyed by the turn object identity. This avoids
|
|
77
|
+
// relying on turn.metadata (which other extensions may clear or mutate)
|
|
78
|
+
// and naturally supports concurrent turns.
|
|
79
|
+
const turnSpans = new WeakMap();
|
|
80
|
+
// The active LLM span for the current iteration. Stored in a per-turn
|
|
81
|
+
// WeakMap so tool spans are created as children of the right LLM span.
|
|
82
|
+
const llmSpans = new WeakMap();
|
|
83
|
+
// Timing for stages that don't have a natural span (beforeTurn → afterTurn
|
|
84
|
+
// is the root span, but we also record per-stage durations as events).
|
|
85
|
+
const stageTimings = new WeakMap();
|
|
86
|
+
function getTiming(turn, stage) {
|
|
87
|
+
return stageTimings.get(turn)?.get(stage);
|
|
88
|
+
}
|
|
89
|
+
function setTiming(turn, stage, time) {
|
|
90
|
+
let map = stageTimings.get(turn);
|
|
91
|
+
if (!map) {
|
|
92
|
+
map = new Map();
|
|
93
|
+
stageTimings.set(turn, map);
|
|
94
|
+
}
|
|
95
|
+
map.set(stage, time);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
name: 'otel',
|
|
99
|
+
priority: 200,
|
|
100
|
+
install(agent) {
|
|
101
|
+
// ── beforeTurn: start root span ──────────────────────────────
|
|
102
|
+
agent.hook('beforeTurn', 'otel', async (ctx) => {
|
|
103
|
+
const span = tracer.startSpan('agent.turn');
|
|
104
|
+
const turnObj = ctx.turn;
|
|
105
|
+
turnSpans.set(turnObj, span);
|
|
106
|
+
if (serviceName) {
|
|
107
|
+
span.setAttribute('libra.service', serviceName);
|
|
108
|
+
}
|
|
109
|
+
span.setAttribute('libra.turn.message_length', messageContentToText(ctx.turn.request.message).length);
|
|
110
|
+
// Record metadata keys as span attributes for session/channel
|
|
111
|
+
// correlation. Supports dot notation for nested keys (e.g.
|
|
112
|
+
// 'slack.channelId' → metadata.slack.channelId).
|
|
113
|
+
const meta = ctx.turn.metadata;
|
|
114
|
+
for (const key of metadataKeys) {
|
|
115
|
+
const value = resolveMetaPath(meta, key);
|
|
116
|
+
if (value !== undefined && (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean')) {
|
|
117
|
+
span.setAttribute(`libra.turn.${key}`, value);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
setTiming(turnObj, 'beforeTurn', performance.now());
|
|
121
|
+
// Set the span as active so child spans (LLM, tools) are
|
|
122
|
+
// parented to it automatically via context.
|
|
123
|
+
context.active();
|
|
124
|
+
});
|
|
125
|
+
// ── beforeContext: record timing ─────────────────────────────
|
|
126
|
+
agent.hook('beforeContext', 'otel', async (ctx) => {
|
|
127
|
+
setTiming(ctx.turn, 'beforeContext', performance.now());
|
|
128
|
+
});
|
|
129
|
+
// ── beforeLLM: start LLM child span ──────────────────────────
|
|
130
|
+
agent.hook('beforeLLM', 'otel', async (ctx) => {
|
|
131
|
+
const turnObj = ctx.turn;
|
|
132
|
+
const rootSpan = turnSpans.get(turnObj);
|
|
133
|
+
if (!rootSpan)
|
|
134
|
+
return;
|
|
135
|
+
// Start the LLM span as a child of the root span.
|
|
136
|
+
const llmSpan = tracer.startSpan('llm.request', undefined, trace.setSpan(context.active(), rootSpan));
|
|
137
|
+
llmSpans.set(turnObj, llmSpan);
|
|
138
|
+
if (ctx.modelRequest) {
|
|
139
|
+
llmSpan.setAttribute('libra.llm.message_count', ctx.modelRequest.messages.length);
|
|
140
|
+
llmSpan.setAttribute('libra.llm.tool_count', ctx.modelRequest.tools?.length ?? 0);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
// ── afterLLM: end LLM span, record usage ─────────────────────
|
|
144
|
+
agent.hook('afterLLM', 'otel', async (ctx) => {
|
|
145
|
+
const turnObj = ctx.turn;
|
|
146
|
+
const llmSpan = llmSpans.get(turnObj);
|
|
147
|
+
if (!llmSpan)
|
|
148
|
+
return;
|
|
149
|
+
const resp = ctx.modelResponse;
|
|
150
|
+
if (resp) {
|
|
151
|
+
const toolCalls = resp.message.toolCalls;
|
|
152
|
+
llmSpan.setAttribute('libra.llm.has_tool_calls', !!toolCalls?.length);
|
|
153
|
+
if (resp.usage) {
|
|
154
|
+
llmSpan.setAttribute('libra.llm.prompt_tokens', resp.usage.promptTokens);
|
|
155
|
+
llmSpan.setAttribute('libra.llm.completion_tokens', resp.usage.completionTokens);
|
|
156
|
+
if (resp.usage.cachedPromptTokens) {
|
|
157
|
+
llmSpan.setAttribute('libra.llm.cached_prompt_tokens', resp.usage.cachedPromptTokens);
|
|
158
|
+
}
|
|
159
|
+
if (resp.usage.reasoningTokens) {
|
|
160
|
+
llmSpan.setAttribute('libra.llm.reasoning_tokens', resp.usage.reasoningTokens);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (resp.finishReason) {
|
|
164
|
+
llmSpan.setAttribute('libra.llm.finish_reason', resp.finishReason);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
llmSpan.end();
|
|
168
|
+
llmSpans.delete(turnObj);
|
|
169
|
+
});
|
|
170
|
+
// ── beforeTool: start tool child span ────────────────────────
|
|
171
|
+
agent.hook('beforeTool', 'otel', async (ctx) => {
|
|
172
|
+
const turnObj = ctx.turn;
|
|
173
|
+
const toolName = ctx.toolCall?.name ?? 'unknown';
|
|
174
|
+
const parentSpan = llmSpans.get(turnObj) ?? turnSpans.get(turnObj);
|
|
175
|
+
if (!parentSpan)
|
|
176
|
+
return;
|
|
177
|
+
const toolSpan = tracer.startSpan(`tool.${toolName}`, undefined, trace.setSpan(context.active(), parentSpan));
|
|
178
|
+
// Stash the tool span on the turn's metadata so afterTool can
|
|
179
|
+
// find it. Use a unique key per tool call id to handle batches.
|
|
180
|
+
if (ctx.toolCall) {
|
|
181
|
+
const key = `_otel_tool_span_${ctx.toolCall.id}`;
|
|
182
|
+
ctx.turn.metadata[key] = toolSpan;
|
|
183
|
+
}
|
|
184
|
+
toolSpan.setAttribute('libra.tool.name', toolName);
|
|
185
|
+
if (recordToolArgs && ctx.toolCall) {
|
|
186
|
+
try {
|
|
187
|
+
toolSpan.setAttribute('libra.tool.args', ctx.toolCall.arguments);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Args may not be serializable — skip.
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
// ── afterTool: end tool span, record result ──────────────────
|
|
195
|
+
agent.hook('afterTool', 'otel', async (ctx) => {
|
|
196
|
+
if (!ctx.toolCall)
|
|
197
|
+
return;
|
|
198
|
+
const key = `_otel_tool_span_${ctx.toolCall.id}`;
|
|
199
|
+
const toolSpan = ctx.turn.metadata[key];
|
|
200
|
+
if (!toolSpan)
|
|
201
|
+
return;
|
|
202
|
+
if (ctx.toolResult) {
|
|
203
|
+
const isError = !!ctx.toolResult.isError;
|
|
204
|
+
toolSpan.setAttribute('libra.tool.is_error', isError);
|
|
205
|
+
if (maxResultLength > 0 && ctx.toolResult.content) {
|
|
206
|
+
const content = ctx.toolResult.content;
|
|
207
|
+
const truncated = content.length > maxResultLength
|
|
208
|
+
? content.slice(0, maxResultLength) + '…'
|
|
209
|
+
: content;
|
|
210
|
+
toolSpan.addEvent('tool.result', { 'libra.tool.result': truncated });
|
|
211
|
+
}
|
|
212
|
+
if (isError) {
|
|
213
|
+
toolSpan.setStatus({ code: SpanStatusCode.ERROR });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
toolSpan.end();
|
|
217
|
+
delete ctx.turn.metadata[key];
|
|
218
|
+
});
|
|
219
|
+
// ── onError: record exception on root span ───────────────────
|
|
220
|
+
agent.hook('onError', 'otel', async (ctx) => {
|
|
221
|
+
const rootSpan = turnSpans.get(ctx.turn);
|
|
222
|
+
if (!rootSpan)
|
|
223
|
+
return;
|
|
224
|
+
const err = ctx.error;
|
|
225
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
226
|
+
rootSpan.recordException(err instanceof Error ? err : new Error(message));
|
|
227
|
+
rootSpan.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
228
|
+
});
|
|
229
|
+
// ── afterTurn: end root span with final attributes ────────────
|
|
230
|
+
agent.hook('afterTurn', 'otel', async (ctx) => {
|
|
231
|
+
const turnObj = ctx.turn;
|
|
232
|
+
const rootSpan = turnSpans.get(turnObj);
|
|
233
|
+
if (!rootSpan)
|
|
234
|
+
return;
|
|
235
|
+
const resp = ctx.turn.response;
|
|
236
|
+
if (resp) {
|
|
237
|
+
rootSpan.setAttribute('libra.turn.finish_reason', resp.finishReason);
|
|
238
|
+
rootSpan.setAttribute('libra.turn.iterations', resp.iterations);
|
|
239
|
+
rootSpan.setAttribute('libra.turn.tool_calls', resp.toolCalls?.length ?? 0);
|
|
240
|
+
}
|
|
241
|
+
// Record total turn duration as an attribute.
|
|
242
|
+
const startTime = getTiming(turnObj, 'beforeTurn');
|
|
243
|
+
if (startTime) {
|
|
244
|
+
const durationMs = performance.now() - startTime;
|
|
245
|
+
rootSpan.setAttribute('libra.turn.duration_ms', Math.round(durationMs));
|
|
246
|
+
}
|
|
247
|
+
rootSpan.end();
|
|
248
|
+
turnSpans.delete(turnObj);
|
|
249
|
+
});
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../src/extras/extensions/otel/extension.ts"],"names":[],"mappings":"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"}
|