@warmdrift/kgauto-compiler 2.0.0-alpha.24 → 2.0.0-alpha.26

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,92 +1,6 @@
1
1
  // src/glassbox/types.ts
2
2
  var GLASSBOX_STREAM_TTL_MS = 6e4;
3
3
 
4
- // src/glassbox/pubsub-memory.ts
5
- var MemoryPubSub = class {
6
- subscribers = /* @__PURE__ */ new Map();
7
- async publish(traceId, event) {
8
- const subs = this.subscribers.get(traceId);
9
- if (!subs || subs.size === 0) return;
10
- for (const sub of subs) {
11
- if (sub.closed) continue;
12
- try {
13
- sub.controller.enqueue(event);
14
- } catch {
15
- sub.closed = true;
16
- continue;
17
- }
18
- this.refreshTtl(traceId, sub);
19
- }
20
- }
21
- subscribe(traceId) {
22
- const self = this;
23
- let sub;
24
- return new ReadableStream({
25
- start(controller) {
26
- sub = {
27
- controller,
28
- ttlTimer: setTimeout(() => {
29
- self.closeSubscriber(traceId, sub);
30
- }, GLASSBOX_STREAM_TTL_MS),
31
- closed: false
32
- };
33
- let set = self.subscribers.get(traceId);
34
- if (!set) {
35
- set = /* @__PURE__ */ new Set();
36
- self.subscribers.set(traceId, set);
37
- }
38
- set.add(sub);
39
- },
40
- cancel() {
41
- if (sub) self.removeSubscriber(traceId, sub);
42
- }
43
- });
44
- }
45
- /**
46
- * Refresh the rolling TTL for a subscriber after an event lands. Replaces
47
- * the existing timer with a fresh 60s one.
48
- */
49
- refreshTtl(traceId, sub) {
50
- clearTimeout(sub.ttlTimer);
51
- sub.ttlTimer = setTimeout(() => {
52
- this.closeSubscriber(traceId, sub);
53
- }, GLASSBOX_STREAM_TTL_MS);
54
- }
55
- /**
56
- * Close the subscriber's stream cleanly and remove from the fan-out set.
57
- * Idempotent — safe to call multiple times.
58
- */
59
- closeSubscriber(traceId, sub) {
60
- if (sub.closed) return;
61
- sub.closed = true;
62
- clearTimeout(sub.ttlTimer);
63
- try {
64
- sub.controller.close();
65
- } catch {
66
- }
67
- this.removeSubscriber(traceId, sub);
68
- }
69
- removeSubscriber(traceId, sub) {
70
- clearTimeout(sub.ttlTimer);
71
- const set = this.subscribers.get(traceId);
72
- if (!set) return;
73
- set.delete(sub);
74
- if (set.size === 0) this.subscribers.delete(traceId);
75
- }
76
- /**
77
- * Test-only reset. Tears down all subscribers, clears all state. Calling
78
- * outside of tests is harmless but cancels every active stream.
79
- */
80
- _reset() {
81
- for (const [, set] of this.subscribers) {
82
- for (const sub of set) {
83
- this.closeSubscriber("", sub);
84
- }
85
- }
86
- this.subscribers.clear();
87
- }
88
- };
89
-
90
4
  // src/glassbox/pubsub-upstash.ts
91
5
  var UpstashPubSub = class {
92
6
  url;
@@ -101,8 +15,8 @@ var UpstashPubSub = class {
101
15
  this.blockMs = cfg.blockMs ?? 100;
102
16
  this.maxLen = cfg.maxLen ?? 100;
103
17
  }
104
- async publish(traceId, event) {
105
- const key = streamKey(traceId);
18
+ async publish(channelKey, event) {
19
+ const key = channelKey;
106
20
  const payload = JSON.stringify(event);
107
21
  await this.cmd([
108
22
  "XADD",
@@ -116,8 +30,8 @@ var UpstashPubSub = class {
116
30
  ]);
117
31
  await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
118
32
  }
119
- subscribe(traceId) {
120
- const key = streamKey(traceId);
33
+ subscribe(channelKey) {
34
+ const key = channelKey;
121
35
  const self = this;
122
36
  let cursor = "$";
123
37
  let cancelled = false;
@@ -191,9 +105,12 @@ var UpstashPubSub = class {
191
105
  return json;
192
106
  }
193
107
  };
194
- function streamKey(traceId) {
108
+ function traceChannel(traceId) {
195
109
  return `glassbox:trace:${traceId}`;
196
110
  }
111
+ function appChannel(appId) {
112
+ return `glassbox:app:${appId}`;
113
+ }
197
114
  function decodeEvent(fields) {
198
115
  const raw = fields["event"];
199
116
  if (!raw) return void 0;
@@ -231,6 +148,92 @@ function parseXReadResult(raw) {
231
148
  return { entries };
232
149
  }
233
150
 
151
+ // src/glassbox/pubsub-memory.ts
152
+ var MemoryPubSub = class {
153
+ subscribers = /* @__PURE__ */ new Map();
154
+ async publish(channelKey, event) {
155
+ const subs = this.subscribers.get(channelKey);
156
+ if (!subs || subs.size === 0) return;
157
+ for (const sub of subs) {
158
+ if (sub.closed) continue;
159
+ try {
160
+ sub.controller.enqueue(event);
161
+ } catch {
162
+ sub.closed = true;
163
+ continue;
164
+ }
165
+ this.refreshTtl(channelKey, sub);
166
+ }
167
+ }
168
+ subscribe(channelKey) {
169
+ const self = this;
170
+ let sub;
171
+ return new ReadableStream({
172
+ start(controller) {
173
+ sub = {
174
+ controller,
175
+ ttlTimer: setTimeout(() => {
176
+ self.closeSubscriber(channelKey, sub);
177
+ }, GLASSBOX_STREAM_TTL_MS),
178
+ closed: false
179
+ };
180
+ let set = self.subscribers.get(channelKey);
181
+ if (!set) {
182
+ set = /* @__PURE__ */ new Set();
183
+ self.subscribers.set(channelKey, set);
184
+ }
185
+ set.add(sub);
186
+ },
187
+ cancel() {
188
+ if (sub) self.removeSubscriber(channelKey, sub);
189
+ }
190
+ });
191
+ }
192
+ /**
193
+ * Refresh the rolling TTL for a subscriber after an event lands. Replaces
194
+ * the existing timer with a fresh 60s one.
195
+ */
196
+ refreshTtl(channelKey, sub) {
197
+ clearTimeout(sub.ttlTimer);
198
+ sub.ttlTimer = setTimeout(() => {
199
+ this.closeSubscriber(channelKey, sub);
200
+ }, GLASSBOX_STREAM_TTL_MS);
201
+ }
202
+ /**
203
+ * Close the subscriber's stream cleanly and remove from the fan-out set.
204
+ * Idempotent — safe to call multiple times.
205
+ */
206
+ closeSubscriber(channelKey, sub) {
207
+ if (sub.closed) return;
208
+ sub.closed = true;
209
+ clearTimeout(sub.ttlTimer);
210
+ try {
211
+ sub.controller.close();
212
+ } catch {
213
+ }
214
+ this.removeSubscriber(channelKey, sub);
215
+ }
216
+ removeSubscriber(channelKey, sub) {
217
+ clearTimeout(sub.ttlTimer);
218
+ const set = this.subscribers.get(channelKey);
219
+ if (!set) return;
220
+ set.delete(sub);
221
+ if (set.size === 0) this.subscribers.delete(channelKey);
222
+ }
223
+ /**
224
+ * Test-only reset. Tears down all subscribers, clears all state. Calling
225
+ * outside of tests is harmless but cancels every active stream.
226
+ */
227
+ _reset() {
228
+ for (const [, set] of this.subscribers) {
229
+ for (const sub of set) {
230
+ this.closeSubscriber("", sub);
231
+ }
232
+ }
233
+ this.subscribers.clear();
234
+ }
235
+ };
236
+
234
237
  // src/glassbox/emit.ts
235
238
  var activePubSub;
236
239
  function getPubSub() {
@@ -254,40 +257,52 @@ function readEnv(key) {
254
257
  }
255
258
  return void 0;
256
259
  }
257
- function emitGlassboxEvent(traceId, kind, data) {
260
+ function emitGlassboxEvent(traceId, appId, kind, data) {
258
261
  if (!traceId) return;
259
262
  const event = { kind, at: Date.now(), data };
260
263
  const ps = getPubSub();
261
264
  try {
262
- const p = ps.publish(traceId, event);
263
- if (p && typeof p.then === "function") {
264
- p.catch(() => {
265
+ const p1 = ps.publish(traceChannel(traceId), event);
266
+ if (p1 && typeof p1.then === "function") {
267
+ p1.catch(() => {
265
268
  });
266
269
  }
267
270
  } catch {
268
271
  }
272
+ if (appId) {
273
+ try {
274
+ const p2 = ps.publish(appChannel(appId), event);
275
+ if (p2 && typeof p2.then === "function") {
276
+ p2.catch(() => {
277
+ });
278
+ }
279
+ } catch {
280
+ }
281
+ }
269
282
  }
270
- function emitCompileStart(traceId, data) {
271
- emitGlassboxEvent(traceId, "compile.start", data);
283
+ function emitCompileStart(traceId, appId, data) {
284
+ emitGlassboxEvent(traceId, appId, "compile.start", data);
272
285
  }
273
- function emitCompileDone(traceId, data) {
274
- emitGlassboxEvent(traceId, "compile.done", data);
286
+ function emitCompileDone(traceId, appId, data) {
287
+ emitGlassboxEvent(traceId, appId, "compile.done", data);
275
288
  }
276
- function emitExecuteAttempt(traceId, data) {
277
- emitGlassboxEvent(traceId, "execute.attempt", data);
289
+ function emitExecuteAttempt(traceId, appId, data) {
290
+ emitGlassboxEvent(traceId, appId, "execute.attempt", data);
278
291
  }
279
- function emitExecuteSuccess(traceId, data) {
280
- emitGlassboxEvent(traceId, "execute.success", data);
292
+ function emitExecuteSuccess(traceId, appId, data) {
293
+ emitGlassboxEvent(traceId, appId, "execute.success", data);
281
294
  }
282
- function emitAdvisoryFired(traceId, data) {
283
- emitGlassboxEvent(traceId, "advisory.fired", data);
295
+ function emitAdvisoryFired(traceId, appId, data) {
296
+ emitGlassboxEvent(traceId, appId, "advisory.fired", data);
284
297
  }
285
- function emitFallbackWalked(traceId, data) {
286
- emitGlassboxEvent(traceId, "fallback.walked", data);
298
+ function emitFallbackWalked(traceId, appId, data) {
299
+ emitGlassboxEvent(traceId, appId, "fallback.walked", data);
287
300
  }
288
301
 
289
302
  export {
290
303
  GLASSBOX_STREAM_TTL_MS,
304
+ traceChannel,
305
+ appChannel,
291
306
  getPubSub,
292
307
  emitCompileStart,
293
308
  emitCompileDone,
@@ -0,0 +1,29 @@
1
+ import {
2
+ appChannel,
3
+ getPubSub,
4
+ traceChannel
5
+ } from "./chunk-NBO4R5PC.mjs";
6
+
7
+ // src/glassbox/subscribe.ts
8
+ function emptyStream() {
9
+ return new ReadableStream({
10
+ start(controller) {
11
+ controller.close();
12
+ }
13
+ });
14
+ }
15
+ function subscribe(traceId) {
16
+ if (!traceId) return emptyStream();
17
+ return getPubSub().subscribe(traceChannel(traceId));
18
+ }
19
+ function subscribeApp({
20
+ appId
21
+ }) {
22
+ if (!appId) return emptyStream();
23
+ return getPubSub().subscribe(appChannel(appId));
24
+ }
25
+
26
+ export {
27
+ subscribe,
28
+ subscribeApp
29
+ };
@@ -1,5 +1,5 @@
1
- import { G as GlassboxEvent } from '../types-D9WndxeD.mjs';
2
- export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-D9WndxeD.mjs';
1
+ import { G as GlassboxEvent } from '../types-o9etg93a.mjs';
2
+ export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-o9etg93a.mjs';
3
3
  import '../ir-B9zqlwjH.mjs';
4
4
  import '../dialect.mjs';
5
5
 
@@ -38,5 +38,22 @@ import '../dialect.mjs';
38
38
  * down the subscription cleanly via the underlying adapter.
39
39
  */
40
40
  declare function subscribe(traceId: string): ReadableStream<GlassboxEvent>;
41
+ /**
42
+ * Subscribe to Glass-Box events for ALL traces under an appId — the
43
+ * "tail-all" surface (alpha.26). Backs the extension's default Live mode:
44
+ * rather than needing a specific traceId ahead of time, the panel sees
45
+ * every event for the configured consumer as calls happen.
46
+ *
47
+ * Per-app routing fires only when emit call-sites pass `appId` (the typed
48
+ * builders thread `ir.appId` automatically). Per-trace channel continues to
49
+ * fire for `subscribe(traceId)` callers — both arms are independent.
50
+ *
51
+ * Cross-tenant isolation: the consumer's `/api/glassbox/stream` uses the
52
+ * factory's configured appId — no caller-supplied `?appId=` URL parameter,
53
+ * so a consumer cannot subscribe to another consumer's stream.
54
+ */
55
+ declare function subscribeApp({ appId, }: {
56
+ appId: string;
57
+ }): ReadableStream<GlassboxEvent>;
41
58
 
42
- export { GlassboxEvent, subscribe };
59
+ export { GlassboxEvent, subscribe, subscribeApp };
@@ -1,5 +1,5 @@
1
- import { G as GlassboxEvent } from '../types-DiWBWvxg.js';
2
- export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-DiWBWvxg.js';
1
+ import { G as GlassboxEvent } from '../types-bt0aVJb8.js';
2
+ export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-bt0aVJb8.js';
3
3
  import '../ir-B_XX2LAO.js';
4
4
  import '../dialect.js';
5
5
 
@@ -38,5 +38,22 @@ import '../dialect.js';
38
38
  * down the subscription cleanly via the underlying adapter.
39
39
  */
40
40
  declare function subscribe(traceId: string): ReadableStream<GlassboxEvent>;
41
+ /**
42
+ * Subscribe to Glass-Box events for ALL traces under an appId — the
43
+ * "tail-all" surface (alpha.26). Backs the extension's default Live mode:
44
+ * rather than needing a specific traceId ahead of time, the panel sees
45
+ * every event for the configured consumer as calls happen.
46
+ *
47
+ * Per-app routing fires only when emit call-sites pass `appId` (the typed
48
+ * builders thread `ir.appId` automatically). Per-trace channel continues to
49
+ * fire for `subscribe(traceId)` callers — both arms are independent.
50
+ *
51
+ * Cross-tenant isolation: the consumer's `/api/glassbox/stream` uses the
52
+ * factory's configured appId — no caller-supplied `?appId=` URL parameter,
53
+ * so a consumer cannot subscribe to another consumer's stream.
54
+ */
55
+ declare function subscribeApp({ appId, }: {
56
+ appId: string;
57
+ }): ReadableStream<GlassboxEvent>;
41
58
 
42
- export { GlassboxEvent, subscribe };
59
+ export { GlassboxEvent, subscribe, subscribeApp };
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var glassbox_exports = {};
22
22
  __export(glassbox_exports, {
23
23
  GLASSBOX_STREAM_TTL_MS: () => GLASSBOX_STREAM_TTL_MS,
24
- subscribe: () => subscribe
24
+ subscribe: () => subscribe,
25
+ subscribeApp: () => subscribeApp
25
26
  });
26
27
  module.exports = __toCommonJS(glassbox_exports);
27
28
 
@@ -31,8 +32,8 @@ var GLASSBOX_STREAM_TTL_MS = 6e4;
31
32
  // src/glassbox/pubsub-memory.ts
32
33
  var MemoryPubSub = class {
33
34
  subscribers = /* @__PURE__ */ new Map();
34
- async publish(traceId, event) {
35
- const subs = this.subscribers.get(traceId);
35
+ async publish(channelKey, event) {
36
+ const subs = this.subscribers.get(channelKey);
36
37
  if (!subs || subs.size === 0) return;
37
38
  for (const sub of subs) {
38
39
  if (sub.closed) continue;
@@ -42,10 +43,10 @@ var MemoryPubSub = class {
42
43
  sub.closed = true;
43
44
  continue;
44
45
  }
45
- this.refreshTtl(traceId, sub);
46
+ this.refreshTtl(channelKey, sub);
46
47
  }
47
48
  }
48
- subscribe(traceId) {
49
+ subscribe(channelKey) {
49
50
  const self = this;
50
51
  let sub;
51
52
  return new ReadableStream({
@@ -53,19 +54,19 @@ var MemoryPubSub = class {
53
54
  sub = {
54
55
  controller,
55
56
  ttlTimer: setTimeout(() => {
56
- self.closeSubscriber(traceId, sub);
57
+ self.closeSubscriber(channelKey, sub);
57
58
  }, GLASSBOX_STREAM_TTL_MS),
58
59
  closed: false
59
60
  };
60
- let set = self.subscribers.get(traceId);
61
+ let set = self.subscribers.get(channelKey);
61
62
  if (!set) {
62
63
  set = /* @__PURE__ */ new Set();
63
- self.subscribers.set(traceId, set);
64
+ self.subscribers.set(channelKey, set);
64
65
  }
65
66
  set.add(sub);
66
67
  },
67
68
  cancel() {
68
- if (sub) self.removeSubscriber(traceId, sub);
69
+ if (sub) self.removeSubscriber(channelKey, sub);
69
70
  }
70
71
  });
71
72
  }
@@ -73,17 +74,17 @@ var MemoryPubSub = class {
73
74
  * Refresh the rolling TTL for a subscriber after an event lands. Replaces
74
75
  * the existing timer with a fresh 60s one.
75
76
  */
76
- refreshTtl(traceId, sub) {
77
+ refreshTtl(channelKey, sub) {
77
78
  clearTimeout(sub.ttlTimer);
78
79
  sub.ttlTimer = setTimeout(() => {
79
- this.closeSubscriber(traceId, sub);
80
+ this.closeSubscriber(channelKey, sub);
80
81
  }, GLASSBOX_STREAM_TTL_MS);
81
82
  }
82
83
  /**
83
84
  * Close the subscriber's stream cleanly and remove from the fan-out set.
84
85
  * Idempotent — safe to call multiple times.
85
86
  */
86
- closeSubscriber(traceId, sub) {
87
+ closeSubscriber(channelKey, sub) {
87
88
  if (sub.closed) return;
88
89
  sub.closed = true;
89
90
  clearTimeout(sub.ttlTimer);
@@ -91,14 +92,14 @@ var MemoryPubSub = class {
91
92
  sub.controller.close();
92
93
  } catch {
93
94
  }
94
- this.removeSubscriber(traceId, sub);
95
+ this.removeSubscriber(channelKey, sub);
95
96
  }
96
- removeSubscriber(traceId, sub) {
97
+ removeSubscriber(channelKey, sub) {
97
98
  clearTimeout(sub.ttlTimer);
98
- const set = this.subscribers.get(traceId);
99
+ const set = this.subscribers.get(channelKey);
99
100
  if (!set) return;
100
101
  set.delete(sub);
101
- if (set.size === 0) this.subscribers.delete(traceId);
102
+ if (set.size === 0) this.subscribers.delete(channelKey);
102
103
  }
103
104
  /**
104
105
  * Test-only reset. Tears down all subscribers, clears all state. Calling
@@ -128,8 +129,8 @@ var UpstashPubSub = class {
128
129
  this.blockMs = cfg.blockMs ?? 100;
129
130
  this.maxLen = cfg.maxLen ?? 100;
130
131
  }
131
- async publish(traceId, event) {
132
- const key = streamKey(traceId);
132
+ async publish(channelKey, event) {
133
+ const key = channelKey;
133
134
  const payload = JSON.stringify(event);
134
135
  await this.cmd([
135
136
  "XADD",
@@ -143,8 +144,8 @@ var UpstashPubSub = class {
143
144
  ]);
144
145
  await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
145
146
  }
146
- subscribe(traceId) {
147
- const key = streamKey(traceId);
147
+ subscribe(channelKey) {
148
+ const key = channelKey;
148
149
  const self = this;
149
150
  let cursor = "$";
150
151
  let cancelled = false;
@@ -218,9 +219,12 @@ var UpstashPubSub = class {
218
219
  return json;
219
220
  }
220
221
  };
221
- function streamKey(traceId) {
222
+ function traceChannel(traceId) {
222
223
  return `glassbox:trace:${traceId}`;
223
224
  }
225
+ function appChannel(appId) {
226
+ return `glassbox:app:${appId}`;
227
+ }
224
228
  function decodeEvent(fields) {
225
229
  const raw = fields["event"];
226
230
  if (!raw) return void 0;
@@ -283,18 +287,26 @@ function readEnv(key) {
283
287
  }
284
288
 
285
289
  // src/glassbox/subscribe.ts
290
+ function emptyStream() {
291
+ return new ReadableStream({
292
+ start(controller) {
293
+ controller.close();
294
+ }
295
+ });
296
+ }
286
297
  function subscribe(traceId) {
287
- if (!traceId) {
288
- return new ReadableStream({
289
- start(controller) {
290
- controller.close();
291
- }
292
- });
293
- }
294
- return getPubSub().subscribe(traceId);
298
+ if (!traceId) return emptyStream();
299
+ return getPubSub().subscribe(traceChannel(traceId));
300
+ }
301
+ function subscribeApp({
302
+ appId
303
+ }) {
304
+ if (!appId) return emptyStream();
305
+ return getPubSub().subscribe(appChannel(appId));
295
306
  }
296
307
  // Annotate the CommonJS export names for ESM import in node:
297
308
  0 && (module.exports = {
298
309
  GLASSBOX_STREAM_TTL_MS,
299
- subscribe
310
+ subscribe,
311
+ subscribeApp
300
312
  });
@@ -1,10 +1,12 @@
1
1
  import {
2
- subscribe
3
- } from "../chunk-VZGMWKRT.mjs";
2
+ subscribe,
3
+ subscribeApp
4
+ } from "../chunk-RO22VFIF.mjs";
4
5
  import {
5
6
  GLASSBOX_STREAM_TTL_MS
6
- } from "../chunk-NUTC7NUC.mjs";
7
+ } from "../chunk-NBO4R5PC.mjs";
7
8
  export {
8
9
  GLASSBOX_STREAM_TTL_MS,
9
- subscribe
10
+ subscribe,
11
+ subscribeApp
10
12
  };
@@ -1,4 +1,4 @@
1
- import { G as GlassboxEvent } from '../types-D9WndxeD.mjs';
1
+ import { G as GlassboxEvent } from '../types-o9etg93a.mjs';
2
2
  import '../ir-B9zqlwjH.mjs';
3
3
  import '../dialect.mjs';
4
4
 
@@ -105,11 +105,20 @@ interface GlassboxRoutesConfig {
105
105
  */
106
106
  fetch?: typeof fetch;
107
107
  /**
108
- * Test-only seam: override the live-stream subscriber. Production code
109
- * resolves to the alpha.17 `subscribe()` export; tests inject a fake
108
+ * Test-only seam: override the per-trace live-stream subscriber. Production
109
+ * code resolves to the alpha.17 `subscribe()` export; tests inject a fake
110
110
  * source ReadableStream<GlassboxEvent>.
111
111
  */
112
112
  subscribe?: (traceId: string) => ReadableStream<GlassboxEvent>;
113
+ /**
114
+ * Test-only seam: override the per-app "tail-all" subscriber (alpha.26).
115
+ * Production code resolves to the `subscribeApp()` export; tests inject
116
+ * a fake source. Backs the extension's default Live tab mode when no
117
+ * traceId is supplied in the URL.
118
+ */
119
+ subscribeApp?: (args: {
120
+ appId: string;
121
+ }) => ReadableStream<GlassboxEvent>;
113
122
  }
114
123
  interface GlassboxRoutes {
115
124
  /** GET /api/glassbox/proxy?traceId=<id> OR ?limit=20 (recent traces) */
@@ -1,4 +1,4 @@
1
- import { G as GlassboxEvent } from '../types-DiWBWvxg.js';
1
+ import { G as GlassboxEvent } from '../types-bt0aVJb8.js';
2
2
  import '../ir-B_XX2LAO.js';
3
3
  import '../dialect.js';
4
4
 
@@ -105,11 +105,20 @@ interface GlassboxRoutesConfig {
105
105
  */
106
106
  fetch?: typeof fetch;
107
107
  /**
108
- * Test-only seam: override the live-stream subscriber. Production code
109
- * resolves to the alpha.17 `subscribe()` export; tests inject a fake
108
+ * Test-only seam: override the per-trace live-stream subscriber. Production
109
+ * code resolves to the alpha.17 `subscribe()` export; tests inject a fake
110
110
  * source ReadableStream<GlassboxEvent>.
111
111
  */
112
112
  subscribe?: (traceId: string) => ReadableStream<GlassboxEvent>;
113
+ /**
114
+ * Test-only seam: override the per-app "tail-all" subscriber (alpha.26).
115
+ * Production code resolves to the `subscribeApp()` export; tests inject
116
+ * a fake source. Backs the extension's default Live tab mode when no
117
+ * traceId is supplied in the URL.
118
+ */
119
+ subscribeApp?: (args: {
120
+ appId: string;
121
+ }) => ReadableStream<GlassboxEvent>;
113
122
  }
114
123
  interface GlassboxRoutes {
115
124
  /** GET /api/glassbox/proxy?traceId=<id> OR ?limit=20 (recent traces) */
@@ -129,7 +129,7 @@ function createProxyHandler(config) {
129
129
  const qs = new URLSearchParams();
130
130
  qs.set("app_id", `eq.${appId}`);
131
131
  if (traceId) {
132
- qs.set("trace_id", `eq.${traceId}`);
132
+ qs.set("handle", `eq.${traceId}`);
133
133
  } else {
134
134
  qs.set("order", "created_at.desc");
135
135
  qs.set("limit", String(limit));
@@ -190,13 +190,6 @@ var SSE_HEADERS = {
190
190
  Connection: "keep-alive",
191
191
  "X-Accel-Buffering": "no"
192
192
  };
193
- var JSON_HEADERS3 = { "Content-Type": "application/json" };
194
- function jsonError3(status, code) {
195
- return new Response(JSON.stringify({ error: code }), {
196
- status,
197
- headers: JSON_HEADERS3
198
- });
199
- }
200
193
  function applyScrub2(event, scrub) {
201
194
  if (!scrub) return event;
202
195
  try {
@@ -216,17 +209,14 @@ data: ${JSON.stringify(data)}
216
209
 
217
210
  `;
218
211
  }
219
- function createStreamHandler(config, subscribe2) {
220
- const { installToken, extensionId, scrub } = config;
212
+ function createStreamHandler(config, subscribe2, subscribeApp2) {
213
+ const { installToken, extensionId, appId, scrub } = config;
221
214
  return async function stream(req) {
222
215
  const authFail = checkAuth(req, { installToken, extensionId });
223
216
  if (authFail) return authFail;
224
217
  const url = new URL(req.url);
225
218
  const traceId = url.searchParams.get("traceId");
226
- if (!traceId) {
227
- return jsonError3(400, "missing_trace_id");
228
- }
229
- const source = subscribe2(traceId);
219
+ const source = traceId ? subscribe2(traceId) : subscribeApp2({ appId });
230
220
  const encoder = new TextEncoder();
231
221
  let sourceReader;
232
222
  let cancelled = false;
@@ -296,8 +286,8 @@ var GLASSBOX_STREAM_TTL_MS = 6e4;
296
286
  // src/glassbox/pubsub-memory.ts
297
287
  var MemoryPubSub = class {
298
288
  subscribers = /* @__PURE__ */ new Map();
299
- async publish(traceId, event) {
300
- const subs = this.subscribers.get(traceId);
289
+ async publish(channelKey, event) {
290
+ const subs = this.subscribers.get(channelKey);
301
291
  if (!subs || subs.size === 0) return;
302
292
  for (const sub of subs) {
303
293
  if (sub.closed) continue;
@@ -307,10 +297,10 @@ var MemoryPubSub = class {
307
297
  sub.closed = true;
308
298
  continue;
309
299
  }
310
- this.refreshTtl(traceId, sub);
300
+ this.refreshTtl(channelKey, sub);
311
301
  }
312
302
  }
313
- subscribe(traceId) {
303
+ subscribe(channelKey) {
314
304
  const self = this;
315
305
  let sub;
316
306
  return new ReadableStream({
@@ -318,19 +308,19 @@ var MemoryPubSub = class {
318
308
  sub = {
319
309
  controller,
320
310
  ttlTimer: setTimeout(() => {
321
- self.closeSubscriber(traceId, sub);
311
+ self.closeSubscriber(channelKey, sub);
322
312
  }, GLASSBOX_STREAM_TTL_MS),
323
313
  closed: false
324
314
  };
325
- let set = self.subscribers.get(traceId);
315
+ let set = self.subscribers.get(channelKey);
326
316
  if (!set) {
327
317
  set = /* @__PURE__ */ new Set();
328
- self.subscribers.set(traceId, set);
318
+ self.subscribers.set(channelKey, set);
329
319
  }
330
320
  set.add(sub);
331
321
  },
332
322
  cancel() {
333
- if (sub) self.removeSubscriber(traceId, sub);
323
+ if (sub) self.removeSubscriber(channelKey, sub);
334
324
  }
335
325
  });
336
326
  }
@@ -338,17 +328,17 @@ var MemoryPubSub = class {
338
328
  * Refresh the rolling TTL for a subscriber after an event lands. Replaces
339
329
  * the existing timer with a fresh 60s one.
340
330
  */
341
- refreshTtl(traceId, sub) {
331
+ refreshTtl(channelKey, sub) {
342
332
  clearTimeout(sub.ttlTimer);
343
333
  sub.ttlTimer = setTimeout(() => {
344
- this.closeSubscriber(traceId, sub);
334
+ this.closeSubscriber(channelKey, sub);
345
335
  }, GLASSBOX_STREAM_TTL_MS);
346
336
  }
347
337
  /**
348
338
  * Close the subscriber's stream cleanly and remove from the fan-out set.
349
339
  * Idempotent — safe to call multiple times.
350
340
  */
351
- closeSubscriber(traceId, sub) {
341
+ closeSubscriber(channelKey, sub) {
352
342
  if (sub.closed) return;
353
343
  sub.closed = true;
354
344
  clearTimeout(sub.ttlTimer);
@@ -356,14 +346,14 @@ var MemoryPubSub = class {
356
346
  sub.controller.close();
357
347
  } catch {
358
348
  }
359
- this.removeSubscriber(traceId, sub);
349
+ this.removeSubscriber(channelKey, sub);
360
350
  }
361
- removeSubscriber(traceId, sub) {
351
+ removeSubscriber(channelKey, sub) {
362
352
  clearTimeout(sub.ttlTimer);
363
- const set = this.subscribers.get(traceId);
353
+ const set = this.subscribers.get(channelKey);
364
354
  if (!set) return;
365
355
  set.delete(sub);
366
- if (set.size === 0) this.subscribers.delete(traceId);
356
+ if (set.size === 0) this.subscribers.delete(channelKey);
367
357
  }
368
358
  /**
369
359
  * Test-only reset. Tears down all subscribers, clears all state. Calling
@@ -393,8 +383,8 @@ var UpstashPubSub = class {
393
383
  this.blockMs = cfg.blockMs ?? 100;
394
384
  this.maxLen = cfg.maxLen ?? 100;
395
385
  }
396
- async publish(traceId, event) {
397
- const key = streamKey(traceId);
386
+ async publish(channelKey, event) {
387
+ const key = channelKey;
398
388
  const payload = JSON.stringify(event);
399
389
  await this.cmd([
400
390
  "XADD",
@@ -408,8 +398,8 @@ var UpstashPubSub = class {
408
398
  ]);
409
399
  await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
410
400
  }
411
- subscribe(traceId) {
412
- const key = streamKey(traceId);
401
+ subscribe(channelKey) {
402
+ const key = channelKey;
413
403
  const self = this;
414
404
  let cursor = "$";
415
405
  let cancelled = false;
@@ -483,9 +473,12 @@ var UpstashPubSub = class {
483
473
  return json;
484
474
  }
485
475
  };
486
- function streamKey(traceId) {
476
+ function traceChannel(traceId) {
487
477
  return `glassbox:trace:${traceId}`;
488
478
  }
479
+ function appChannel(appId) {
480
+ return `glassbox:app:${appId}`;
481
+ }
489
482
  function decodeEvent(fields) {
490
483
  const raw = fields["event"];
491
484
  if (!raw) return void 0;
@@ -548,15 +541,22 @@ function readEnv(key) {
548
541
  }
549
542
 
550
543
  // src/glassbox/subscribe.ts
544
+ function emptyStream() {
545
+ return new ReadableStream({
546
+ start(controller) {
547
+ controller.close();
548
+ }
549
+ });
550
+ }
551
551
  function subscribe(traceId) {
552
- if (!traceId) {
553
- return new ReadableStream({
554
- start(controller) {
555
- controller.close();
556
- }
557
- });
558
- }
559
- return getPubSub().subscribe(traceId);
552
+ if (!traceId) return emptyStream();
553
+ return getPubSub().subscribe(traceChannel(traceId));
554
+ }
555
+ function subscribeApp({
556
+ appId
557
+ }) {
558
+ if (!appId) return emptyStream();
559
+ return getPubSub().subscribe(appChannel(appId));
560
560
  }
561
561
 
562
562
  // src/glassbox-routes/index.ts
@@ -587,9 +587,11 @@ function createGlassboxRoutes(config) {
587
587
  {
588
588
  installToken,
589
589
  extensionId,
590
+ appId,
590
591
  scrub: config.scrub
591
592
  },
592
- config.subscribe ?? subscribe
593
+ config.subscribe ?? subscribe,
594
+ config.subscribeApp ?? subscribeApp
593
595
  );
594
596
  return { proxy, stream };
595
597
  }
@@ -1,7 +1,8 @@
1
1
  import {
2
- subscribe
3
- } from "../chunk-VZGMWKRT.mjs";
4
- import "../chunk-NUTC7NUC.mjs";
2
+ subscribe,
3
+ subscribeApp
4
+ } from "../chunk-RO22VFIF.mjs";
5
+ import "../chunk-NBO4R5PC.mjs";
5
6
 
6
7
  // src/glassbox-routes/auth.ts
7
8
  var JSON_HEADERS = { "Content-Type": "application/json" };
@@ -108,7 +109,7 @@ function createProxyHandler(config) {
108
109
  const qs = new URLSearchParams();
109
110
  qs.set("app_id", `eq.${appId}`);
110
111
  if (traceId) {
111
- qs.set("trace_id", `eq.${traceId}`);
112
+ qs.set("handle", `eq.${traceId}`);
112
113
  } else {
113
114
  qs.set("order", "created_at.desc");
114
115
  qs.set("limit", String(limit));
@@ -169,13 +170,6 @@ var SSE_HEADERS = {
169
170
  Connection: "keep-alive",
170
171
  "X-Accel-Buffering": "no"
171
172
  };
172
- var JSON_HEADERS3 = { "Content-Type": "application/json" };
173
- function jsonError3(status, code) {
174
- return new Response(JSON.stringify({ error: code }), {
175
- status,
176
- headers: JSON_HEADERS3
177
- });
178
- }
179
173
  function applyScrub2(event, scrub) {
180
174
  if (!scrub) return event;
181
175
  try {
@@ -195,17 +189,14 @@ data: ${JSON.stringify(data)}
195
189
 
196
190
  `;
197
191
  }
198
- function createStreamHandler(config, subscribe2) {
199
- const { installToken, extensionId, scrub } = config;
192
+ function createStreamHandler(config, subscribe2, subscribeApp2) {
193
+ const { installToken, extensionId, appId, scrub } = config;
200
194
  return async function stream(req) {
201
195
  const authFail = checkAuth(req, { installToken, extensionId });
202
196
  if (authFail) return authFail;
203
197
  const url = new URL(req.url);
204
198
  const traceId = url.searchParams.get("traceId");
205
- if (!traceId) {
206
- return jsonError3(400, "missing_trace_id");
207
- }
208
- const source = subscribe2(traceId);
199
+ const source = traceId ? subscribe2(traceId) : subscribeApp2({ appId });
209
200
  const encoder = new TextEncoder();
210
201
  let sourceReader;
211
202
  let cancelled = false;
@@ -297,9 +288,11 @@ function createGlassboxRoutes(config) {
297
288
  {
298
289
  installToken,
299
290
  extensionId,
291
+ appId,
300
292
  scrub: config.scrub
301
293
  },
302
- config.subscribe ?? subscribe
294
+ config.subscribe ?? subscribe,
295
+ config.subscribeApp ?? subscribeApp
303
296
  );
304
297
  return { proxy, stream };
305
298
  }
package/dist/index.js CHANGED
@@ -3473,8 +3473,8 @@ var GLASSBOX_STREAM_TTL_MS = 6e4;
3473
3473
  // src/glassbox/pubsub-memory.ts
3474
3474
  var MemoryPubSub = class {
3475
3475
  subscribers = /* @__PURE__ */ new Map();
3476
- async publish(traceId, event) {
3477
- const subs = this.subscribers.get(traceId);
3476
+ async publish(channelKey, event) {
3477
+ const subs = this.subscribers.get(channelKey);
3478
3478
  if (!subs || subs.size === 0) return;
3479
3479
  for (const sub of subs) {
3480
3480
  if (sub.closed) continue;
@@ -3484,10 +3484,10 @@ var MemoryPubSub = class {
3484
3484
  sub.closed = true;
3485
3485
  continue;
3486
3486
  }
3487
- this.refreshTtl(traceId, sub);
3487
+ this.refreshTtl(channelKey, sub);
3488
3488
  }
3489
3489
  }
3490
- subscribe(traceId) {
3490
+ subscribe(channelKey) {
3491
3491
  const self = this;
3492
3492
  let sub;
3493
3493
  return new ReadableStream({
@@ -3495,19 +3495,19 @@ var MemoryPubSub = class {
3495
3495
  sub = {
3496
3496
  controller,
3497
3497
  ttlTimer: setTimeout(() => {
3498
- self.closeSubscriber(traceId, sub);
3498
+ self.closeSubscriber(channelKey, sub);
3499
3499
  }, GLASSBOX_STREAM_TTL_MS),
3500
3500
  closed: false
3501
3501
  };
3502
- let set = self.subscribers.get(traceId);
3502
+ let set = self.subscribers.get(channelKey);
3503
3503
  if (!set) {
3504
3504
  set = /* @__PURE__ */ new Set();
3505
- self.subscribers.set(traceId, set);
3505
+ self.subscribers.set(channelKey, set);
3506
3506
  }
3507
3507
  set.add(sub);
3508
3508
  },
3509
3509
  cancel() {
3510
- if (sub) self.removeSubscriber(traceId, sub);
3510
+ if (sub) self.removeSubscriber(channelKey, sub);
3511
3511
  }
3512
3512
  });
3513
3513
  }
@@ -3515,17 +3515,17 @@ var MemoryPubSub = class {
3515
3515
  * Refresh the rolling TTL for a subscriber after an event lands. Replaces
3516
3516
  * the existing timer with a fresh 60s one.
3517
3517
  */
3518
- refreshTtl(traceId, sub) {
3518
+ refreshTtl(channelKey, sub) {
3519
3519
  clearTimeout(sub.ttlTimer);
3520
3520
  sub.ttlTimer = setTimeout(() => {
3521
- this.closeSubscriber(traceId, sub);
3521
+ this.closeSubscriber(channelKey, sub);
3522
3522
  }, GLASSBOX_STREAM_TTL_MS);
3523
3523
  }
3524
3524
  /**
3525
3525
  * Close the subscriber's stream cleanly and remove from the fan-out set.
3526
3526
  * Idempotent — safe to call multiple times.
3527
3527
  */
3528
- closeSubscriber(traceId, sub) {
3528
+ closeSubscriber(channelKey, sub) {
3529
3529
  if (sub.closed) return;
3530
3530
  sub.closed = true;
3531
3531
  clearTimeout(sub.ttlTimer);
@@ -3533,14 +3533,14 @@ var MemoryPubSub = class {
3533
3533
  sub.controller.close();
3534
3534
  } catch {
3535
3535
  }
3536
- this.removeSubscriber(traceId, sub);
3536
+ this.removeSubscriber(channelKey, sub);
3537
3537
  }
3538
- removeSubscriber(traceId, sub) {
3538
+ removeSubscriber(channelKey, sub) {
3539
3539
  clearTimeout(sub.ttlTimer);
3540
- const set = this.subscribers.get(traceId);
3540
+ const set = this.subscribers.get(channelKey);
3541
3541
  if (!set) return;
3542
3542
  set.delete(sub);
3543
- if (set.size === 0) this.subscribers.delete(traceId);
3543
+ if (set.size === 0) this.subscribers.delete(channelKey);
3544
3544
  }
3545
3545
  /**
3546
3546
  * Test-only reset. Tears down all subscribers, clears all state. Calling
@@ -3570,8 +3570,8 @@ var UpstashPubSub = class {
3570
3570
  this.blockMs = cfg.blockMs ?? 100;
3571
3571
  this.maxLen = cfg.maxLen ?? 100;
3572
3572
  }
3573
- async publish(traceId, event) {
3574
- const key = streamKey(traceId);
3573
+ async publish(channelKey, event) {
3574
+ const key = channelKey;
3575
3575
  const payload = JSON.stringify(event);
3576
3576
  await this.cmd([
3577
3577
  "XADD",
@@ -3585,8 +3585,8 @@ var UpstashPubSub = class {
3585
3585
  ]);
3586
3586
  await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
3587
3587
  }
3588
- subscribe(traceId) {
3589
- const key = streamKey(traceId);
3588
+ subscribe(channelKey) {
3589
+ const key = channelKey;
3590
3590
  const self = this;
3591
3591
  let cursor = "$";
3592
3592
  let cancelled = false;
@@ -3660,9 +3660,12 @@ var UpstashPubSub = class {
3660
3660
  return json;
3661
3661
  }
3662
3662
  };
3663
- function streamKey(traceId) {
3663
+ function traceChannel(traceId) {
3664
3664
  return `glassbox:trace:${traceId}`;
3665
3665
  }
3666
+ function appChannel(appId) {
3667
+ return `glassbox:app:${appId}`;
3668
+ }
3666
3669
  function decodeEvent(fields) {
3667
3670
  const raw = fields["event"];
3668
3671
  if (!raw) return void 0;
@@ -3723,43 +3726,53 @@ function readEnv(key) {
3723
3726
  }
3724
3727
  return void 0;
3725
3728
  }
3726
- function emitGlassboxEvent(traceId, kind, data) {
3729
+ function emitGlassboxEvent(traceId, appId, kind, data) {
3727
3730
  if (!traceId) return;
3728
3731
  const event = { kind, at: Date.now(), data };
3729
3732
  const ps = getPubSub();
3730
3733
  try {
3731
- const p = ps.publish(traceId, event);
3732
- if (p && typeof p.then === "function") {
3733
- p.catch(() => {
3734
+ const p1 = ps.publish(traceChannel(traceId), event);
3735
+ if (p1 && typeof p1.then === "function") {
3736
+ p1.catch(() => {
3734
3737
  });
3735
3738
  }
3736
3739
  } catch {
3737
3740
  }
3741
+ if (appId) {
3742
+ try {
3743
+ const p2 = ps.publish(appChannel(appId), event);
3744
+ if (p2 && typeof p2.then === "function") {
3745
+ p2.catch(() => {
3746
+ });
3747
+ }
3748
+ } catch {
3749
+ }
3750
+ }
3738
3751
  }
3739
- function emitCompileStart(traceId, data) {
3740
- emitGlassboxEvent(traceId, "compile.start", data);
3752
+ function emitCompileStart(traceId, appId, data) {
3753
+ emitGlassboxEvent(traceId, appId, "compile.start", data);
3741
3754
  }
3742
- function emitCompileDone(traceId, data) {
3743
- emitGlassboxEvent(traceId, "compile.done", data);
3755
+ function emitCompileDone(traceId, appId, data) {
3756
+ emitGlassboxEvent(traceId, appId, "compile.done", data);
3744
3757
  }
3745
- function emitExecuteAttempt(traceId, data) {
3746
- emitGlassboxEvent(traceId, "execute.attempt", data);
3758
+ function emitExecuteAttempt(traceId, appId, data) {
3759
+ emitGlassboxEvent(traceId, appId, "execute.attempt", data);
3747
3760
  }
3748
- function emitExecuteSuccess(traceId, data) {
3749
- emitGlassboxEvent(traceId, "execute.success", data);
3761
+ function emitExecuteSuccess(traceId, appId, data) {
3762
+ emitGlassboxEvent(traceId, appId, "execute.success", data);
3750
3763
  }
3751
- function emitAdvisoryFired(traceId, data) {
3752
- emitGlassboxEvent(traceId, "advisory.fired", data);
3764
+ function emitAdvisoryFired(traceId, appId, data) {
3765
+ emitGlassboxEvent(traceId, appId, "advisory.fired", data);
3753
3766
  }
3754
- function emitFallbackWalked(traceId, data) {
3755
- emitGlassboxEvent(traceId, "fallback.walked", data);
3767
+ function emitFallbackWalked(traceId, appId, data) {
3768
+ emitGlassboxEvent(traceId, appId, "fallback.walked", data);
3756
3769
  }
3757
3770
 
3758
3771
  // src/call.ts
3759
3772
  async function call(ir, opts = {}) {
3760
3773
  const traceId = generateTraceId();
3761
3774
  safeEmit(
3762
- () => emitCompileStart(traceId, {
3775
+ () => emitCompileStart(traceId, ir.appId, {
3763
3776
  appId: ir.appId,
3764
3777
  archetype: ir.intent.archetype,
3765
3778
  models: ir.models
@@ -3767,7 +3780,7 @@ async function call(ir, opts = {}) {
3767
3780
  );
3768
3781
  const initial = compileAndRegister(ir, opts);
3769
3782
  safeEmit(
3770
- () => emitCompileDone(traceId, {
3783
+ () => emitCompileDone(traceId, ir.appId, {
3771
3784
  target: initial.target,
3772
3785
  provider: initial.provider,
3773
3786
  fallbackChain: initial.fallbackChain,
@@ -3779,7 +3792,7 @@ async function call(ir, opts = {}) {
3779
3792
  );
3780
3793
  for (const adv of initial.advisories) {
3781
3794
  safeEmit(
3782
- () => emitAdvisoryFired(traceId, { code: adv.code, message: adv.message })
3795
+ () => emitAdvisoryFired(traceId, ir.appId, { code: adv.code, message: adv.message })
3783
3796
  );
3784
3797
  }
3785
3798
  const start = Date.now();
@@ -3913,7 +3926,7 @@ async function call(ir, opts = {}) {
3913
3926
  }
3914
3927
  }
3915
3928
  safeEmit(
3916
- () => emitExecuteAttempt(traceId, { model: targetModel, attemptIndex: i })
3929
+ () => emitExecuteAttempt(traceId, ir.appId, { model: targetModel, attemptIndex: i })
3917
3930
  );
3918
3931
  const exec = await execute(activeCompile.request, {
3919
3932
  apiKeys: opts.apiKeys,
@@ -3925,7 +3938,7 @@ async function call(ir, opts = {}) {
3925
3938
  attempts.push({ model: targetModel, status: "success" });
3926
3939
  const latencyMs2 = Date.now() - start;
3927
3940
  safeEmit(
3928
- () => emitExecuteSuccess(traceId, {
3941
+ () => emitExecuteSuccess(traceId, ir.appId, {
3929
3942
  model: targetModel,
3930
3943
  tokensIn: validated.response.tokens.input,
3931
3944
  tokensOut: validated.response.tokens.output,
@@ -3953,7 +3966,7 @@ async function call(ir, opts = {}) {
3953
3966
  const firstFailed = attempts.find((a) => a.status !== "success");
3954
3967
  if (firstFailed) {
3955
3968
  safeEmit(
3956
- () => emitFallbackWalked(traceId, {
3969
+ () => emitFallbackWalked(traceId, ir.appId, {
3957
3970
  from: initial.target,
3958
3971
  to: targetModel,
3959
3972
  reason: fallbackReason ?? "unknown",
package/dist/index.mjs CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  emitExecuteAttempt,
26
26
  emitExecuteSuccess,
27
27
  emitFallbackWalked
28
- } from "./chunk-NUTC7NUC.mjs";
28
+ } from "./chunk-NBO4R5PC.mjs";
29
29
 
30
30
  // src/tokenizer.ts
31
31
  var tokenizerImpl = defaultCharBasedCounter;
@@ -2265,7 +2265,7 @@ function ensureCrossProviderTail(opts) {
2265
2265
  async function call(ir, opts = {}) {
2266
2266
  const traceId = generateTraceId();
2267
2267
  safeEmit(
2268
- () => emitCompileStart(traceId, {
2268
+ () => emitCompileStart(traceId, ir.appId, {
2269
2269
  appId: ir.appId,
2270
2270
  archetype: ir.intent.archetype,
2271
2271
  models: ir.models
@@ -2273,7 +2273,7 @@ async function call(ir, opts = {}) {
2273
2273
  );
2274
2274
  const initial = compileAndRegister(ir, opts);
2275
2275
  safeEmit(
2276
- () => emitCompileDone(traceId, {
2276
+ () => emitCompileDone(traceId, ir.appId, {
2277
2277
  target: initial.target,
2278
2278
  provider: initial.provider,
2279
2279
  fallbackChain: initial.fallbackChain,
@@ -2285,7 +2285,7 @@ async function call(ir, opts = {}) {
2285
2285
  );
2286
2286
  for (const adv of initial.advisories) {
2287
2287
  safeEmit(
2288
- () => emitAdvisoryFired(traceId, { code: adv.code, message: adv.message })
2288
+ () => emitAdvisoryFired(traceId, ir.appId, { code: adv.code, message: adv.message })
2289
2289
  );
2290
2290
  }
2291
2291
  const start = Date.now();
@@ -2419,7 +2419,7 @@ async function call(ir, opts = {}) {
2419
2419
  }
2420
2420
  }
2421
2421
  safeEmit(
2422
- () => emitExecuteAttempt(traceId, { model: targetModel, attemptIndex: i })
2422
+ () => emitExecuteAttempt(traceId, ir.appId, { model: targetModel, attemptIndex: i })
2423
2423
  );
2424
2424
  const exec = await execute(activeCompile.request, {
2425
2425
  apiKeys: opts.apiKeys,
@@ -2431,7 +2431,7 @@ async function call(ir, opts = {}) {
2431
2431
  attempts.push({ model: targetModel, status: "success" });
2432
2432
  const latencyMs2 = Date.now() - start;
2433
2433
  safeEmit(
2434
- () => emitExecuteSuccess(traceId, {
2434
+ () => emitExecuteSuccess(traceId, ir.appId, {
2435
2435
  model: targetModel,
2436
2436
  tokensIn: validated.response.tokens.input,
2437
2437
  tokensOut: validated.response.tokens.output,
@@ -2459,7 +2459,7 @@ async function call(ir, opts = {}) {
2459
2459
  const firstFailed = attempts.find((a) => a.status !== "success");
2460
2460
  if (firstFailed) {
2461
2461
  safeEmit(
2462
- () => emitFallbackWalked(traceId, {
2462
+ () => emitFallbackWalked(traceId, ir.appId, {
2463
2463
  from: initial.target,
2464
2464
  to: targetModel,
2465
2465
  reason: fallbackReason ?? "unknown",
@@ -92,20 +92,29 @@ interface FallbackWalkedData {
92
92
  */
93
93
  interface GlassboxPubSub {
94
94
  /**
95
- * Publish a single event for a traceId. Returns a promise that resolves
96
- * after the event is durably appended (or rejects on adapter failure —
97
- * callers in emit.ts always swallow rejections).
95
+ * Publish a single event to a channel key. The channel is an opaque
96
+ * namespaced string callers build it via `traceChannel(traceId)` or
97
+ * `appChannel(appId)` (see pubsub-upstash.ts). Returns a promise that
98
+ * resolves after the event is durably appended (or rejects on adapter
99
+ * failure — callers in emit.ts always swallow rejections).
100
+ *
101
+ * Pre-alpha.26 the parameter was named `traceId` because there was only
102
+ * one channel namespace; alpha.26 added per-app channels for the
103
+ * "tail-all" Live tab subscription. Behavior identical to the adapters —
104
+ * they treat the value as an opaque key — but the rename surfaces the
105
+ * generalization at the type level.
98
106
  */
99
- publish(traceId: string, event: GlassboxEvent): Promise<void>;
107
+ publish(channelKey: string, event: GlassboxEvent): Promise<void>;
100
108
  /**
101
- * Subscribe to events for a traceId. Returns a ReadableStream that emits
102
- * GlassboxEvent objects as they're published. The stream closes cleanly
103
- * after the per-trace TTL elapses since the LAST event (rolling 60s).
109
+ * Subscribe to events on a channel key. Returns a ReadableStream that
110
+ * emits GlassboxEvent objects as they're published. The stream closes
111
+ * cleanly after the channel-level TTL elapses since the LAST event
112
+ * (rolling 60s).
104
113
  *
105
- * If the traceId has no publisher within 60s of subscription, the stream
106
- * closes empty.
114
+ * If no publisher writes to the channel within 60s of subscription, the
115
+ * stream closes empty.
107
116
  */
108
- subscribe(traceId: string): ReadableStream<GlassboxEvent>;
117
+ subscribe(channelKey: string): ReadableStream<GlassboxEvent>;
109
118
  /**
110
119
  * Test-only escape hatch. Clears any in-memory state. Upstash adapter
111
120
  * no-ops (server-side state isn't accessible from here). Tests reach for
@@ -92,20 +92,29 @@ interface FallbackWalkedData {
92
92
  */
93
93
  interface GlassboxPubSub {
94
94
  /**
95
- * Publish a single event for a traceId. Returns a promise that resolves
96
- * after the event is durably appended (or rejects on adapter failure —
97
- * callers in emit.ts always swallow rejections).
95
+ * Publish a single event to a channel key. The channel is an opaque
96
+ * namespaced string callers build it via `traceChannel(traceId)` or
97
+ * `appChannel(appId)` (see pubsub-upstash.ts). Returns a promise that
98
+ * resolves after the event is durably appended (or rejects on adapter
99
+ * failure — callers in emit.ts always swallow rejections).
100
+ *
101
+ * Pre-alpha.26 the parameter was named `traceId` because there was only
102
+ * one channel namespace; alpha.26 added per-app channels for the
103
+ * "tail-all" Live tab subscription. Behavior identical to the adapters —
104
+ * they treat the value as an opaque key — but the rename surfaces the
105
+ * generalization at the type level.
98
106
  */
99
- publish(traceId: string, event: GlassboxEvent): Promise<void>;
107
+ publish(channelKey: string, event: GlassboxEvent): Promise<void>;
100
108
  /**
101
- * Subscribe to events for a traceId. Returns a ReadableStream that emits
102
- * GlassboxEvent objects as they're published. The stream closes cleanly
103
- * after the per-trace TTL elapses since the LAST event (rolling 60s).
109
+ * Subscribe to events on a channel key. Returns a ReadableStream that
110
+ * emits GlassboxEvent objects as they're published. The stream closes
111
+ * cleanly after the channel-level TTL elapses since the LAST event
112
+ * (rolling 60s).
104
113
  *
105
- * If the traceId has no publisher within 60s of subscription, the stream
106
- * closes empty.
114
+ * If no publisher writes to the channel within 60s of subscription, the
115
+ * stream closes empty.
107
116
  */
108
- subscribe(traceId: string): ReadableStream<GlassboxEvent>;
117
+ subscribe(channelKey: string): ReadableStream<GlassboxEvent>;
109
118
  /**
110
119
  * Test-only escape hatch. Clears any in-memory state. Upstash adapter
111
120
  * no-ops (server-side state isn't accessible from here). Tests reach for
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmdrift/kgauto-compiler",
3
- "version": "2.0.0-alpha.24",
3
+ "version": "2.0.0-alpha.26",
4
4
  "description": "Prompt compiler + central learning brain for multi-model AI apps. Swap models without rewriting prompts.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -1,19 +0,0 @@
1
- import {
2
- getPubSub
3
- } from "./chunk-NUTC7NUC.mjs";
4
-
5
- // src/glassbox/subscribe.ts
6
- function subscribe(traceId) {
7
- if (!traceId) {
8
- return new ReadableStream({
9
- start(controller) {
10
- controller.close();
11
- }
12
- });
13
- }
14
- return getPubSub().subscribe(traceId);
15
- }
16
-
17
- export {
18
- subscribe
19
- };