@nanobpm/nano-workforce 0.183.1 → 0.183.2

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.
@@ -11,6 +11,7 @@ import type { Frame } from "@nanobpm/agentic/protocol";
11
11
  import type { SqliteDb } from "@nanobpm/agentic/transcript";
12
12
  import type { AppApi, DataLayer } from "@nanobpm/urban";
13
13
  import { assert, assertEquals } from "#test-assert";
14
+ import { composeStreamId } from "@nanobpm/agentic/emit";
14
15
  import { currentCorrelation } from "../app/agentic/correlation.ts";
15
16
  import { family as correlationFamily } from "../app/agentic/families/correlation.family.ts";
16
17
  import { createRelayFamily, currentRelayTranscriptService } from "../app/agentic/families/relay.family.ts";
@@ -78,8 +79,8 @@ test("projects the TranscriptStore rows into the list (byteLength, chunkCount, l
78
79
  relayFamily.mount(mountCtx(memSqlite()));
79
80
  const store = currentRelayTranscriptService()?.store;
80
81
  assert(store !== undefined, "the relay family installs a persisted store");
81
- // Seed one completed ephemeral session on a jobKey-scoped stream.
82
- store.flush("job:6494", { since: () => ({ entries: [{ offset: 0, chunk: "hello " }, { offset: 1, chunk: "world" }] }), nextOffset: 2 }, "ephemeral");
82
+ // Seed one completed ephemeral session on an instance-scoped stream (issue #738).
83
+ store.flush(composeStreamId("wk", "6494"), { since: () => ({ entries: [{ offset: 0, chunk: "hello " }, { offset: 1, chunk: "world" }] }), nextOffset: 2 }, "ephemeral");
83
84
  try {
84
85
  const res = (await handler(input(), app)) as {
85
86
  status: number;
@@ -89,8 +90,8 @@ test("projects the TranscriptStore rows into the list (byteLength, chunkCount, l
89
90
  assertEquals(res.body.count, 1);
90
91
  assert(typeof res.body.retentionMs === "number", "the list surfaces the retention window");
91
92
  const t = res.body.transcripts[0];
92
- assertEquals(t.stream, "job:6494");
93
- assertEquals(t.jobKey, "6494", "the jobKey is decoded from the job: stream id");
93
+ assertEquals(t.stream, composeStreamId("wk", "6494"));
94
+ assertEquals(t.jobKey, "6494", "the jobKey is decoded from the instance-scoped stream id");
94
95
  assertEquals(t.lifecycle, "ephemeral");
95
96
  assertEquals(t.status, "completed");
96
97
  assertEquals(t.chunkCount, 2);
@@ -105,7 +106,7 @@ test("enriches with the H6 correlation (process instance / plan) when it is stil
105
106
  relayFamily.mount(mountCtx(memSqlite()));
106
107
  const store = currentRelayTranscriptService()?.store;
107
108
  assert(store !== undefined);
108
- store.flush("job:6494", { since: () => ({ entries: [{ offset: 0, chunk: "x" }] }), nextOffset: 1 }, "ephemeral");
109
+ store.flush(composeStreamId("wk-a", "6494"), { since: () => ({ entries: [{ offset: 0, chunk: "x" }] }), nextOffset: 1 }, "ephemeral");
109
110
  correlationFamily.mount({ hub: undefined as never, registry: undefined as never, transport: undefined as never, data: undefined, log: noopLog() });
110
111
  currentCorrelation()?.link("wk-a", "6494", { processInstanceKey: "4612", bpmnProcessId: "plan-fanout", planKey: "o/r#142" });
111
112
  try {
@@ -124,18 +125,18 @@ test("filters by jobKey and plan", async () => {
124
125
  relayFamily.mount(mountCtx(memSqlite()));
125
126
  const store = currentRelayTranscriptService()?.store;
126
127
  assert(store !== undefined);
127
- store.flush("job:1", { since: () => ({ entries: [{ offset: 0, chunk: "a" }] }), nextOffset: 1 }, "ephemeral");
128
- store.flush("job:2", { since: () => ({ entries: [{ offset: 0, chunk: "b" }] }), nextOffset: 1 }, "ephemeral");
128
+ store.flush(composeStreamId("wk", "1"), { since: () => ({ entries: [{ offset: 0, chunk: "a" }] }), nextOffset: 1 }, "ephemeral");
129
+ store.flush(composeStreamId("wk", "2"), { since: () => ({ entries: [{ offset: 0, chunk: "b" }] }), nextOffset: 1 }, "ephemeral");
129
130
  correlationFamily.mount({ hub: undefined as never, registry: undefined as never, transport: undefined as never, data: undefined, log: noopLog() });
130
131
  currentCorrelation()?.link("wk", "2", { planKey: "o/r#9" });
131
132
  try {
132
133
  const byJob = (await handler(input({ jobKey: "1" }), app)) as { body: { count: number; transcripts: Array<Record<string, unknown>> } };
133
134
  assertEquals(byJob.body.count, 1);
134
- assertEquals(byJob.body.transcripts[0]?.stream, "job:1");
135
+ assertEquals(byJob.body.transcripts[0]?.stream, composeStreamId("wk", "1"));
135
136
 
136
137
  const byPlan = (await handler(input({ planKey: "o/r#9" }), app)) as { body: { count: number; transcripts: Array<Record<string, unknown>> } };
137
138
  assertEquals(byPlan.body.count, 1);
138
- assertEquals(byPlan.body.transcripts[0]?.stream, "job:2");
139
+ assertEquals(byPlan.body.transcripts[0]?.stream, composeStreamId("wk", "2"));
139
140
  } finally {
140
141
  correlationFamily.teardown?.();
141
142
  relayFamily.teardown?.();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.183.1",
3
+ "version": "0.183.2",
4
4
  "description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
5
5
  "type": "module",
6
6
  "main": "main.ts",
@@ -27,6 +27,7 @@ import type { SqliteDb } from "@nanobpm/agentic/presence";
27
27
  import { decodeFrame, encodeFrame, type Frame } from "@nanobpm/agentic/protocol";
28
28
  import type { AppApi, DataLayer } from "@nanobpm/urban";
29
29
  import { assert, assertEquals } from "#test-assert";
30
+ import { composeStreamId } from "@nanobpm/agentic/emit";
30
31
  import { currentCorrelation } from "../app/agentic/correlation.ts";
31
32
  import { loadAgenticFamilies } from "../app/agentic/loader.ts";
32
33
  import { type AgenticContext, AgenticFamilyRegistry } from "../app/agentic/registry.ts";
@@ -146,7 +147,9 @@ function supplyInput() {
146
147
  test("E2E: the whole visibility plane wires up — presence, correlation, supply report, relay drill, and resume across a hub restart", async () => {
147
148
  const db = memSqlite();
148
149
  const JOB = "6494";
149
- const STREAM = `job:${JOB}`;
150
+ // The producer writes a job's terminal on the instance-scoped stream (issue #738); the drill stream
151
+ // the supply advertises MUST be this exact id, or the cockpit reads a stream that never existed.
152
+ const STREAM = composeStreamId("wk-a", JOB);
150
153
 
151
154
  // Sanity: the fleet the seam discovers really includes presence, relay, and correlation.
152
155
  const fleet = await mountFleet(db);