@poncho-ai/harness 0.59.7 → 0.59.9

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.7 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.59.9 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
11
12
  ESM dist/isolate-F2PPSUL6.js 53.82 KB
12
- ESM dist/index.js 558.06 KB
13
- ESM ⚡️ Build success in 257ms
13
+ ESM ⚡️ Build success in 233ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 7680ms
16
- DTS dist/index.d.ts 101.66 KB
15
+ DTS ⚡️ Build success in 7974ms
16
+ DTS dist/index.d.ts 102.06 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.59.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [`eb9600a`](https://github.com/cesr/poncho-ai/commit/eb9600a111cf74968689f8b33835d8b58c64e375) Thanks [@cesr](https://github.com/cesr)! - Root trace spans now carry `session.id` (= conversationId) and `user.id`
8
+ (new `config.telemetry.userId`) alongside the existing
9
+ `gen_ai.conversation.id` — the attributes observability backends
10
+ (Latitude) key session grouping and user filtering on.
11
+
12
+ ## 0.59.8
13
+
14
+ ### Patch Changes
15
+
16
+ - [`fb07954`](https://github.com/cesr/poncho-ai/commit/fb07954ee7edfa614bdd5ed27474f4d3be7c8f1f) Thanks [@cesr](https://github.com/cesr)! - Fix conversations.rename on Postgres: the JSONB `data` column usually
17
+ holds a JSON-encoded string scalar (update() binds JSON.stringify output),
18
+ so the 0.59.3 in-blob title update threw `cannot set path in scalar` and
19
+ every rename 500'd. The UPDATE now branches on jsonb_typeof(data) and
20
+ preserves each row's encoding (objects via jsonb_set; string scalars
21
+ unwrapped, set, and re-serialized).
22
+
3
23
  ## 0.59.7
4
24
 
5
25
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -756,6 +756,11 @@ interface PonchoConfig extends McpConfig {
756
756
  url: string;
757
757
  headers?: Record<string, string>;
758
758
  };
759
+ /** End-user identifier (e.g. an email) stamped as `user.id` on every
760
+ * root trace span — observability backends (Latitude) group and
761
+ * filter traces by it. Per-harness, so a harness-per-user consumer
762
+ * sets it once at construction. */
763
+ userId?: string;
759
764
  handler?: (event: unknown) => Promise<void> | void;
760
765
  };
761
766
  skills?: Record<string, Record<string, unknown>>;
@@ -1442,6 +1447,8 @@ declare class AgentHarness {
1442
1447
  private otlpSpanProcessor?;
1443
1448
  private otlpTracerProvider?;
1444
1449
  private hasOtlpExporter;
1450
+ /** End-user id (config.telemetry.userId) stamped as `user.id` on root spans. */
1451
+ private telemetryUserId?;
1445
1452
  private _browserSession?;
1446
1453
  private _browserMod?;
1447
1454
  private parsedAgent?;
package/dist/index.js CHANGED
@@ -3918,7 +3918,10 @@ var SqlStorageEngine = class {
3918
3918
  },
3919
3919
  rename: async (conversationId, title) => {
3920
3920
  const normalized = normalizeTitle2(title);
3921
- const dataExpr = this.dialect.tag === "sqlite" ? `json_set(data, '$.title', $2)` : `jsonb_set(data, '{title}', to_jsonb($2::text))`;
3921
+ const dataExpr = this.dialect.tag === "sqlite" ? `json_set(data, '$.title', $2)` : `CASE WHEN jsonb_typeof(data) = 'object'
3922
+ THEN jsonb_set(data, '{title}', to_jsonb($2::text))
3923
+ ELSE to_jsonb(jsonb_set((data #>> '{}')::jsonb, '{title}', to_jsonb($2::text))::text)
3924
+ END`;
3922
3925
  await this.executor.run(
3923
3926
  rewrite(
3924
3927
  `UPDATE conversations SET title = $1, data = ${dataExpr}, updated_at = $3 WHERE id = $4`,
@@ -9508,6 +9511,8 @@ var AgentHarness = class _AgentHarness {
9508
9511
  otlpSpanProcessor;
9509
9512
  otlpTracerProvider;
9510
9513
  hasOtlpExporter = false;
9514
+ /** End-user id (config.telemetry.userId) stamped as `user.id` on root spans. */
9515
+ telemetryUserId;
9511
9516
  _browserSession;
9512
9517
  _browserMod;
9513
9518
  parsedAgent;
@@ -10324,6 +10329,7 @@ var AgentHarness = class _AgentHarness {
10324
10329
  await this.refreshMcpTools("initialize");
10325
10330
  const telemetryEnabled = config?.telemetry?.enabled !== false;
10326
10331
  const otlpConfig = telemetryEnabled ? normalizeOtlp(config?.telemetry?.otlp) : void 0;
10332
+ this.telemetryUserId = config?.telemetry?.userId;
10327
10333
  if (otlpConfig) {
10328
10334
  diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.WARN);
10329
10335
  const exporter = new OTLPTraceExporter({
@@ -10489,7 +10495,14 @@ var AgentHarness = class _AgentHarness {
10489
10495
  kind: SpanKind.INTERNAL,
10490
10496
  attributes: {
10491
10497
  "gen_ai.operation.name": "invoke_agent",
10492
- ...input.conversationId ? { "gen_ai.conversation.id": input.conversationId } : {},
10498
+ // `session.id` / `user.id` are the attributes observability
10499
+ // backends (Latitude) key session grouping and user filtering on.
10500
+ // gen_ai.conversation.id is kept for the GenAI semantic convention.
10501
+ ...input.conversationId ? {
10502
+ "gen_ai.conversation.id": input.conversationId,
10503
+ "session.id": input.conversationId
10504
+ } : {},
10505
+ ...this.telemetryUserId ? { "user.id": this.telemetryUserId } : {},
10493
10506
  ...input.tenantId ? { "tenant.id": input.tenantId } : {}
10494
10507
  }
10495
10508
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.59.7",
3
+ "version": "0.59.9",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
package/src/config.ts CHANGED
@@ -231,6 +231,11 @@ export interface PonchoConfig extends McpConfig {
231
231
  url: string;
232
232
  headers?: Record<string, string>;
233
233
  };
234
+ /** End-user identifier (e.g. an email) stamped as `user.id` on every
235
+ * root trace span — observability backends (Latitude) group and
236
+ * filter traces by it. Per-harness, so a harness-per-user consumer
237
+ * sets it once at construction. */
238
+ userId?: string;
234
239
  handler?: (event: unknown) => Promise<void> | void;
235
240
  };
236
241
  skills?: Record<string, Record<string, unknown>>;
package/src/harness.ts CHANGED
@@ -881,6 +881,8 @@ export class AgentHarness {
881
881
  private otlpSpanProcessor?: BatchSpanProcessor;
882
882
  private otlpTracerProvider?: NodeTracerProvider;
883
883
  private hasOtlpExporter = false;
884
+ /** End-user id (config.telemetry.userId) stamped as `user.id` on root spans. */
885
+ private telemetryUserId?: string;
884
886
  private _browserSession?: unknown;
885
887
  private _browserMod?: {
886
888
  createBrowserTools: (getSession: () => unknown, getConversationId?: () => string) => ToolDefinition[];
@@ -1871,6 +1873,7 @@ export class AgentHarness {
1871
1873
 
1872
1874
  const telemetryEnabled = config?.telemetry?.enabled !== false;
1873
1875
  const otlpConfig = telemetryEnabled ? normalizeOtlp(config?.telemetry?.otlp) : undefined;
1876
+ this.telemetryUserId = config?.telemetry?.userId;
1874
1877
  if (otlpConfig) {
1875
1878
  diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.WARN);
1876
1879
  const exporter = new OTLPTraceExporter({
@@ -2057,7 +2060,16 @@ export class AgentHarness {
2057
2060
  kind: SpanKind.INTERNAL,
2058
2061
  attributes: {
2059
2062
  "gen_ai.operation.name": "invoke_agent",
2060
- ...(input.conversationId ? { "gen_ai.conversation.id": input.conversationId } : {}),
2063
+ // `session.id` / `user.id` are the attributes observability
2064
+ // backends (Latitude) key session grouping and user filtering on.
2065
+ // gen_ai.conversation.id is kept for the GenAI semantic convention.
2066
+ ...(input.conversationId
2067
+ ? {
2068
+ "gen_ai.conversation.id": input.conversationId,
2069
+ "session.id": input.conversationId,
2070
+ }
2071
+ : {}),
2072
+ ...(this.telemetryUserId ? { "user.id": this.telemetryUserId } : {}),
2061
2073
  ...(input.tenantId ? { "tenant.id": input.tenantId } : {}),
2062
2074
  },
2063
2075
  });
@@ -571,9 +571,21 @@ export abstract class SqlStorageEngine implements StorageEngine {
571
571
  // Distinct placeholders for the two title occurrences: rewrite()
572
572
  // converts $N → ? positionally for sqlite, so reusing $1 would
573
573
  // desync the param array.
574
+ //
575
+ // Postgres: the JSONB column usually holds a JSON-encoded STRING
576
+ // scalar, not an object — update() binds `JSON.stringify(conv)` and
577
+ // the driver serializes that JS string as a JSON string. A bare
578
+ // jsonb_set on those rows throws `cannot set path in scalar`
579
+ // (observed in prod 2026-06-12: every rename 500'd). Branch on the
580
+ // stored shape and preserve each row's encoding: objects get a plain
581
+ // jsonb_set; string scalars get unwrapped (#>> '{}'), parsed, set,
582
+ // and re-serialized back to a string scalar.
574
583
  const dataExpr = this.dialect.tag === "sqlite"
575
584
  ? `json_set(data, '$.title', $2)`
576
- : `jsonb_set(data, '{title}', to_jsonb($2::text))`;
585
+ : `CASE WHEN jsonb_typeof(data) = 'object'
586
+ THEN jsonb_set(data, '{title}', to_jsonb($2::text))
587
+ ELSE to_jsonb(jsonb_set((data #>> '{}')::jsonb, '{title}', to_jsonb($2::text))::text)
588
+ END`;
577
589
  await this.executor.run(
578
590
  rewrite(
579
591
  `UPDATE conversations SET title = $1, data = ${dataExpr}, updated_at = $3 WHERE id = $4`,