@cat-factory/observability-langfuse 0.10.107 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,14 +8,23 @@ when wired into a facade every LLM call: container-agent calls (through the LLM
8
8
  agent): surfaces in Langfuse as a generation grouped under its run's trace, plus
9
9
  optional container tool spans.
10
10
 
11
- ## Why fetch-only
12
-
13
- The sink talks to Langfuse's public **ingestion API** (`POST /api/public/ingestion`,
14
- HTTP Basic auth, batched JSON events) using only the global `fetch` / `crypto` /
15
- `btoa`. It deliberately does **not** depend on the official `langfuse` Node SDK or any
16
- `@opentelemetry/*` package: those rely on Node-only APIs that are unavailable on the
17
- Cloudflare Worker runtime (workerd). Using the raw ingestion API keeps the sink
18
- byte-for-byte identical on both the Worker and Node facades.
11
+ ## What it is: the OTLP exporter, pointed at Langfuse
12
+
13
+ The sink is `@cat-factory/observability-otel`'s fetch-based OTLP/HTTP exporter with three
14
+ Langfuse-specific decisions in its constructor: the endpoint `{baseUrl}/api/public/otel`
15
+ (onto which the exporter appends `/v1/traces`), HTTP Basic auth over the key pair, and the
16
+ `x-langfuse-ingestion-version: 4` header that v4 needs for real-time ingestion. Metrics
17
+ are off, because Langfuse implements the traces signal only.
18
+
19
+ It used to be its own client speaking Langfuse's batch **ingestion API**
20
+ (`POST /api/public/ingestion`). That API is deprecated, sunsets on Langfuse Cloud on
21
+ **2026-11-16**, and the `trace-create` / `generation-create` / `span-create` events it sent
22
+ are already unsupported on the v4 data model. OTLP is the supported path and this repo
23
+ already spoke it.
24
+
25
+ Neither package depends on the official `langfuse` Node SDK or on any `@opentelemetry/*`
26
+ package: those rely on Node-only APIs unavailable on the Cloudflare Worker runtime
27
+ (workerd), which is what keeps the sink byte-for-byte identical on both facades.
19
28
 
20
29
  ## Behaviour
21
30
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { LlmGenerationEvent, LlmToolSpan, LlmToolSpanContext, LlmTraceSink, Logger } from '@cat-factory/kernel';
1
+ import type { Logger } from '@cat-factory/kernel';
2
+ import { OtelTraceSink } from '@cat-factory/observability-otel';
2
3
  export interface LangfuseSinkConfig {
3
4
  /** Langfuse public key (`pk-lf-…`). */
4
5
  publicKey: string;
@@ -6,20 +7,23 @@ export interface LangfuseSinkConfig {
6
7
  secretKey: string;
7
8
  /** Host of the Langfuse instance. Default: Langfuse Cloud (`https://cloud.langfuse.com`). */
8
9
  baseUrl?: string;
10
+ /** OTLP resource `service.name`, as it appears on the exported spans. */
11
+ serviceName?: string;
9
12
  /** Optional logger for swallowed errors. */
10
13
  logger?: Logger;
11
14
  /** Injectable fetch (tests); defaults to the global `fetch`. */
12
15
  fetchImpl?: typeof fetch;
13
16
  }
14
- export declare class LangfuseTraceSink implements LlmTraceSink {
15
- private readonly endpoint;
16
- private readonly authorization;
17
- private readonly logger?;
18
- private readonly fetchImpl;
17
+ /**
18
+ * The OTLP exporter, configured for a Langfuse project.
19
+ *
20
+ * A subclass rather than a factory returning the base type, because a facade composing several
21
+ * sinks has to be able to say WHICH destination it wired: `CompositeTraceSink` holds a list, and
22
+ * two members of the same class are indistinguishable to the wiring assertions that keep the
23
+ * facades symmetric.
24
+ */
25
+ export declare class LangfuseTraceSink extends OtelTraceSink {
19
26
  constructor(config: LangfuseSinkConfig);
20
- recordGeneration(event: LlmGenerationEvent): Promise<void>;
21
- recordToolSpans(context: LlmToolSpanContext, spans: LlmToolSpan[]): Promise<void>;
22
- private send;
23
27
  }
24
28
  /** Build a {@link LangfuseTraceSink}. Returns the opt-in sink wired into a facade. */
25
29
  export declare function createLangfuseSink(config: LangfuseSinkConfig): LangfuseTraceSink;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,MAAM,EACP,MAAM,qBAAqB,CAAA;AAkD5B,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAkBD,qBAAa,iBAAkB,YAAW,YAAY;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IAExC,YAAY,MAAM,EAAE,kBAAkB,EAMrC;IAEK,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0D/D;IAEK,eAAe,CAAC,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCtF;YAEa,IAAI;CA4BnB;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,iBAAiB,CAEhF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAuC/D,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAMD;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,aAAa;IAClD,YAAY,MAAM,EAAE,kBAAkB,EAarC;CACF;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,iBAAiB,CAEhF"}
package/dist/index.js CHANGED
@@ -1,192 +1,63 @@
1
- import { getErrorMessage } from '@cat-factory/kernel';
2
- // A fetch-based Langfuse trace sink. It speaks Langfuse's public **ingestion API**
3
- // (`POST /api/public/ingestion`, HTTP Basic auth = public:secret key, batched JSON
4
- // events) using only the global `fetch`/`crypto`/`btoa` — NO `langfuse` Node SDK and
5
- // NO `@opentelemetry/*`, both of which depend on Node-only APIs that are unavailable on
6
- // the Cloudflare Worker runtime (workerd). This keeps the sink byte-for-byte identical
7
- // across the Worker and Node facades, which is the whole reason it exists as its own
8
- // package: see `LlmTraceSink` in `@cat-factory/kernel`.
1
+ import { OtelTraceSink } from '@cat-factory/observability-otel';
2
+ // The opt-in Langfuse trace sink, which is now the OTLP exporter pointed at Langfuse.
9
3
  //
10
- // Observability must never break the product, so every method swallows its own errors
11
- // (logging at most a warning) and the caller additionally schedules the call off the
12
- // response path. A failed flush drops that batch; it never propagates.
4
+ // It used to be its own fetch client speaking Langfuse's ingestion API
5
+ // (`POST /api/public/ingestion`, batched `trace-create` / `generation-create` / `span-create`
6
+ // events). That API is deprecated and sunsets on Langfuse Cloud on 2026-11-16, and the three event
7
+ // types this sent are already unsupported on the v4 data model: "Trace, span, and generation events
8
+ // via the legacy batch ingestion API are not supported on the v4 data model". The supported path is
9
+ // OTLP, which this repo already speaks: `@cat-factory/observability-otel` hand-writes an OTLP/HTTP
10
+ // JSON exporter for exactly the same three shapes, so the migration retargets an encoder rather
11
+ // than writing one, and Langfuse becomes a DESTINATION instead of a second recording path.
13
12
  //
14
- // Each `recordGeneration` posts its own small ingestion batch rather than buffering
15
- // across calls. This is deliberate: the Worker runtime is stateless per request (there
16
- // is no durable cross-request buffer to flush, and a `waitUntil`-scheduled POST can't
17
- // outlive its request), so a per-call POST is the only shape that stays identical across
18
- // the Worker and Node facades. Tool spans, which the backend already accumulates per
19
- // poll, ARE sent as one batch. Langfuse's ingestion API is built for this volume.
13
+ // What differs from a plain collector, and it is only these three things:
14
+ // - the endpoint is `{base}/api/public/otel`, so the exporter's own `/v1/traces` append lands on
15
+ // Langfuse's documented signal path;
16
+ // - auth is HTTP Basic over `publicKey:secretKey`, the same credential pair as before;
17
+ // - `x-langfuse-ingestion-version: 4` is required for real-time ingestion on v4. Without it the
18
+ // data still arrives, up to ten minutes late, which is the kind of delay that reads as data
19
+ // loss to whoever is watching a run.
20
20
  //
21
- // IMPACT ANALYSIS why per-call POST is safe for the execution hot path:
22
- // - NOT on the hot path. The proxied feeder runs under `executionCtx.waitUntil`
23
- // (`LlmProxyController`), scheduled AFTER the container's chat-completion response
24
- // is returned (on Node `waitUntil` is a plain fire-and-forget); the inline feeder
25
- // (`InstrumentedModelProvider`) dispatches AFTER `generateText` resolves. Inside
26
- // `LlmObservabilityService.record` the POST is then dispatched detached (not
27
- // awaited), so even the `waitUntil` window never blocks on the Langfuse round trip.
28
- // The only synchronous cost added to any path is one object build + `JSON.stringify`
29
- // — microseconds, never the network call.
30
- // - NOT a source of execution brittleness. Every error is swallowed + logged, the
31
- // fetch is bounded by SEND_TIMEOUT_MS, and nothing in the run lifecycle reads the
32
- // sink's result a Langfuse outage / slowness / 4xx drops a batch and nothing else.
33
- // - The costs that DO exist are telemetry-side, not run-side: +1 detached subrequest
34
- // per proxy invocation (~2 of the Worker's 1000-subrequest budget), negligible
35
- // `waitUntil` CPU (I/O-bound, timeout-capped), and N calls ⇒ N POSTs — a very chatty
36
- // run could brush Langfuse ingestion rate limits and drop some batches, degrading
37
- // telemetry COMPLETENESS only, never the run. (Tool spans are batched per poll, so
38
- // they don't multiply.)
21
+ // METRICS ARE OFF because Langfuse implements the traces signal only. Posting `/v1/metrics` there
22
+ // would 404 once per generation, a per-call failure that says nothing about the deployment.
23
+ //
24
+ // The contract the two sinks share is unchanged and is documented on the exporter: observability
25
+ // must never break the product, so every method swallows its own errors (logging at most a
26
+ // warning), each POST is timeout-bounded, and a dropped batch is the worst case. No `langfuse` SDK
27
+ // and no `@opentelemetry/*`: both depend on Node-only APIs that are unavailable on workerd, which
28
+ // is why the fetch-based exporter exists at all.
29
+ //
30
+ // Read 2026-08-18: https://langfuse.com/docs/api, https://langfuse.com/docs/compatibility,
31
+ // https://langfuse.com/integrations/native/opentelemetry
32
+ /** Langfuse Cloud EU. The US, Japan and HIPAA clouds are the same shape on their own hosts. */
39
33
  const DEFAULT_BASE_URL = 'https://cloud.langfuse.com';
40
- /**
41
- * Hard ceiling on a single ingestion POST. Observability must never tie up the LLM
42
- * path: the proxied feeder records under the platform's `waitUntil` budget and the
43
- * inline feeder dispatches without awaiting, so a hung Langfuse endpoint must abort
44
- * rather than dangle. A dropped batch is the documented best-effort worst case.
45
- */
46
- const SEND_TIMEOUT_MS = 10_000;
47
- function iso(ms) {
48
- return new Date(ms).toISOString();
49
- }
34
+ /** Langfuse's OTLP path, onto which the exporter appends the `/v1/traces` signal segment. */
35
+ const OTEL_PATH = '/api/public/otel';
50
36
  function basicAuth(publicKey, secretKey) {
51
37
  return `Basic ${btoa(`${publicKey}:${secretKey}`)}`;
52
38
  }
53
- export class LangfuseTraceSink {
54
- endpoint;
55
- authorization;
56
- logger;
57
- fetchImpl;
39
+ /**
40
+ * The OTLP exporter, configured for a Langfuse project.
41
+ *
42
+ * A subclass rather than a factory returning the base type, because a facade composing several
43
+ * sinks has to be able to say WHICH destination it wired: `CompositeTraceSink` holds a list, and
44
+ * two members of the same class are indistinguishable to the wiring assertions that keep the
45
+ * facades symmetric.
46
+ */
47
+ export class LangfuseTraceSink extends OtelTraceSink {
58
48
  constructor(config) {
59
49
  const base = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
60
- this.endpoint = `${base}/api/public/ingestion`;
61
- this.authorization = basicAuth(config.publicKey, config.secretKey);
62
- this.logger = config.logger;
63
- this.fetchImpl = config.fetchImpl ?? fetch;
64
- }
65
- async recordGeneration(event) {
66
- // Group every call of a run under one trace (keyed by the execution id); inline
67
- // single-shot calls (no execution) become their own standalone trace.
68
- const traceId = event.executionId ?? crypto.randomUUID();
69
- const generation = {
70
- id: crypto.randomUUID(),
71
- traceId,
72
- name: event.agentKind,
73
- startTime: iso(event.startedAt),
74
- endTime: iso(event.endedAt),
75
- model: event.model,
76
- usage: {
77
- // Langfuse's `input` is the whole input side, so the three orthogonal classes are
78
- // summed back for it; the split rides the metadata below, where a cache-read-dominated
79
- // generation is still distinguishable from a fresh one.
80
- input: event.promptTokens + event.cacheReadTokens + event.cacheWriteTokens,
81
- output: event.completionTokens,
82
- total: event.totalTokens,
83
- unit: 'TOKENS',
84
- },
85
- level: event.ok ? 'DEFAULT' : 'ERROR',
86
- metadata: {
87
- provider: event.provider,
88
- agentKind: event.agentKind,
89
- finishReason: event.finishReason,
90
- freshInputTokens: event.promptTokens,
91
- cacheReadTokens: event.cacheReadTokens,
92
- cacheWriteTokens: event.cacheWriteTokens,
93
- workspaceId: event.workspaceId,
94
- },
95
- };
96
- // Prompt/response bodies are present only when prompt recording is on (the same
97
- // `LLM_RECORD_PROMPTS` switch the local store honours): omit empty bodies entirely.
98
- if (event.input)
99
- generation.input = event.input;
100
- if (event.output)
101
- generation.output = event.output;
102
- if (event.errorMessage)
103
- generation.statusMessage = event.errorMessage;
104
- await this.send([
105
- {
106
- id: crypto.randomUUID(),
107
- type: 'trace-create',
108
- timestamp: iso(event.endedAt),
109
- body: {
110
- id: traceId,
111
- // A run trace is upserted by every call it groups, so keep the trace body
112
- // stable across them: the per-call agent kind lives on each generation
113
- // (its `name` + metadata), NOT as a trace tag that the next call would clobber.
114
- name: event.executionId ? `run ${event.executionId}` : event.agentKind,
115
- metadata: { workspaceId: event.workspaceId },
116
- },
117
- },
118
- {
119
- id: crypto.randomUUID(),
120
- type: 'generation-create',
121
- timestamp: iso(event.endedAt),
122
- body: generation,
50
+ super({
51
+ endpoint: `${base}${OTEL_PATH}`,
52
+ exportMetrics: false,
53
+ headers: {
54
+ authorization: basicAuth(config.publicKey, config.secretKey),
55
+ 'x-langfuse-ingestion-version': '4',
123
56
  },
124
- ]);
125
- }
126
- async recordToolSpans(context, spans) {
127
- // Tool spans are only meaningful as children of a run's trace.
128
- if (!context.executionId || spans.length === 0)
129
- return;
130
- const traceId = context.executionId;
131
- const batch = spans.map((span) => ({
132
- id: crypto.randomUUID(),
133
- type: 'span-create',
134
- timestamp: iso(span.endedAt),
135
- body: {
136
- id: crypto.randomUUID(),
137
- traceId,
138
- name: span.tool,
139
- startTime: iso(span.startedAt),
140
- endTime: iso(span.endedAt),
141
- level: span.ok ? 'DEFAULT' : 'ERROR',
142
- // The call's arguments and result go in Langfuse's own input/output slots rather than
143
- // metadata, so the trajectory reads in the UI the way a generation's prompt does.
144
- // Present only when the double gate allowed capture (upstream blanks them otherwise).
145
- ...(span.args ? { input: span.args } : {}),
146
- ...(span.result ? { output: span.result } : {}),
147
- metadata: {
148
- agentKind: context.agentKind,
149
- // The ordinal a trajectory orders by: a tool loop routinely fires several calls inside
150
- // one millisecond, so start time alone cannot sequence them. The dispatch rides with
151
- // it because `seq` restarts at zero on each one, so a re-run's spans would otherwise
152
- // be indistinguishable from the first round's.
153
- ...(context.jobId ? { jobId: context.jobId } : {}),
154
- ...(span.seq !== undefined ? { seq: span.seq } : {}),
155
- ...(span.argsDropped ? { argsDroppedChars: span.argsDropped } : {}),
156
- ...(span.resultDropped ? { resultDroppedChars: span.resultDropped } : {}),
157
- },
158
- },
159
- }));
160
- await this.send(batch);
161
- }
162
- async send(batch) {
163
- try {
164
- const res = await this.fetchImpl(this.endpoint, {
165
- method: 'POST',
166
- headers: {
167
- 'content-type': 'application/json',
168
- authorization: this.authorization,
169
- },
170
- body: JSON.stringify({ batch }),
171
- // Bound the request so a hung endpoint can't tie up the caller's waitUntil
172
- // budget; an abort lands in the catch below and drops the batch (best-effort).
173
- signal: AbortSignal.timeout(SEND_TIMEOUT_MS),
174
- });
175
- // 207 = partial success (per-event errors in the body); anything else non-2xx is
176
- // a hard failure. Either way we only log — observability never breaks the caller.
177
- if (!res.ok && res.status !== 207) {
178
- this.logger?.warn('langfuse: ingestion rejected batch', {
179
- scope: 'langfuse',
180
- status: res.status,
181
- });
182
- }
183
- }
184
- catch (err) {
185
- this.logger?.warn('langfuse: failed to post ingestion batch', {
186
- scope: 'langfuse',
187
- err: getErrorMessage(err),
188
- });
189
- }
57
+ ...(config.serviceName ? { serviceName: config.serviceName } : {}),
58
+ ...(config.logger ? { logger: config.logger } : {}),
59
+ ...(config.fetchImpl ? { fetchImpl: config.fetchImpl } : {}),
60
+ });
190
61
  }
191
62
  }
192
63
  /** Build a {@link LangfuseTraceSink}. Returns the opt-in sink wired into a facade. */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAE/D,sFAAsF;AACtF,EAAE;AACF,uEAAuE;AACvE,8FAA8F;AAC9F,mGAAmG;AACnG,oGAAoG;AACpG,oGAAoG;AACpG,mGAAmG;AACnG,gGAAgG;AAChG,2FAA2F;AAC3F,EAAE;AACF,0EAA0E;AAC1E,mGAAmG;AACnG,yCAAyC;AACzC,yFAAyF;AACzF,kGAAkG;AAClG,gGAAgG;AAChG,yCAAyC;AACzC,EAAE;AACF,kGAAkG;AAClG,4FAA4F;AAC5F,EAAE;AACF,iGAAiG;AACjG,2FAA2F;AAC3F,mGAAmG;AACnG,kGAAkG;AAClG,iDAAiD;AACjD,EAAE;AACF,2FAA2F;AAC3F,yDAAyD;AAEzD,+FAA+F;AAC/F,MAAM,gBAAgB,GAAG,4BAA4B,CAAA;AAErD,6FAA6F;AAC7F,MAAM,SAAS,GAAG,kBAAkB,CAAA;AAiBpC,SAAS,SAAS,CAAC,SAAiB,EAAE,SAAiB;IACrD,OAAO,SAAS,IAAI,CAAC,GAAG,SAAS,IAAI,SAAS,EAAE,CAAC,EAAE,CAAA;AACrD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,aAAa;IAClD,YAAY,MAA0B;QACpC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACrE,KAAK,CAAC;YACJ,QAAQ,EAAE,GAAG,IAAI,GAAG,SAAS,EAAE;YAC/B,aAAa,EAAE,KAAK;YACpB,OAAO,EAAE;gBACP,aAAa,EAAE,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;gBAC5D,8BAA8B,EAAE,GAAG;aACpC;YACD,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7D,CAAC,CAAA;IACJ,CAAC;CACF;AAED,sFAAsF;AACtF,MAAM,UAAU,kBAAkB,CAAC,MAA0B;IAC3D,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAA;AACtC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cat-factory/observability-langfuse",
3
- "version": "0.10.107",
4
- "description": "Opt-in Langfuse trace sink for the Agent Architecture Board. A fetch-based LlmTraceSink that streams LLM generations (and container tool spans) to Langfuse's ingestion API — runs unchanged on both the Cloudflare Worker (workerd) and Node facades.",
3
+ "version": "0.11.0",
4
+ "description": "Opt-in Langfuse trace sink for the Agent Architecture Board. The workerd-safe OTLP/HTTP exporter pointed at Langfuse's OpenTelemetry endpoint, so LLM generations and container tool spans stream unchanged on both the Cloudflare Worker and Node facades.",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/kibertoad/cat-factory.git",
@@ -24,7 +24,8 @@
24
24
  "access": "public"
25
25
  },
26
26
  "dependencies": {
27
- "@cat-factory/kernel": "0.311.0"
27
+ "@cat-factory/kernel": "0.313.0",
28
+ "@cat-factory/observability-otel": "0.22.0"
28
29
  },
29
30
  "devDependencies": {
30
31
  "typescript": "7.0.2",