@ultrathink-solutions/openclaw-logfire 0.1.2 → 0.3.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/CHANGELOG.md +47 -0
- package/README.md +37 -32
- package/dist/context/propagation.d.ts.map +1 -1
- package/dist/context/propagation.js +14 -16
- package/dist/context/propagation.js.map +1 -1
- package/dist/context/span-store.d.ts +28 -0
- package/dist/context/span-store.d.ts.map +1 -1
- package/dist/context/span-store.js +27 -3
- package/dist/context/span-store.js.map +1 -1
- package/dist/hooks/agent-end.d.ts +7 -16
- package/dist/hooks/agent-end.d.ts.map +1 -1
- package/dist/hooks/agent-end.js +63 -39
- package/dist/hooks/agent-end.js.map +1 -1
- package/dist/hooks/before-agent-start.d.ts +12 -11
- package/dist/hooks/before-agent-start.d.ts.map +1 -1
- package/dist/hooks/before-agent-start.js +14 -14
- package/dist/hooks/before-agent-start.js.map +1 -1
- package/dist/hooks/before-tool-call.d.ts +10 -9
- package/dist/hooks/before-tool-call.d.ts.map +1 -1
- package/dist/hooks/before-tool-call.js +19 -16
- package/dist/hooks/before-tool-call.js.map +1 -1
- package/dist/hooks/llm-input.d.ts +27 -0
- package/dist/hooks/llm-input.d.ts.map +1 -0
- package/dist/hooks/llm-input.js +53 -0
- package/dist/hooks/llm-input.js.map +1 -0
- package/dist/hooks/llm-output.d.ts +25 -0
- package/dist/hooks/llm-output.d.ts.map +1 -0
- package/dist/hooks/llm-output.js +97 -0
- package/dist/hooks/llm-output.js.map +1 -0
- package/dist/hooks/message-received.d.ts +12 -10
- package/dist/hooks/message-received.d.ts.map +1 -1
- package/dist/hooks/message-received.js +13 -21
- package/dist/hooks/message-received.js.map +1 -1
- package/dist/hooks/tool-result-persist.d.ts +13 -6
- package/dist/hooks/tool-result-persist.d.ts.map +1 -1
- package/dist/hooks/tool-result-persist.js +26 -43
- package/dist/hooks/tool-result-persist.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -16
- package/dist/index.js.map +1 -1
- package/dist/metrics/genai-metrics.js +1 -1
- package/dist/otel.js +2 -2
- package/dist/otel.js.map +1 -1
- package/package.json +15 -13
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,51 @@ All notable changes to `@ultrathink-solutions/openclaw-logfire` will be document
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.0] - 2026-02-16
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `llm_input` and `llm_output` hook handlers for per-LLM-call observability
|
|
13
|
+
- Individual `gen_ai.chat` child spans for each LLM invocation, correlated by `runId`
|
|
14
|
+
- Token usage metrics now populated with real data from `llm_output` hook (`recordTokenUsage()` was previously stubbed but never called)
|
|
15
|
+
- Model name tracking (`gen_ai.request.model`, `gen_ai.response.model`) on LLM and agent spans
|
|
16
|
+
- Cache token tracking (`openclaw.usage.cache_read_tokens`, `openclaw.usage.cache_write_tokens`) on LLM spans
|
|
17
|
+
- Cumulative token counts set on root `invoke_agent` span at session end
|
|
18
|
+
- Inference detail events (`gen_ai.client.inference.operation.details`) now emitted when `captureInferenceEvents` is enabled
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **OpenTelemetry SDK upgraded from 1.x to 2.x** — stable SDK 1.30→2.5, experimental 0.57→0.212. Only breaking change: `Resource` class constructor replaced with `resourceFromAttributes()`. Dependency ranges updated; consumers using OTEL 2.x will no longer see peer dep warnings.
|
|
23
|
+
- Token usage metrics include actual model names instead of empty strings
|
|
24
|
+
- Operation duration metrics include model name and provider from LLM hooks
|
|
25
|
+
- Provider name on agent span is updated from `llm_input` when config `providerName` is unset
|
|
26
|
+
- Zero-value token counts (e.g. 0 output tokens) are now correctly accumulated — fixed truthy checks that silently dropped zeros
|
|
27
|
+
- LLM span closure wrapped in `try/finally` to prevent span leaks on exceptions
|
|
28
|
+
- Prompt content capture now applies `prepareForCapture()` redaction and truncation (consistent with tool args)
|
|
29
|
+
- `isRecord` runtime guard added to `llm_input`/`llm_output` hook registrations (consistent with all other hooks)
|
|
30
|
+
- Orphaned span cleanup uses LIFO order (children before parent) for valid trace trees
|
|
31
|
+
|
|
32
|
+
### Testing
|
|
33
|
+
|
|
34
|
+
- Hook handler unit tests added — 113 tests across 11 files, coverage boosted from 28% to 67%
|
|
35
|
+
|
|
36
|
+
### Known Limitations
|
|
37
|
+
|
|
38
|
+
- `after_tool_call` hook not yet implemented — OpenClaw SDK passes `sessionKey: undefined` at all call sites, making span store lookup impossible. Per-tool error status is not available on tool spans. Tool errors are still captured at the agent level via the `agent_end` hook. Pending upstream fix.
|
|
39
|
+
|
|
40
|
+
## [0.2.0] - 2026-02-16
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- **Breaking:** Align all hook handlers with the OpenClaw plugin SDK `(event, ctx)` two-argument contract. Previous version only captured the first argument and expected context data nested inside the event, which caused `TypeError: Cannot read properties of undefined` on every hook invocation.
|
|
45
|
+
- Correct event property names: `event.toolName` (was `event.tool?.name`), `event.params` (was `event.tool?.args`), `event.message` (was `event.result`)
|
|
46
|
+
|
|
47
|
+
### Removed
|
|
48
|
+
|
|
49
|
+
- Token usage recording in `agent_end` — token data is not available in the `agent_end` event payload (restored in 0.3.0 via `llm_output` hook)
|
|
50
|
+
- W3C trace context extraction from webhook headers in `message_received` — raw HTTP headers are not exposed in the `message_received` event metadata
|
|
51
|
+
- Per-tool error recording in `tool_result_persist` — error details are not available in that hook's event payload
|
|
52
|
+
|
|
8
53
|
## [0.1.2] - 2026-02-16
|
|
9
54
|
|
|
10
55
|
### Fixed
|
|
@@ -46,6 +91,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
46
91
|
- Batch and simple span processor modes
|
|
47
92
|
- Zero-config quickstart (just set `LOGFIRE_TOKEN`)
|
|
48
93
|
|
|
94
|
+
[0.3.0]: https://github.com/Ultrathink-Solutions/openclaw-logfire/compare/v0.2.0...v0.3.0
|
|
95
|
+
[0.2.0]: https://github.com/Ultrathink-Solutions/openclaw-logfire/compare/v0.1.2...v0.2.0
|
|
49
96
|
[0.1.2]: https://github.com/Ultrathink-Solutions/openclaw-logfire/compare/v0.1.1...v0.1.2
|
|
50
97
|
[0.1.1]: https://github.com/Ultrathink-Solutions/openclaw-logfire/compare/v0.1.0...v0.1.1
|
|
51
98
|
[0.1.0]: https://github.com/Ultrathink-Solutions/openclaw-logfire/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -45,28 +45,35 @@ Restart OpenClaw. That's it — traces appear in your Logfire dashboard.
|
|
|
45
45
|
Every agent invocation produces a trace tree:
|
|
46
46
|
|
|
47
47
|
```
|
|
48
|
-
invoke_agent
|
|
48
|
+
invoke_agent my-agent (root span, cumulative tokens)
|
|
49
|
+
|-- gen_ai.chat anthropic (LLM call: model, input/output tokens)
|
|
49
50
|
|-- execute_tool Read (file read)
|
|
50
51
|
|-- execute_tool exec (shell command)
|
|
52
|
+
|-- gen_ai.chat anthropic (LLM call: model, input/output tokens)
|
|
51
53
|
|-- execute_tool Write (file write)
|
|
52
|
-
|--
|
|
54
|
+
|-- gen_ai.chat anthropic (LLM call: model, input/output tokens)
|
|
53
55
|
```
|
|
54
56
|
|
|
55
57
|
### Attributes (OTEL GenAI Semantic Conventions)
|
|
56
58
|
|
|
57
|
-
| Attribute | Example | Description |
|
|
58
|
-
|
|
59
|
-
| `gen_ai.operation.name` | `invoke_agent` | Operation type |
|
|
60
|
-
| `gen_ai.agent.name` | `
|
|
61
|
-
| `gen_ai.conversation.id` | `session_abc123` | Session key |
|
|
62
|
-
| `gen_ai.
|
|
63
|
-
| `gen_ai.
|
|
64
|
-
| `gen_ai.
|
|
65
|
-
| `gen_ai.usage.
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `openclaw.
|
|
69
|
-
| `
|
|
59
|
+
| Attribute | Span | Example | Description |
|
|
60
|
+
|-----------|------|---------|-------------|
|
|
61
|
+
| `gen_ai.operation.name` | All | `invoke_agent` | Operation type |
|
|
62
|
+
| `gen_ai.agent.name` | Agent | `my-agent` | Agent identifier |
|
|
63
|
+
| `gen_ai.conversation.id` | Agent | `session_abc123` | Session key |
|
|
64
|
+
| `gen_ai.request.model` | Agent, LLM | `claude-sonnet-4-5-20250929` | Model name |
|
|
65
|
+
| `gen_ai.response.model` | Agent, LLM | `claude-sonnet-4-5-20250929` | Response model |
|
|
66
|
+
| `gen_ai.provider.name` | Agent, LLM | `anthropic` | LLM provider |
|
|
67
|
+
| `gen_ai.usage.input_tokens` | Agent, LLM | `1024` | Input tokens (cumulative on agent) |
|
|
68
|
+
| `gen_ai.usage.output_tokens` | Agent, LLM | `512` | Output tokens (cumulative on agent) |
|
|
69
|
+
| `openclaw.usage.cache_read_tokens` | Agent, LLM | `8192` | Cached prompt tokens read |
|
|
70
|
+
| `openclaw.usage.cache_write_tokens` | Agent, LLM | `4096` | Cached prompt tokens written |
|
|
71
|
+
| `gen_ai.tool.name` | Tool | `Read` | Tool being called |
|
|
72
|
+
| `gen_ai.tool.call.id` | Tool | `call_abc123` | Unique tool call identifier |
|
|
73
|
+
| `gen_ai.tool.call.arguments` | Tool | `{"path": "/..."}` | Tool input (opt-in) |
|
|
74
|
+
| `error.type` | Agent | `AgentError` | Error classification |
|
|
75
|
+
| `openclaw.workspace` | Agent | `my-agent` | Workspace name |
|
|
76
|
+
| `openclaw.channel` | Agent | `slack` | Message source |
|
|
70
77
|
|
|
71
78
|
### Metrics
|
|
72
79
|
|
|
@@ -77,13 +84,7 @@ invoke_agent chief-of-staff (root span)
|
|
|
77
84
|
|
|
78
85
|
### Error Tracing
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
- `exception.type` — Error class name
|
|
83
|
-
- `exception.message` — Error description
|
|
84
|
-
- `exception.stacktrace` — Full stack trace
|
|
85
|
-
|
|
86
|
-
Errors propagate up the span tree so the root `invoke_agent` span is marked as errored.
|
|
87
|
+
Agent-level errors are captured on the root `invoke_agent` span with `error.type` and error status. Errors from tool failures propagate up so the agent span is marked as errored.
|
|
87
88
|
|
|
88
89
|
## Configuration
|
|
89
90
|
|
|
@@ -170,11 +171,11 @@ Connect OpenClaw traces to your backend services. When enabled, the plugin injec
|
|
|
170
171
|
This produces connected traces across services:
|
|
171
172
|
|
|
172
173
|
```
|
|
173
|
-
OpenClaw: invoke_agent
|
|
174
|
-
|-- execute_tool exec (curl POST /
|
|
175
|
-
|-- [Backend]
|
|
174
|
+
OpenClaw: invoke_agent my-agent
|
|
175
|
+
|-- execute_tool exec (curl POST /api/data)
|
|
176
|
+
|-- [Your Backend] POST /api/data
|
|
176
177
|
|-- database query
|
|
177
|
-
|--
|
|
178
|
+
|-- downstream service call
|
|
178
179
|
```
|
|
179
180
|
|
|
180
181
|
Your backend must support W3C trace context extraction (most frameworks do: FastAPI with Logfire, Express with OTEL, etc.).
|
|
@@ -188,12 +189,14 @@ openclaw-logfire/src/
|
|
|
188
189
|
otel.ts OTEL SDK initialization (Logfire OTLP)
|
|
189
190
|
hooks/
|
|
190
191
|
before-agent-start invoke_agent span creation
|
|
192
|
+
llm-input gen_ai.chat span creation (per LLM call)
|
|
193
|
+
llm-output LLM span close + token metrics + accumulation
|
|
191
194
|
before-tool-call execute_tool span + context propagation
|
|
192
|
-
tool-result-persist Tool span close +
|
|
193
|
-
agent-end Span close +
|
|
195
|
+
tool-result-persist Tool span close + result capture
|
|
196
|
+
agent-end Span close + cumulative tokens + metrics
|
|
194
197
|
message-received Channel attribution + inbound context
|
|
195
198
|
context/
|
|
196
|
-
span-store Session -> active spans (LIFO tool stack)
|
|
199
|
+
span-store Session -> active spans (LIFO tool stack, LLM spans)
|
|
197
200
|
propagation W3C traceparent inject/extract
|
|
198
201
|
metrics/
|
|
199
202
|
genai-metrics Token usage + operation duration histograms
|
|
@@ -206,12 +209,14 @@ openclaw-logfire/src/
|
|
|
206
209
|
| Hook | Purpose |
|
|
207
210
|
|------|---------|
|
|
208
211
|
| `before_agent_start` | Create root `invoke_agent` span |
|
|
212
|
+
| `llm_input` | Create `gen_ai.chat` child span per LLM call |
|
|
213
|
+
| `llm_output` | Close LLM span, record token usage metrics |
|
|
209
214
|
| `before_tool_call` | Create `execute_tool` child span |
|
|
210
|
-
| `tool_result_persist` | Close tool span, record
|
|
211
|
-
| `agent_end` | Close spans, emit metrics |
|
|
215
|
+
| `tool_result_persist` | Close tool span, record result size |
|
|
216
|
+
| `agent_end` | Close spans, set cumulative tokens, emit metrics |
|
|
212
217
|
| `message_received` | Enrich with channel info |
|
|
213
218
|
|
|
214
|
-
Requires OpenClaw >= 2026.2.1 (`before_tool_call`
|
|
219
|
+
Requires OpenClaw >= 2026.2.1 (`before_tool_call` and `llm_input`/`llm_output` hooks).
|
|
215
220
|
|
|
216
221
|
## Development
|
|
217
222
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"propagation.d.ts","sourceRoot":"","sources":["../../src/context/propagation.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAEH,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,mBAAmB,EAC1B,UAAU,EAAE,IAAI,EAChB,WAAW,EAAE,MAAM,EAAE,GACpB,IAAI,
|
|
1
|
+
{"version":3,"file":"propagation.d.ts","sourceRoot":"","sources":["../../src/context/propagation.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAEH,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,mBAAmB,EAC1B,UAAU,EAAE,IAAI,EAChB,WAAW,EAAE,MAAM,EAAE,GACpB,IAAI,CAuCN;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,WAAW,GAAG,IAAI,CAapB"}
|
|
@@ -15,15 +15,16 @@ import picomatch from 'picomatch';
|
|
|
15
15
|
* Only injects if the target URL matches one of the configured patterns.
|
|
16
16
|
*/
|
|
17
17
|
export function injectTraceContext(event, parentSpan, urlPatterns) {
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
18
|
+
const params = event.params;
|
|
19
|
+
if (!params)
|
|
20
20
|
return;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
// Extract command string from params (exec tool uses command/cmd keys)
|
|
22
|
+
const command = typeof params.command === 'string'
|
|
23
|
+
? params.command
|
|
24
|
+
: typeof params.cmd === 'string'
|
|
25
|
+
? params.cmd
|
|
26
|
+
: '';
|
|
27
|
+
if (!command)
|
|
27
28
|
return;
|
|
28
29
|
// Only inject into HTTP client commands
|
|
29
30
|
if (!isHttpCommand(command))
|
|
@@ -43,15 +44,12 @@ export function injectTraceContext(event, parentSpan, urlPatterns) {
|
|
|
43
44
|
if (carrier.tracestate) {
|
|
44
45
|
headerFlags += ` -H "tracestate: ${carrier.tracestate}"`;
|
|
45
46
|
}
|
|
46
|
-
// Mutate the event's
|
|
47
|
-
if (typeof
|
|
48
|
-
|
|
47
|
+
// Mutate the event's params to include trace headers
|
|
48
|
+
if (typeof params.command === 'string') {
|
|
49
|
+
params.command = params.command + headerFlags;
|
|
49
50
|
}
|
|
50
|
-
else if (typeof
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
else if (typeof args.cmd === 'string') {
|
|
54
|
-
args.cmd += headerFlags;
|
|
51
|
+
else if (typeof params.cmd === 'string') {
|
|
52
|
+
params.cmd = params.cmd + headerFlags;
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
55
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"propagation.js","sourceRoot":"","sources":["../../src/context/propagation.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B;;;;;;GAMG;AAEH,OAAO,EACL,OAAO,EACP,WAAW,EACX,KAAK,GAGN,MAAM,oBAAoB,CAAC;AAC5B,OAAO,SAAS,MAAM,WAAW,CAAC;AAGlC;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAA0B,EAC1B,UAAgB,EAChB,WAAqB;IAErB,MAAM,
|
|
1
|
+
{"version":3,"file":"propagation.js","sourceRoot":"","sources":["../../src/context/propagation.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,12 +13,34 @@ export interface ToolSpanEntry {
|
|
|
13
13
|
callId: string;
|
|
14
14
|
startTime: number;
|
|
15
15
|
}
|
|
16
|
+
export interface LlmSpanEntry {
|
|
17
|
+
span: Span;
|
|
18
|
+
ctx: Context;
|
|
19
|
+
runId: string;
|
|
20
|
+
provider: string;
|
|
21
|
+
model: string;
|
|
22
|
+
startTime: number;
|
|
23
|
+
}
|
|
24
|
+
export interface TokenAccumulator {
|
|
25
|
+
input: number;
|
|
26
|
+
output: number;
|
|
27
|
+
cacheRead: number;
|
|
28
|
+
cacheWrite: number;
|
|
29
|
+
}
|
|
16
30
|
export interface SessionSpanContext {
|
|
17
31
|
/** Root span: invoke_agent */
|
|
18
32
|
agentSpan: Span;
|
|
19
33
|
agentCtx: Context;
|
|
20
34
|
/** Tool call stack (LIFO for correct nesting) */
|
|
21
35
|
toolStack: ToolSpanEntry[];
|
|
36
|
+
/** Pending LLM call spans indexed by runId */
|
|
37
|
+
llmSpans: Map<string, LlmSpanEntry>;
|
|
38
|
+
/** Accumulated token usage across all LLM calls */
|
|
39
|
+
tokens: TokenAccumulator;
|
|
40
|
+
/** Last known model (set by llm_input/llm_output hooks) */
|
|
41
|
+
model?: string;
|
|
42
|
+
/** Last known provider (set by llm_input/llm_output hooks) */
|
|
43
|
+
provider?: string;
|
|
22
44
|
/** Monotonic tool call counter for sequencing */
|
|
23
45
|
toolSequence: number;
|
|
24
46
|
/** Whether any tool errored (propagated to agent span) */
|
|
@@ -37,6 +59,12 @@ declare class SpanStore {
|
|
|
37
59
|
popTool(sessionKey: string): ToolSpanEntry | undefined;
|
|
38
60
|
/** Peek at the top of the tool stack without removing. */
|
|
39
61
|
peekTool(sessionKey: string): ToolSpanEntry | undefined;
|
|
62
|
+
/** Store a pending LLM call span. */
|
|
63
|
+
setLlmSpan(sessionKey: string, runId: string, entry: LlmSpanEntry): void;
|
|
64
|
+
/** Retrieve a pending LLM call span by runId. */
|
|
65
|
+
getLlmSpan(sessionKey: string, runId: string): LlmSpanEntry | undefined;
|
|
66
|
+
/** Remove and return an LLM call span. */
|
|
67
|
+
deleteLlmSpan(sessionKey: string, runId: string): LlmSpanEntry | undefined;
|
|
40
68
|
get size(): number;
|
|
41
69
|
/** End orphaned spans and remove stale sessions. */
|
|
42
70
|
private cleanup;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"span-store.d.ts","sourceRoot":"","sources":["../../src/context/span-store.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAElB,iDAAiD;IACjD,SAAS,EAAE,aAAa,EAAE,CAAC;IAE3B,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IAErB,0DAA0D;IAC1D,QAAQ,EAAE,OAAO,CAAC;IAElB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,cAAM,SAAS;IACb,OAAO,CAAC,QAAQ,CAAyC;IAEzD,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,GAAG,IAAI;IAKtD,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIvD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIhC,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAMxD,4CAA4C;IAC5C,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMtD,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMvD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,oDAAoD;IACpD,OAAO,CAAC,OAAO;
|
|
1
|
+
{"version":3,"file":"span-store.d.ts","sourceRoot":"","sources":["../../src/context/span-store.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAElB,iDAAiD;IACjD,SAAS,EAAE,aAAa,EAAE,CAAC;IAE3B,8CAA8C;IAC9C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEpC,mDAAmD;IACnD,MAAM,EAAE,gBAAgB,CAAC;IAEzB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IAErB,0DAA0D;IAC1D,QAAQ,EAAE,OAAO,CAAC;IAElB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,cAAM,SAAS;IACb,OAAO,CAAC,QAAQ,CAAyC;IAEzD,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,GAAG,IAAI;IAKtD,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIvD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIhC,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAMxD,4CAA4C;IAC5C,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMtD,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMvD,qCAAqC;IACrC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAMxE,iDAAiD;IACjD,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIvE,0CAA0C;IAC1C,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAQ1E,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,oDAAoD;IACpD,OAAO,CAAC,OAAO;CAgBhB;AAED,eAAO,MAAM,SAAS,WAAkB,CAAC"}
|
|
@@ -41,6 +41,27 @@ class SpanStore {
|
|
|
41
41
|
return undefined;
|
|
42
42
|
return session.toolStack[session.toolStack.length - 1];
|
|
43
43
|
}
|
|
44
|
+
/** Store a pending LLM call span. */
|
|
45
|
+
setLlmSpan(sessionKey, runId, entry) {
|
|
46
|
+
const session = this.sessions.get(sessionKey);
|
|
47
|
+
if (!session)
|
|
48
|
+
return;
|
|
49
|
+
session.llmSpans.set(runId, entry);
|
|
50
|
+
}
|
|
51
|
+
/** Retrieve a pending LLM call span by runId. */
|
|
52
|
+
getLlmSpan(sessionKey, runId) {
|
|
53
|
+
return this.sessions.get(sessionKey)?.llmSpans.get(runId);
|
|
54
|
+
}
|
|
55
|
+
/** Remove and return an LLM call span. */
|
|
56
|
+
deleteLlmSpan(sessionKey, runId) {
|
|
57
|
+
const session = this.sessions.get(sessionKey);
|
|
58
|
+
if (!session)
|
|
59
|
+
return undefined;
|
|
60
|
+
const entry = session.llmSpans.get(runId);
|
|
61
|
+
if (entry)
|
|
62
|
+
session.llmSpans.delete(runId);
|
|
63
|
+
return entry;
|
|
64
|
+
}
|
|
44
65
|
get size() {
|
|
45
66
|
return this.sessions.size;
|
|
46
67
|
}
|
|
@@ -49,9 +70,12 @@ class SpanStore {
|
|
|
49
70
|
const now = Date.now();
|
|
50
71
|
for (const [key, session] of this.sessions) {
|
|
51
72
|
if (now - session.startTime > MAX_AGE_MS) {
|
|
52
|
-
//
|
|
53
|
-
for (
|
|
54
|
-
|
|
73
|
+
// Close children before parent — reverse order (LIFO)
|
|
74
|
+
for (let i = session.toolStack.length - 1; i >= 0; i--) {
|
|
75
|
+
session.toolStack[i].span.end();
|
|
76
|
+
}
|
|
77
|
+
for (const llm of [...session.llmSpans.values()].reverse()) {
|
|
78
|
+
llm.span.end();
|
|
55
79
|
}
|
|
56
80
|
session.agentSpan.end();
|
|
57
81
|
this.sessions.delete(key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"span-store.js","sourceRoot":"","sources":["../../src/context/span-store.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"span-store.js","sourceRoot":"","sources":["../../src/context/span-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,22 +5,13 @@
|
|
|
5
5
|
* emits metrics, and logs the Logfire trace link.
|
|
6
6
|
*/
|
|
7
7
|
import type { LogfirePluginConfig } from '../config.js';
|
|
8
|
+
import type { AgentContext } from './before-agent-start.js';
|
|
9
|
+
/** OpenClaw agent_end event payload. */
|
|
8
10
|
export interface AgentEndEvent {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
model?: string;
|
|
14
|
-
};
|
|
15
|
-
/** Token usage reported by OpenClaw (structure may vary). */
|
|
16
|
-
usage?: {
|
|
17
|
-
inputTokens?: number;
|
|
18
|
-
outputTokens?: number;
|
|
19
|
-
totalTokens?: number;
|
|
20
|
-
model?: string;
|
|
21
|
-
cost?: number;
|
|
22
|
-
};
|
|
23
|
-
error?: unknown;
|
|
11
|
+
messages: unknown[];
|
|
12
|
+
success: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
durationMs?: number;
|
|
24
15
|
}
|
|
25
16
|
/** Logger interface — matches OpenClaw plugin api.logger shape. */
|
|
26
17
|
export interface Logger {
|
|
@@ -29,5 +20,5 @@ export interface Logger {
|
|
|
29
20
|
warn(msg: string): void;
|
|
30
21
|
error(msg: string): void;
|
|
31
22
|
}
|
|
32
|
-
export declare function handleAgentEnd(event: AgentEndEvent, config: LogfirePluginConfig, logger: Logger): void;
|
|
23
|
+
export declare function handleAgentEnd(event: AgentEndEvent, ctx: AgentContext, config: LogfirePluginConfig, logger: Logger): void;
|
|
33
24
|
//# sourceMappingURL=agent-end.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-end.d.ts","sourceRoot":"","sources":["../../src/hooks/agent-end.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-end.d.ts","sourceRoot":"","sources":["../../src/hooks/agent-end.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,mEAAmE;AACnE,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,MAAM,GACb,IAAI,CAwHN"}
|
package/dist/hooks/agent-end.js
CHANGED
|
@@ -8,48 +8,80 @@
|
|
|
8
8
|
import { SpanStatusCode } from '@opentelemetry/api';
|
|
9
9
|
import { spanStore } from '../context/span-store.js';
|
|
10
10
|
import { buildLogfireTraceUrl } from '../trace-link.js';
|
|
11
|
-
import {
|
|
12
|
-
import { extractWorkspaceName } from '../util.js';
|
|
13
|
-
export function handleAgentEnd(event, config, logger) {
|
|
14
|
-
const
|
|
11
|
+
import { recordOperationDuration } from '../metrics/genai-metrics.js';
|
|
12
|
+
import { extractWorkspaceName, extractErrorDetails } from '../util.js';
|
|
13
|
+
export function handleAgentEnd(event, ctx, config, logger) {
|
|
14
|
+
const sessionKey = typeof ctx.sessionKey === 'string' && ctx.sessionKey.length > 0
|
|
15
|
+
? ctx.sessionKey
|
|
16
|
+
: typeof ctx.sessionId === 'string' && ctx.sessionId.length > 0
|
|
17
|
+
? ctx.sessionId
|
|
18
|
+
: undefined;
|
|
19
|
+
if (!sessionKey)
|
|
20
|
+
return;
|
|
21
|
+
const session = spanStore.get(sessionKey);
|
|
15
22
|
if (!session)
|
|
16
23
|
return;
|
|
17
|
-
const durationMs =
|
|
24
|
+
const durationMs = typeof event.durationMs === 'number' && Number.isFinite(event.durationMs)
|
|
25
|
+
? event.durationMs
|
|
26
|
+
: Date.now() - session.startTime;
|
|
18
27
|
const durationS = durationMs / 1000;
|
|
19
|
-
const agentName =
|
|
20
|
-
|
|
28
|
+
const agentName = typeof ctx.agentId === 'string' && ctx.agentId.length > 0
|
|
29
|
+
? ctx.agentId
|
|
30
|
+
: 'agent';
|
|
31
|
+
const workspace = extractWorkspaceName(typeof ctx.workspaceDir === 'string' ? ctx.workspaceDir : undefined);
|
|
21
32
|
// Close any remaining tool spans (shouldn't happen but safety net)
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
// Reverse order: close children before parent (LIFO)
|
|
34
|
+
for (let i = session.toolStack.length - 1; i >= 0; i--) {
|
|
35
|
+
session.toolStack[i].span.end();
|
|
24
36
|
}
|
|
25
|
-
//
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
if (usage.inputTokens !== undefined) {
|
|
29
|
-
session.agentSpan.setAttribute('gen_ai.usage.input_tokens', usage.inputTokens);
|
|
30
|
-
}
|
|
31
|
-
if (usage.outputTokens !== undefined) {
|
|
32
|
-
session.agentSpan.setAttribute('gen_ai.usage.output_tokens', usage.outputTokens);
|
|
33
|
-
}
|
|
34
|
-
if (usage.model) {
|
|
35
|
-
session.agentSpan.setAttribute('gen_ai.response.model', usage.model);
|
|
36
|
-
}
|
|
37
|
+
// Close any pending LLM spans (aborted mid-call)
|
|
38
|
+
for (const llm of [...session.llmSpans.values()].reverse()) {
|
|
39
|
+
llm.span.end();
|
|
37
40
|
}
|
|
38
41
|
// Duration and tool count
|
|
39
42
|
session.agentSpan.setAttribute('openclaw.request.duration_ms', durationMs);
|
|
40
43
|
session.agentSpan.setAttribute('openclaw.request.tool_count', session.toolSequence);
|
|
44
|
+
// Cumulative token usage from llm_output hooks
|
|
45
|
+
const { tokens } = session;
|
|
46
|
+
if (tokens.input > 0 || tokens.output > 0) {
|
|
47
|
+
session.agentSpan.setAttribute('gen_ai.usage.input_tokens', tokens.input);
|
|
48
|
+
session.agentSpan.setAttribute('gen_ai.usage.output_tokens', tokens.output);
|
|
49
|
+
if (tokens.cacheRead > 0) {
|
|
50
|
+
session.agentSpan.setAttribute('openclaw.usage.cache_read_tokens', tokens.cacheRead);
|
|
51
|
+
}
|
|
52
|
+
if (tokens.cacheWrite > 0) {
|
|
53
|
+
session.agentSpan.setAttribute('openclaw.usage.cache_write_tokens', tokens.cacheWrite);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Model/provider from LLM hooks (last seen values)
|
|
57
|
+
if (session.model) {
|
|
58
|
+
session.agentSpan.setAttribute('gen_ai.request.model', session.model);
|
|
59
|
+
session.agentSpan.setAttribute('gen_ai.response.model', session.model);
|
|
60
|
+
}
|
|
61
|
+
if (session.provider) {
|
|
62
|
+
session.agentSpan.setAttribute('gen_ai.provider.name', session.provider);
|
|
63
|
+
}
|
|
41
64
|
// Error status
|
|
42
|
-
if (event.error || session.hasError) {
|
|
43
|
-
const errorType = event.error
|
|
44
|
-
?
|
|
65
|
+
if (event.error || !event.success || session.hasError) {
|
|
66
|
+
const errorType = event.error
|
|
67
|
+
? 'AgentError'
|
|
45
68
|
: session.hasError
|
|
46
69
|
? 'ToolError'
|
|
47
70
|
: 'Error';
|
|
71
|
+
const errorMsg = event.error || 'Agent invocation failed';
|
|
48
72
|
session.agentSpan.setAttribute('error.type', errorType);
|
|
49
73
|
session.agentSpan.setStatus({
|
|
50
74
|
code: SpanStatusCode.ERROR,
|
|
51
|
-
message:
|
|
75
|
+
message: errorMsg,
|
|
52
76
|
});
|
|
77
|
+
// Record structured exception per OTEL semantic conventions.
|
|
78
|
+
// recordException() expects Error | string — construct a real Error instance.
|
|
79
|
+
const errDetails = extractErrorDetails(event.error ?? errorMsg);
|
|
80
|
+
const exception = new Error(errDetails.message);
|
|
81
|
+
exception.name = errDetails.type;
|
|
82
|
+
if (errDetails.stacktrace)
|
|
83
|
+
exception.stack = errDetails.stacktrace;
|
|
84
|
+
session.agentSpan.recordException(exception);
|
|
53
85
|
}
|
|
54
86
|
else {
|
|
55
87
|
session.agentSpan.setStatus({ code: SpanStatusCode.OK });
|
|
@@ -61,23 +93,15 @@ export function handleAgentEnd(event, config, logger) {
|
|
|
61
93
|
const metricAttrs = {
|
|
62
94
|
agentName,
|
|
63
95
|
workspace,
|
|
64
|
-
providerName: config.providerName || 'unknown',
|
|
65
|
-
requestModel:
|
|
66
|
-
responseModel:
|
|
67
|
-
hasError: !!(event.error || session.hasError),
|
|
96
|
+
providerName: session.provider || config.providerName || 'unknown',
|
|
97
|
+
requestModel: session.model || '',
|
|
98
|
+
responseModel: session.model || '',
|
|
99
|
+
hasError: !!(event.error || !event.success || session.hasError),
|
|
68
100
|
errorType: event.error
|
|
69
|
-
?
|
|
70
|
-
? event.error.constructor.name
|
|
71
|
-
: 'Error'
|
|
101
|
+
? 'AgentError'
|
|
72
102
|
: undefined,
|
|
73
103
|
};
|
|
74
104
|
recordOperationDuration(durationS, metricAttrs);
|
|
75
|
-
if (usage?.inputTokens !== undefined) {
|
|
76
|
-
recordTokenUsage(usage.inputTokens, 'input', metricAttrs);
|
|
77
|
-
}
|
|
78
|
-
if (usage?.outputTokens !== undefined) {
|
|
79
|
-
recordTokenUsage(usage.outputTokens, 'output', metricAttrs);
|
|
80
|
-
}
|
|
81
105
|
}
|
|
82
106
|
// Log trace link
|
|
83
107
|
if (config.enableTraceLinks && config.projectUrl) {
|
|
@@ -86,6 +110,6 @@ export function handleAgentEnd(event, config, logger) {
|
|
|
86
110
|
logger.info(`Logfire trace: ${url}`);
|
|
87
111
|
}
|
|
88
112
|
// Cleanup
|
|
89
|
-
spanStore.delete(
|
|
113
|
+
spanStore.delete(sessionKey);
|
|
90
114
|
}
|
|
91
115
|
//# sourceMappingURL=agent-end.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-end.js","sourceRoot":"","sources":["../../src/hooks/agent-end.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"agent-end.js","sourceRoot":"","sources":["../../src/hooks/agent-end.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
* in agent-end.ts.
|
|
7
7
|
*/
|
|
8
8
|
import type { LogfirePluginConfig } from '../config.js';
|
|
9
|
-
/**
|
|
9
|
+
/** OpenClaw before_agent_start event payload. */
|
|
10
10
|
export interface BeforeAgentStartEvent {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
agentId?: string;
|
|
14
|
-
workspaceDir?: string;
|
|
15
|
-
commandSource?: string;
|
|
16
|
-
senderId?: string;
|
|
17
|
-
model?: string;
|
|
18
|
-
messages?: unknown[];
|
|
19
|
-
};
|
|
11
|
+
prompt: string;
|
|
12
|
+
messages?: unknown[];
|
|
20
13
|
}
|
|
21
|
-
|
|
14
|
+
/** OpenClaw agent lifecycle hook context (2nd argument). */
|
|
15
|
+
export interface AgentContext {
|
|
16
|
+
agentId?: string;
|
|
17
|
+
sessionKey?: string;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
workspaceDir?: string;
|
|
20
|
+
messageProvider?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function handleBeforeAgentStart(_event: BeforeAgentStartEvent, ctx: AgentContext, config: LogfirePluginConfig): void;
|
|
22
23
|
//# sourceMappingURL=before-agent-start.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"before-agent-start.d.ts","sourceRoot":"","sources":["../../src/hooks/before-agent-start.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,
|
|
1
|
+
{"version":3,"file":"before-agent-start.d.ts","sourceRoot":"","sources":["../../src/hooks/before-agent-start.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,iDAAiD;AACjD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,qBAAqB,EAC7B,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,mBAAmB,GAC1B,IAAI,CAgDN"}
|