@syengup/friday-channel-next 0.1.2 → 0.1.4
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/LICENSE +1 -1
- package/dist/src/friday-session.js +35 -30
- package/package.json +1 -1
- package/src/friday-session.forward-agent.test.ts +64 -36
- package/src/friday-session.ts +32 -30
package/LICENSE
CHANGED
|
@@ -420,38 +420,43 @@ export function forwardAgentEventRaw(evt) {
|
|
|
420
420
|
}, ended.deviceId);
|
|
421
421
|
}
|
|
422
422
|
}
|
|
423
|
-
// Build sessionUsage:
|
|
424
|
-
if (isTerminalLifecycle) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const
|
|
423
|
+
// Build sessionUsage: store (cumulative session totals) → llm_output (per-run fallback).
|
|
424
|
+
if (isTerminalLifecycle && getFridayAgentForwardRuntime()) {
|
|
425
|
+
// Defer to let store write complete, then read cumulative totals.
|
|
426
|
+
// llm_output data is per-run; store is cumulative across rounds.
|
|
427
|
+
setTimeout(() => {
|
|
428
|
+
let data = outgoingData;
|
|
429
|
+
const storeUsage = tryReadSessionUsageFromStore(sk);
|
|
430
|
+
const llmUsage = consumeRunUsage(evt.runId);
|
|
431
|
+
const memUsage = buildSessionUsageFromRunMetadata(evt.runId);
|
|
432
|
+
let usage;
|
|
433
|
+
if (storeUsage) {
|
|
434
|
+
// Store provides cumulative session totals. Supplement with
|
|
435
|
+
// fresher model/provider from llm_output when available.
|
|
436
|
+
usage = storeUsage;
|
|
437
|
+
if (llmUsage?.modelId)
|
|
438
|
+
usage.modelId = llmUsage.modelId;
|
|
439
|
+
if (llmUsage?.modelProvider)
|
|
440
|
+
usage.modelProvider = llmUsage.modelProvider;
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
// First message in session — store not yet written, fall back
|
|
444
|
+
// to per-run llm_output + RunMetadata.
|
|
445
|
+
usage = mergeUsage(llmUsage, memUsage);
|
|
446
|
+
}
|
|
430
447
|
if (usage) {
|
|
431
|
-
|
|
448
|
+
data = { ...outgoingData, sessionUsage: usage };
|
|
432
449
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
completeAgentEventForward({
|
|
445
|
-
evt,
|
|
446
|
-
sk,
|
|
447
|
-
deviceIdRaw,
|
|
448
|
-
outgoingData: data,
|
|
449
|
-
isTerminalLifecycle: true,
|
|
450
|
-
subagentMeta,
|
|
451
|
-
});
|
|
452
|
-
}, 100);
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
450
|
+
completeAgentEventForward({
|
|
451
|
+
evt,
|
|
452
|
+
sk,
|
|
453
|
+
deviceIdRaw,
|
|
454
|
+
outgoingData: data,
|
|
455
|
+
isTerminalLifecycle: true,
|
|
456
|
+
subagentMeta,
|
|
457
|
+
});
|
|
458
|
+
}, 100);
|
|
459
|
+
return;
|
|
455
460
|
}
|
|
456
461
|
completeAgentEventForward({
|
|
457
462
|
evt,
|
package/package.json
CHANGED
|
@@ -200,8 +200,20 @@ describe("forwardAgentEventRaw (thinking delta rewrite)", () => {
|
|
|
200
200
|
expect("reasoningPrefixChars" in (payload.data as object)).toBe(false);
|
|
201
201
|
});
|
|
202
202
|
|
|
203
|
-
it("builds sessionUsage from
|
|
204
|
-
//
|
|
203
|
+
it("builds sessionUsage from store (cumulative) with llm_output fallback", async () => {
|
|
204
|
+
// No store entry — falls back to llm_output per-run data.
|
|
205
|
+
setFridayAgentForwardRuntime({
|
|
206
|
+
runtime: {
|
|
207
|
+
config: { current: () => ({ session: {} }) },
|
|
208
|
+
agent: {
|
|
209
|
+
session: {
|
|
210
|
+
resolveStorePath: () => "/tmp/sessions.json",
|
|
211
|
+
loadSessionStore: vi.fn(() => ({})),
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
} as never);
|
|
216
|
+
|
|
205
217
|
accumulateRunUsage(runId, { input: 100, output: 50, cacheRead: 10, total: 150 }, "my-model", "openai");
|
|
206
218
|
accumulateRunUsage(runId, { input: 30, output: 10, cacheRead: 0, total: 40 }, "my-model", "openai");
|
|
207
219
|
|
|
@@ -213,15 +225,18 @@ describe("forwardAgentEventRaw (thinking delta rewrite)", () => {
|
|
|
213
225
|
data: { phase: "end" },
|
|
214
226
|
});
|
|
215
227
|
|
|
216
|
-
//
|
|
228
|
+
// Deferred 100ms — not broadcast yet.
|
|
229
|
+
expect(sseEmitter.broadcastToRun).not.toHaveBeenCalled();
|
|
230
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 150));
|
|
231
|
+
|
|
217
232
|
expect(sseEmitter.broadcastToRun).toHaveBeenCalledTimes(1);
|
|
218
233
|
const forwarded = (sseEmitter.broadcastToRun as ReturnType<typeof vi.fn>).mock.calls[0][1].data;
|
|
219
234
|
expect(forwarded.stream).toBe("lifecycle");
|
|
220
235
|
const sessionUsage = (forwarded.data as Record<string, unknown>).sessionUsage as Record<string, unknown>;
|
|
221
236
|
expect(sessionUsage).toBeDefined();
|
|
237
|
+
// llm_output fallback — per-run totals.
|
|
222
238
|
expect(sessionUsage.modelId).toBe("my-model");
|
|
223
239
|
expect(sessionUsage.modelProvider).toBe("openai");
|
|
224
|
-
// Accumulated totals across both API calls.
|
|
225
240
|
expect((sessionUsage.tokens as Record<string, unknown>).input).toBe(130);
|
|
226
241
|
expect((sessionUsage.tokens as Record<string, unknown>).output).toBe(60);
|
|
227
242
|
expect((sessionUsage.tokens as Record<string, unknown>).cacheRead).toBe(10);
|
|
@@ -229,50 +244,63 @@ describe("forwardAgentEventRaw (thinking delta rewrite)", () => {
|
|
|
229
244
|
expect((sessionUsage.tokens as Record<string, unknown>).totalFresh).toBe(true);
|
|
230
245
|
});
|
|
231
246
|
|
|
232
|
-
it("
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
+
it("prefers store cumulative totals over llm_output per-run data", async () => {
|
|
248
|
+
const storeKey = toSessionStoreKey(sessionKey);
|
|
249
|
+
setFridayAgentForwardRuntime({
|
|
250
|
+
runtime: {
|
|
251
|
+
config: { current: () => ({ session: {} }) },
|
|
252
|
+
agent: {
|
|
253
|
+
session: {
|
|
254
|
+
resolveStorePath: () => "/tmp/sessions.json",
|
|
255
|
+
loadSessionStore: vi.fn(() => ({
|
|
256
|
+
[storeKey]: {
|
|
257
|
+
model: "store-model",
|
|
258
|
+
modelProvider: "old-provider",
|
|
259
|
+
inputTokens: 5000,
|
|
260
|
+
outputTokens: 2000,
|
|
261
|
+
totalTokens: 99999,
|
|
262
|
+
totalTokensFresh: true,
|
|
263
|
+
contextTokens: 128000,
|
|
264
|
+
estimatedCostUsd: 0.05,
|
|
265
|
+
cacheRead: 100,
|
|
266
|
+
cacheWrite: 50,
|
|
267
|
+
},
|
|
268
|
+
})),
|
|
269
|
+
},
|
|
270
|
+
},
|
|
247
271
|
},
|
|
248
|
-
});
|
|
272
|
+
} as never);
|
|
273
|
+
|
|
274
|
+
// llm_output has fresher model/provider but per-run (smaller) tokens.
|
|
275
|
+
accumulateRunUsage(runId, { input: 500, output: 100, cacheRead: 200, total: 800 }, "llm-model", "llm-provider");
|
|
249
276
|
|
|
250
277
|
forwardAgentEventRaw({
|
|
251
278
|
runId,
|
|
252
|
-
seq:
|
|
279
|
+
seq: 1,
|
|
253
280
|
stream: "lifecycle",
|
|
254
281
|
sessionKey,
|
|
255
282
|
data: { phase: "end" },
|
|
256
283
|
});
|
|
257
284
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
285
|
+
expect(sseEmitter.broadcastToRun).not.toHaveBeenCalled();
|
|
286
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 150));
|
|
287
|
+
|
|
288
|
+
expect(sseEmitter.broadcastToRun).toHaveBeenCalledTimes(1);
|
|
289
|
+
const forwarded = (sseEmitter.broadcastToRun as ReturnType<typeof vi.fn>).mock.calls[0][1].data;
|
|
290
|
+
const sessionUsage = (forwarded.data as Record<string, unknown>).sessionUsage as Record<string, unknown>;
|
|
263
291
|
expect(sessionUsage).toBeDefined();
|
|
264
|
-
//
|
|
265
|
-
expect(sessionUsage
|
|
266
|
-
expect(sessionUsage
|
|
267
|
-
expect((sessionUsage
|
|
268
|
-
|
|
269
|
-
expect(
|
|
270
|
-
expect(
|
|
271
|
-
|
|
272
|
-
expect((sessionUsage
|
|
292
|
+
// Store cumulative totals win.
|
|
293
|
+
expect((sessionUsage.tokens as Record<string, unknown>).input).toBe(5000);
|
|
294
|
+
expect((sessionUsage.tokens as Record<string, unknown>).output).toBe(2000);
|
|
295
|
+
expect((sessionUsage.tokens as Record<string, unknown>).total).toBe(99999);
|
|
296
|
+
// Model/provider from llm_output (fresher) override store.
|
|
297
|
+
expect(sessionUsage.modelId).toBe("llm-model");
|
|
298
|
+
expect(sessionUsage.modelProvider).toBe("llm-provider");
|
|
299
|
+
expect(sessionUsage.estimatedCostUsd).toBe(0.05);
|
|
300
|
+
expect((sessionUsage.context as Record<string, unknown>).windowMax).toBe(128000);
|
|
273
301
|
});
|
|
274
302
|
|
|
275
|
-
it("
|
|
303
|
+
it("uses store cumulative totals when llm_output has no data", async () => {
|
|
276
304
|
const storeKey = toSessionStoreKey(sessionKey);
|
|
277
305
|
const store: Record<string, Record<string, unknown>> = {
|
|
278
306
|
[storeKey]: {
|
package/src/friday-session.ts
CHANGED
|
@@ -483,38 +483,40 @@ export function forwardAgentEventRaw(evt: ForwardAgentEventArgs): void {
|
|
|
483
483
|
}
|
|
484
484
|
}
|
|
485
485
|
|
|
486
|
-
// Build sessionUsage:
|
|
487
|
-
if (isTerminalLifecycle) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const
|
|
486
|
+
// Build sessionUsage: store (cumulative session totals) → llm_output (per-run fallback).
|
|
487
|
+
if (isTerminalLifecycle && getFridayAgentForwardRuntime()) {
|
|
488
|
+
// Defer to let store write complete, then read cumulative totals.
|
|
489
|
+
// llm_output data is per-run; store is cumulative across rounds.
|
|
490
|
+
setTimeout(() => {
|
|
491
|
+
let data = outgoingData;
|
|
492
|
+
const storeUsage = tryReadSessionUsageFromStore(sk);
|
|
493
|
+
const llmUsage = consumeRunUsage(evt.runId);
|
|
494
|
+
const memUsage = buildSessionUsageFromRunMetadata(evt.runId);
|
|
495
|
+
let usage: FridaySessionUsagePayload | undefined;
|
|
496
|
+
if (storeUsage) {
|
|
497
|
+
// Store provides cumulative session totals. Supplement with
|
|
498
|
+
// fresher model/provider from llm_output when available.
|
|
499
|
+
usage = storeUsage;
|
|
500
|
+
if (llmUsage?.modelId) usage.modelId = llmUsage.modelId;
|
|
501
|
+
if (llmUsage?.modelProvider) usage.modelProvider = llmUsage.modelProvider;
|
|
502
|
+
} else {
|
|
503
|
+
// First message in session — store not yet written, fall back
|
|
504
|
+
// to per-run llm_output + RunMetadata.
|
|
505
|
+
usage = mergeUsage(llmUsage, memUsage);
|
|
506
|
+
}
|
|
494
507
|
if (usage) {
|
|
495
|
-
|
|
508
|
+
data = { ...outgoingData, sessionUsage: usage };
|
|
496
509
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
completeAgentEventForward({
|
|
508
|
-
evt,
|
|
509
|
-
sk,
|
|
510
|
-
deviceIdRaw,
|
|
511
|
-
outgoingData: data,
|
|
512
|
-
isTerminalLifecycle: true,
|
|
513
|
-
subagentMeta,
|
|
514
|
-
});
|
|
515
|
-
}, 100);
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
510
|
+
completeAgentEventForward({
|
|
511
|
+
evt,
|
|
512
|
+
sk,
|
|
513
|
+
deviceIdRaw,
|
|
514
|
+
outgoingData: data,
|
|
515
|
+
isTerminalLifecycle: true,
|
|
516
|
+
subagentMeta,
|
|
517
|
+
});
|
|
518
|
+
}, 100);
|
|
519
|
+
return;
|
|
518
520
|
}
|
|
519
521
|
|
|
520
522
|
completeAgentEventForward({
|