@poncho-ai/harness 0.59.9 → 0.59.10

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.59.9 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.59.10 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,9 +8,9 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 558.75 KB
12
11
  ESM dist/isolate-F2PPSUL6.js 53.82 KB
13
- ESM ⚡️ Build success in 233ms
12
+ ESM dist/index.js 559.89 KB
13
+ ESM ⚡️ Build success in 238ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 7974ms
15
+ DTS ⚡️ Build success in 7368ms
16
16
  DTS dist/index.d.ts 102.06 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.59.10
4
+
5
+ ### Patch Changes
6
+
7
+ - [`fad3918`](https://github.com/cesr/poncho-ai/commit/fad3918302114f76a29080cf28e9c003c61ef0d9) Thanks [@cesr](https://github.com/cesr)! - Stamp `session.id` / `user.id` on EVERY span, not just the invoke_agent
8
+ root. Observability backends resolve a span's identity from its own
9
+ attributes — Latitude's console session/conversation views key on the LLM
10
+ generation spans, so root-only attributes grouped the API-level trace but
11
+ left the console showing one session per turn and no user. The identity now
12
+ rides the OTel Context and an IdentityAttributeSpanProcessor injects it
13
+ into every descendant span (LLM steps, tool executions) at start.
14
+
3
15
  ## 0.59.9
4
16
 
5
17
  ### Patch Changes
package/dist/index.js CHANGED
@@ -8745,7 +8745,7 @@ var createSubagentTools = (manager) => [
8745
8745
  ];
8746
8746
 
8747
8747
  // src/harness.ts
8748
- import { trace, context as otelContext, SpanStatusCode, SpanKind, diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
8748
+ import { trace, context as otelContext, createContextKey, SpanStatusCode, SpanKind, diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
8749
8749
  import { NodeTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
8750
8750
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
8751
8751
 
@@ -8928,6 +8928,28 @@ var telemetryLog2 = createLogger7("telemetry");
8928
8928
  var costLog = createLogger7("cost");
8929
8929
  var mcpLog2 = createLogger7("mcp");
8930
8930
  var modelLog = createLogger7("model");
8931
+ var TELEMETRY_SESSION_ID_KEY = createContextKey("poncho.telemetry.session_id");
8932
+ var TELEMETRY_USER_ID_KEY = createContextKey("poncho.telemetry.user_id");
8933
+ var IdentityAttributeSpanProcessor = class {
8934
+ onStart(span, parentContext) {
8935
+ const sessionId = parentContext.getValue(TELEMETRY_SESSION_ID_KEY);
8936
+ if (typeof sessionId === "string" && sessionId) {
8937
+ span.setAttribute("session.id", sessionId);
8938
+ }
8939
+ const userId = parentContext.getValue(TELEMETRY_USER_ID_KEY);
8940
+ if (typeof userId === "string" && userId) {
8941
+ span.setAttribute("user.id", userId);
8942
+ }
8943
+ }
8944
+ onEnd() {
8945
+ }
8946
+ forceFlush() {
8947
+ return Promise.resolve();
8948
+ }
8949
+ shutdown() {
8950
+ return Promise.resolve();
8951
+ }
8952
+ };
8931
8953
  function formatOtlpError(err) {
8932
8954
  if (!(err instanceof Error)) return String(err);
8933
8955
  const parts = [];
@@ -10339,7 +10361,9 @@ var AgentHarness = class _AgentHarness {
10339
10361
  const processor = new BatchSpanProcessor(exporter);
10340
10362
  this.otlpSpanProcessor = processor;
10341
10363
  const provider2 = new NodeTracerProvider({
10342
- spanProcessors: [processor]
10364
+ // Identity injector FIRST so every span (root, LLM steps, tool
10365
+ // executions) carries session.id/user.id before batching/export.
10366
+ spanProcessors: [new IdentityAttributeSpanProcessor(), processor]
10343
10367
  });
10344
10368
  provider2.register();
10345
10369
  this.otlpTracerProvider = provider2;
@@ -10506,7 +10530,13 @@ var AgentHarness = class _AgentHarness {
10506
10530
  ...input.tenantId ? { "tenant.id": input.tenantId } : {}
10507
10531
  }
10508
10532
  });
10509
- const spanContext = trace.setSpan(otelContext.active(), rootSpan);
10533
+ let spanContext = trace.setSpan(otelContext.active(), rootSpan);
10534
+ if (input.conversationId) {
10535
+ spanContext = spanContext.setValue(TELEMETRY_SESSION_ID_KEY, input.conversationId);
10536
+ }
10537
+ if (this.telemetryUserId) {
10538
+ spanContext = spanContext.setValue(TELEMETRY_USER_ID_KEY, this.telemetryUserId);
10539
+ }
10510
10540
  try {
10511
10541
  const gen = this.run(input);
10512
10542
  let next;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.59.9",
3
+ "version": "0.59.10",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
package/src/harness.ts CHANGED
@@ -67,9 +67,41 @@ import { createSkillTools, normalizeScriptPolicyPath } from "./skill-tools.js";
67
67
  import { createSearchTools } from "./search-tools.js";
68
68
  import { createSubagentTools } from "./subagent-tools.js";
69
69
  import type { SubagentManager } from "./subagent-manager.js";
70
- import { trace, context as otelContext, SpanStatusCode, SpanKind, diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
70
+ import { trace, context as otelContext, createContextKey, type Context as OtelContextType, SpanStatusCode, SpanKind, diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
71
+ import type { Span as OtelSdkSpan, SpanProcessor } from "@opentelemetry/sdk-trace-node";
71
72
  import { NodeTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
72
73
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
74
+
75
+ // ── Telemetry identity propagation ──────────────────────────────────────────
76
+ // Observability backends (Latitude) resolve a span's session/user from the
77
+ // span's OWN attributes — the console's session & conversation views key on
78
+ // the LLM generation spans, not the root span. So stamping `session.id` /
79
+ // `user.id` only on the invoke_agent root groups the API-level trace but
80
+ // leaves the console treating every turn as its own session. The fix is the
81
+ // same one vendor SDKs use: carry the identity in the OTel Context and have
82
+ // a SpanProcessor stamp it onto EVERY span at start.
83
+ const TELEMETRY_SESSION_ID_KEY = createContextKey("poncho.telemetry.session_id");
84
+ const TELEMETRY_USER_ID_KEY = createContextKey("poncho.telemetry.user_id");
85
+
86
+ class IdentityAttributeSpanProcessor implements SpanProcessor {
87
+ onStart(span: OtelSdkSpan, parentContext: OtelContextType): void {
88
+ const sessionId = parentContext.getValue(TELEMETRY_SESSION_ID_KEY);
89
+ if (typeof sessionId === "string" && sessionId) {
90
+ span.setAttribute("session.id", sessionId);
91
+ }
92
+ const userId = parentContext.getValue(TELEMETRY_USER_ID_KEY);
93
+ if (typeof userId === "string" && userId) {
94
+ span.setAttribute("user.id", userId);
95
+ }
96
+ }
97
+ onEnd(): void {}
98
+ forceFlush(): Promise<void> {
99
+ return Promise.resolve();
100
+ }
101
+ shutdown(): Promise<void> {
102
+ return Promise.resolve();
103
+ }
104
+ }
73
105
  import { normalizeOtlp } from "./telemetry.js";
74
106
 
75
107
  /** Extract useful details from OTLPExporterError (has .code + .data) or plain Error. */
@@ -1883,7 +1915,9 @@ export class AgentHarness {
1883
1915
  const processor = new BatchSpanProcessor(exporter);
1884
1916
  this.otlpSpanProcessor = processor;
1885
1917
  const provider = new NodeTracerProvider({
1886
- spanProcessors: [processor],
1918
+ // Identity injector FIRST so every span (root, LLM steps, tool
1919
+ // executions) carries session.id/user.id before batching/export.
1920
+ spanProcessors: [new IdentityAttributeSpanProcessor(), processor],
1887
1921
  });
1888
1922
  provider.register();
1889
1923
  this.otlpTracerProvider = provider;
@@ -2074,7 +2108,15 @@ export class AgentHarness {
2074
2108
  },
2075
2109
  });
2076
2110
 
2077
- const spanContext = trace.setSpan(otelContext.active(), rootSpan);
2111
+ let spanContext = trace.setSpan(otelContext.active(), rootSpan);
2112
+ // Identity rides the context so IdentityAttributeSpanProcessor stamps
2113
+ // session.id/user.id on every descendant span (see processor docs).
2114
+ if (input.conversationId) {
2115
+ spanContext = spanContext.setValue(TELEMETRY_SESSION_ID_KEY, input.conversationId);
2116
+ }
2117
+ if (this.telemetryUserId) {
2118
+ spanContext = spanContext.setValue(TELEMETRY_USER_ID_KEY, this.telemetryUserId);
2119
+ }
2078
2120
 
2079
2121
  try {
2080
2122
  const gen = this.run(input);