@dudousxd/nestjs-agent 1.36.1 → 1.37.0
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/README.md +2 -2
- package/dist/a2ui/index.cjs +11 -1
- package/dist/a2ui/index.cjs.map +1 -1
- package/dist/a2ui/index.d.cts +2 -2
- package/dist/a2ui/index.d.ts +2 -2
- package/dist/a2ui/index.js +11 -1
- package/dist/a2ui/index.js.map +1 -1
- package/dist/{chat-queue.service-CzXsKVb1.d.ts → chat-queue.service-YjiKVTKE.d.ts} +2 -2
- package/dist/{chat-queue.service-CF2fcJDx.d.cts → chat-queue.service-fopUN313.d.cts} +2 -2
- package/dist/durable/index.cjs +250 -50
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +6 -18
- package/dist/durable/index.d.ts +6 -18
- package/dist/durable/index.js +250 -50
- package/dist/durable/index.js.map +1 -1
- package/dist/{index-NF93YDF4.d.cts → index-4caNqEQ-.d.cts} +29 -6
- package/dist/{index-DpS9P7so.d.ts → index-yC_Ra3CE.d.ts} +29 -6
- package/dist/index.cjs +244 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -7
- package/dist/index.d.ts +19 -7
- package/dist/index.js +244 -47
- package/dist/index.js.map +1 -1
- package/dist/sink-redis/index.cjs +164 -18
- package/dist/sink-redis/index.cjs.map +1 -1
- package/dist/sink-redis/index.d.cts +36 -7
- package/dist/sink-redis/index.d.ts +36 -7
- package/dist/sink-redis/index.js +165 -19
- package/dist/sink-redis/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1676,6 +1676,26 @@ var RunNotActiveException = class extends import_common5.ConflictException {
|
|
|
1676
1676
|
}
|
|
1677
1677
|
};
|
|
1678
1678
|
|
|
1679
|
+
// src/thread-reads.ts
|
|
1680
|
+
function threadReads(store, threadId, separately) {
|
|
1681
|
+
const projecting = store;
|
|
1682
|
+
if (typeof projecting.threadSettings !== "function") {
|
|
1683
|
+
return separately;
|
|
1684
|
+
}
|
|
1685
|
+
let settings;
|
|
1686
|
+
const read = /* @__PURE__ */ __name(() => {
|
|
1687
|
+
settings ??= projecting.threadSettings?.(threadId) ?? Promise.resolve(null);
|
|
1688
|
+
return settings;
|
|
1689
|
+
}, "read");
|
|
1690
|
+
return {
|
|
1691
|
+
owner: /* @__PURE__ */ __name(async () => (await read())?.actorRef ?? null, "owner"),
|
|
1692
|
+
defaultAgent: /* @__PURE__ */ __name(async () => (await read())?.defaultAgent ?? null, "defaultAgent"),
|
|
1693
|
+
persona: /* @__PURE__ */ __name(async () => (await read())?.persona ?? null, "persona"),
|
|
1694
|
+
model: /* @__PURE__ */ __name(async () => (await read())?.model ?? null, "model")
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
__name(threadReads, "threadReads");
|
|
1698
|
+
|
|
1679
1699
|
// src/agent.service.ts
|
|
1680
1700
|
function _ts_decorate5(decorators, target, key, desc) {
|
|
1681
1701
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -1939,7 +1959,7 @@ var AgentService2 = class {
|
|
|
1939
1959
|
* else the thread's pinned one, else none. An agent the catalog locks to one model runs on it
|
|
1940
1960
|
* whatever was sent or pinned, and a send naming another model is refused.
|
|
1941
1961
|
*/
|
|
1942
|
-
async resolveModel(actor, agent, requested, threadId) {
|
|
1962
|
+
async resolveModel(actor, agent, requested, threadId, reads) {
|
|
1943
1963
|
const locked = this.models !== void 0 ? (await this.models.list({
|
|
1944
1964
|
actor,
|
|
1945
1965
|
agent
|
|
@@ -1950,7 +1970,7 @@ var AgentService2 = class {
|
|
|
1950
1970
|
}
|
|
1951
1971
|
return locked.model;
|
|
1952
1972
|
}
|
|
1953
|
-
const model = requested ?? (threadId !== void 0 ? await this.threadModel(threadId) : null);
|
|
1973
|
+
const model = requested ?? (threadId !== void 0 ? await (reads?.model() ?? this.threadModel(threadId)) : null);
|
|
1954
1974
|
if (model === null || model === void 0) {
|
|
1955
1975
|
return void 0;
|
|
1956
1976
|
}
|
|
@@ -2010,10 +2030,11 @@ var AgentService2 = class {
|
|
|
2010
2030
|
if ("proposalDecision" in decision) return decision;
|
|
2011
2031
|
}
|
|
2012
2032
|
await this.assertWithinQuota(params.actor);
|
|
2013
|
-
const
|
|
2033
|
+
const reads = params.threadId !== void 0 ? this.threadReads(params.threadId) : void 0;
|
|
2034
|
+
const target = this.deps.resolveAgent(await this.resolveAgentName(params.agentName, params.threadId, reads));
|
|
2014
2035
|
const agentName = target.agentName;
|
|
2015
|
-
const persona = await this.resolvePersona(agentName, params.personaId ?? target.persona, params.threadId);
|
|
2016
|
-
const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId);
|
|
2036
|
+
const persona = await this.resolvePersona(agentName, params.personaId ?? target.persona, params.threadId, reads);
|
|
2037
|
+
const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId, reads);
|
|
2017
2038
|
const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
|
|
2018
2039
|
let threadId = params.threadId;
|
|
2019
2040
|
if (threadId === void 0) {
|
|
@@ -2037,9 +2058,9 @@ var AgentService2 = class {
|
|
|
2037
2058
|
});
|
|
2038
2059
|
threadId = created.id;
|
|
2039
2060
|
} else {
|
|
2040
|
-
if (params.authorized !== true) await this.assertOwnsThread(params.actor, threadId);
|
|
2061
|
+
if (params.authorized !== true) await this.assertOwnsThread(params.actor, threadId, reads);
|
|
2041
2062
|
if (params.personaId !== void 0) {
|
|
2042
|
-
await this.pinThreadPersona(threadId, params.personaId);
|
|
2063
|
+
await this.pinThreadPersona(threadId, params.personaId, reads);
|
|
2043
2064
|
}
|
|
2044
2065
|
}
|
|
2045
2066
|
const input = {
|
|
@@ -2365,8 +2386,8 @@ var AgentService2 = class {
|
|
|
2365
2386
|
* {@link subscribeAs} instead: a runId is the only thing standing between a caller and another
|
|
2366
2387
|
* actor's answer, tool arguments and tool results.
|
|
2367
2388
|
*/
|
|
2368
|
-
subscribe(runId) {
|
|
2369
|
-
return this.deps.forAgent().sink.subscribe(runId);
|
|
2389
|
+
subscribe(runId, options) {
|
|
2390
|
+
return this.deps.forAgent().sink.subscribe(runId, options);
|
|
2370
2391
|
}
|
|
2371
2392
|
/**
|
|
2372
2393
|
* {@link subscribe}, gated the way {@link cancel} is: only the actor whose thread is currently
|
|
@@ -2374,9 +2395,9 @@ var AgentService2 = class {
|
|
|
2374
2395
|
* replayed — the runner clears the thread's active stream as the run ends, and that field is what
|
|
2375
2396
|
* ownership is derived from.
|
|
2376
2397
|
*/
|
|
2377
|
-
async subscribeAs(actor, runId) {
|
|
2398
|
+
async subscribeAs(actor, runId, options) {
|
|
2378
2399
|
await this.assertOwnsActiveStream(actor, runId);
|
|
2379
|
-
return this.subscribe(runId);
|
|
2400
|
+
return this.subscribe(runId, options);
|
|
2380
2401
|
}
|
|
2381
2402
|
/**
|
|
2382
2403
|
* Approve a parked action call as `actor`. Who may is the call's recorded approver's business
|
|
@@ -2529,9 +2550,28 @@ var AgentService2 = class {
|
|
|
2529
2550
|
await this.assertOwnsThread(actor, threadId);
|
|
2530
2551
|
return this.store.softDeleteThread(threadId);
|
|
2531
2552
|
}
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2553
|
+
/**
|
|
2554
|
+
* Copy a thread up to `fromMessageId` (inclusive) into a new one. By default only the thread's
|
|
2555
|
+
* owner may, and the copy is theirs. With `params.authorized`, the host has vouched for `actor`
|
|
2556
|
+
* (a share link it checked) and the copy is `actor`'s — see {@link ForkThreadParams}.
|
|
2557
|
+
*/
|
|
2558
|
+
async forkThread(actor, threadId, fromMessageId, params = {}) {
|
|
2559
|
+
if (params.authorized === true) {
|
|
2560
|
+
if (await this.store.ownerOfThread(threadId) === null) {
|
|
2561
|
+
throw new import_common6.NotFoundException(`thread ${threadId} not found`);
|
|
2562
|
+
}
|
|
2563
|
+
} else {
|
|
2564
|
+
await this.assertOwnsThread(actor, threadId);
|
|
2565
|
+
}
|
|
2566
|
+
const options = {
|
|
2567
|
+
...params.authorized === true ? {
|
|
2568
|
+
actorRef: actor.id
|
|
2569
|
+
} : {},
|
|
2570
|
+
...params.tenantRef !== void 0 ? {
|
|
2571
|
+
tenantRef: params.tenantRef
|
|
2572
|
+
} : {}
|
|
2573
|
+
};
|
|
2574
|
+
return this.store.forkThread(threadId, fromMessageId, options);
|
|
2535
2575
|
}
|
|
2536
2576
|
/** Kept for source compatibility — a thin wrapper over the more general `updateThread`. */
|
|
2537
2577
|
async renameThread(actor, threadId, title) {
|
|
@@ -2583,7 +2623,7 @@ var AgentService2 = class {
|
|
|
2583
2623
|
* The persona this send runs under — see {@link AgentDepsFactory.resolvePersona}. The thread's
|
|
2584
2624
|
* pinned persona is read only when the send names none AND the agent has personas to pick from.
|
|
2585
2625
|
*/
|
|
2586
|
-
async resolvePersona(agentName, requested, threadId) {
|
|
2626
|
+
async resolvePersona(agentName, requested, threadId, reads) {
|
|
2587
2627
|
const needsThread = requested === void 0 && threadId !== void 0 && this.deps.personaCatalog(agentName).length > 0;
|
|
2588
2628
|
return this.deps.resolvePersona({
|
|
2589
2629
|
agentName,
|
|
@@ -2591,16 +2631,16 @@ var AgentService2 = class {
|
|
|
2591
2631
|
requested
|
|
2592
2632
|
} : {},
|
|
2593
2633
|
...needsThread ? {
|
|
2594
|
-
threadPersona: await threadPersona(this.store, threadId)
|
|
2634
|
+
threadPersona: await (reads?.persona() ?? threadPersona(this.store, threadId))
|
|
2595
2635
|
} : {}
|
|
2596
2636
|
});
|
|
2597
2637
|
}
|
|
2598
2638
|
/** Pin `persona` on the thread when it is not already — a no-op on a store that cannot. */
|
|
2599
|
-
async pinThreadPersona(threadId, persona) {
|
|
2639
|
+
async pinThreadPersona(threadId, persona, reads) {
|
|
2600
2640
|
if (this.store.updateThread === void 0) {
|
|
2601
2641
|
return;
|
|
2602
2642
|
}
|
|
2603
|
-
if (await threadPersona(this.store, threadId) !== persona) {
|
|
2643
|
+
if (await (reads?.persona() ?? threadPersona(this.store, threadId)) !== persona) {
|
|
2604
2644
|
await this.store.updateThread(threadId, {
|
|
2605
2645
|
persona
|
|
2606
2646
|
});
|
|
@@ -2627,18 +2667,27 @@ var AgentService2 = class {
|
|
|
2627
2667
|
* workflow, for a string. A store predating {@link ThreadDefaultAgentReader} still answers, via
|
|
2628
2668
|
* the full read.
|
|
2629
2669
|
*/
|
|
2630
|
-
async resolveAgentName(agentName, threadId) {
|
|
2670
|
+
async resolveAgentName(agentName, threadId, reads) {
|
|
2631
2671
|
if (agentName !== void 0) {
|
|
2632
2672
|
return agentName;
|
|
2633
2673
|
}
|
|
2634
2674
|
if (threadId !== void 0) {
|
|
2635
|
-
const threadDefault = await this.threadDefaultAgent(threadId);
|
|
2675
|
+
const threadDefault = await (reads?.defaultAgent() ?? this.threadDefaultAgent(threadId));
|
|
2636
2676
|
if (threadDefault !== null) {
|
|
2637
2677
|
return threadDefault;
|
|
2638
2678
|
}
|
|
2639
2679
|
}
|
|
2640
2680
|
return this.deps.defaultAgentName();
|
|
2641
2681
|
}
|
|
2682
|
+
/** Everything a send reads off `threadId`, in one read where the store allows it. */
|
|
2683
|
+
threadReads(threadId) {
|
|
2684
|
+
return threadReads(this.store, threadId, {
|
|
2685
|
+
owner: /* @__PURE__ */ __name(() => this.store.ownerOfThread(threadId), "owner"),
|
|
2686
|
+
defaultAgent: /* @__PURE__ */ __name(() => this.threadDefaultAgent(threadId), "defaultAgent"),
|
|
2687
|
+
persona: /* @__PURE__ */ __name(() => threadPersona(this.store, threadId), "persona"),
|
|
2688
|
+
model: /* @__PURE__ */ __name(() => this.threadModel(threadId), "model")
|
|
2689
|
+
});
|
|
2690
|
+
}
|
|
2642
2691
|
async threadDefaultAgent(threadId) {
|
|
2643
2692
|
const projecting = this.store;
|
|
2644
2693
|
if (typeof projecting.defaultAgentForThread === "function") {
|
|
@@ -2808,8 +2857,8 @@ var AgentService2 = class {
|
|
|
2808
2857
|
* Authorization seam for thread-scoped endpoints: the caller must own the thread. A missing
|
|
2809
2858
|
* thread is a 404; someone else's thread is a 403 — one actor never touches another's thread.
|
|
2810
2859
|
*/
|
|
2811
|
-
async assertOwnsThread(actor, threadId) {
|
|
2812
|
-
const owner = await this.store.ownerOfThread(threadId);
|
|
2860
|
+
async assertOwnsThread(actor, threadId, reads) {
|
|
2861
|
+
const owner = await (reads?.owner() ?? this.store.ownerOfThread(threadId));
|
|
2813
2862
|
if (owner === null) {
|
|
2814
2863
|
throw new import_common6.NotFoundException(`thread ${threadId} not found`);
|
|
2815
2864
|
}
|
|
@@ -3249,6 +3298,18 @@ AttachmentsController = _ts_decorate8([
|
|
|
3249
3298
|
var import_nestjs_agent_core12 = require("@dudousxd/nestjs-agent-core");
|
|
3250
3299
|
var import_genui2 = require("@dudousxd/nestjs-agent-core/genui");
|
|
3251
3300
|
var import_common10 = require("@nestjs/common");
|
|
3301
|
+
|
|
3302
|
+
// src/controller/reader-gone.ts
|
|
3303
|
+
function readerGone(res) {
|
|
3304
|
+
const controller = new AbortController();
|
|
3305
|
+
res.once("close", () => controller.abort());
|
|
3306
|
+
return {
|
|
3307
|
+
signal: controller.signal
|
|
3308
|
+
};
|
|
3309
|
+
}
|
|
3310
|
+
__name(readerGone, "readerGone");
|
|
3311
|
+
|
|
3312
|
+
// src/controller/chat.controller.ts
|
|
3252
3313
|
function _ts_decorate9(decorators, target, key, desc) {
|
|
3253
3314
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3254
3315
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -3382,7 +3443,8 @@ var ChatController = class {
|
|
|
3382
3443
|
return;
|
|
3383
3444
|
}
|
|
3384
3445
|
const { runId, threadId } = result;
|
|
3385
|
-
|
|
3446
|
+
const gone = readerGone(res);
|
|
3447
|
+
await this.pipe(res, runId, this.agent.subscribe(runId, gone), threadId, 0, gone.signal);
|
|
3386
3448
|
}
|
|
3387
3449
|
/**
|
|
3388
3450
|
* Attach to a run's stream: every buffered frame, then live ones. `?after=<seq>` (or the SSE
|
|
@@ -3392,7 +3454,8 @@ var ChatController = class {
|
|
|
3392
3454
|
async stream(req, runId, res, after) {
|
|
3393
3455
|
const actor = await this.actorResolver.resolve(req);
|
|
3394
3456
|
const cursor = parseCursor(after) ?? parseCursor(req.headers["last-event-id"]) ?? 0;
|
|
3395
|
-
|
|
3457
|
+
const gone = readerGone(res);
|
|
3458
|
+
await this.pipe(res, runId, await this.agent.subscribeAs(actor, runId, gone), void 0, cursor, gone.signal);
|
|
3396
3459
|
}
|
|
3397
3460
|
async cancel(req, runId) {
|
|
3398
3461
|
const actor = await this.actorResolver.resolve(req);
|
|
@@ -3408,8 +3471,11 @@ var ChatController = class {
|
|
|
3408
3471
|
* and on any later `GET …/stream`, whichever replica serves it. A reconnecting client passes the
|
|
3409
3472
|
* last one it saw as `?after=`; frames at or below it are read off the sink but not re-sent.
|
|
3410
3473
|
* `meta`, `done` and `error` carry no id: `meta` is re-sent on every attach, the terminals once.
|
|
3474
|
+
*
|
|
3475
|
+
* A reader that disconnects aborts `gone`, which the sink honours by ending the subscription even
|
|
3476
|
+
* while the run is silent (parked on a person, or never writing again).
|
|
3411
3477
|
*/
|
|
3412
|
-
async pipe(res, runId, events, threadId, after = 0) {
|
|
3478
|
+
async pipe(res, runId, events, threadId, after = 0, gone) {
|
|
3413
3479
|
res.setHeader("Content-Type", "text/event-stream");
|
|
3414
3480
|
res.setHeader("Cache-Control", "no-cache");
|
|
3415
3481
|
res.setHeader("Connection", "keep-alive");
|
|
@@ -3438,6 +3504,9 @@ data: ${line}
|
|
|
3438
3504
|
}, "forward");
|
|
3439
3505
|
try {
|
|
3440
3506
|
for await (const chunk of events) {
|
|
3507
|
+
if (gone?.aborted) {
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3441
3510
|
buffer += decoder.decode(chunk, {
|
|
3442
3511
|
stream: true
|
|
3443
3512
|
});
|
|
@@ -3451,11 +3520,17 @@ data: ${line}
|
|
|
3451
3520
|
newline = buffer.indexOf("\n");
|
|
3452
3521
|
}
|
|
3453
3522
|
}
|
|
3523
|
+
if (gone?.aborted) {
|
|
3524
|
+
return;
|
|
3525
|
+
}
|
|
3454
3526
|
if (buffer.length > 0) {
|
|
3455
3527
|
forward(buffer);
|
|
3456
3528
|
}
|
|
3457
3529
|
res.write("event: done\ndata: {}\n\n");
|
|
3458
3530
|
} catch (error) {
|
|
3531
|
+
if (gone?.aborted) {
|
|
3532
|
+
return;
|
|
3533
|
+
}
|
|
3459
3534
|
const payload = error instanceof import_nestjs_agent_core12.AgentStreamError ? {
|
|
3460
3535
|
code: error.code,
|
|
3461
3536
|
message: error.message
|
|
@@ -5385,49 +5460,121 @@ SkillDiscoveryService = _ts_decorate22([
|
|
|
5385
5460
|
|
|
5386
5461
|
// src/in-process-sink.ts
|
|
5387
5462
|
var import_nestjs_agent_core27 = require("@dudousxd/nestjs-agent-core");
|
|
5463
|
+
var LIVE_TTL_MS = 36e5;
|
|
5464
|
+
var ENDED_GRACE_MS = 6e4;
|
|
5388
5465
|
var InProcessTokenStreamSink = class {
|
|
5389
5466
|
static {
|
|
5390
5467
|
__name(this, "InProcessTokenStreamSink");
|
|
5391
5468
|
}
|
|
5392
5469
|
runs = /* @__PURE__ */ new Map();
|
|
5470
|
+
/** Subscribers of a run nothing has opened yet, woken by its `open()`. */
|
|
5471
|
+
waiting = /* @__PURE__ */ new Map();
|
|
5393
5472
|
buffer(runId) {
|
|
5394
5473
|
let buf = this.runs.get(runId);
|
|
5395
5474
|
if (buf === void 0) {
|
|
5396
5475
|
buf = {
|
|
5397
5476
|
chunks: [],
|
|
5398
5477
|
ended: false,
|
|
5399
|
-
notify: /* @__PURE__ */ new Set()
|
|
5478
|
+
notify: /* @__PURE__ */ new Set(),
|
|
5479
|
+
lastWriteAt: Date.now(),
|
|
5480
|
+
expiry: void 0
|
|
5400
5481
|
};
|
|
5401
5482
|
this.runs.set(runId, buf);
|
|
5483
|
+
this.expireAfter(runId, buf, LIVE_TTL_MS);
|
|
5484
|
+
const waiters = this.waiting.get(runId);
|
|
5485
|
+
this.waiting.delete(runId);
|
|
5486
|
+
for (const resolve2 of waiters ?? []) {
|
|
5487
|
+
resolve2();
|
|
5488
|
+
}
|
|
5402
5489
|
}
|
|
5403
5490
|
return buf;
|
|
5404
5491
|
}
|
|
5492
|
+
expireAfter(runId, buf, ms) {
|
|
5493
|
+
if (buf.expiry !== void 0) {
|
|
5494
|
+
clearTimeout(buf.expiry);
|
|
5495
|
+
}
|
|
5496
|
+
buf.expiry = setTimeout(() => {
|
|
5497
|
+
buf.expiry = void 0;
|
|
5498
|
+
const idle = Date.now() - buf.lastWriteAt;
|
|
5499
|
+
if (!buf.ended && idle < LIVE_TTL_MS) {
|
|
5500
|
+
this.expireAfter(runId, buf, LIVE_TTL_MS - idle);
|
|
5501
|
+
return;
|
|
5502
|
+
}
|
|
5503
|
+
this.drop(runId, buf);
|
|
5504
|
+
}, ms);
|
|
5505
|
+
buf.expiry.unref?.();
|
|
5506
|
+
}
|
|
5507
|
+
/** Forget the run, and let anyone still following it finish as if it had ended. */
|
|
5508
|
+
drop(runId, buf) {
|
|
5509
|
+
if (buf.expiry !== void 0) {
|
|
5510
|
+
clearTimeout(buf.expiry);
|
|
5511
|
+
buf.expiry = void 0;
|
|
5512
|
+
}
|
|
5513
|
+
if (this.runs.get(runId) === buf) {
|
|
5514
|
+
this.runs.delete(runId);
|
|
5515
|
+
}
|
|
5516
|
+
buf.ended = true;
|
|
5517
|
+
this.wake(buf);
|
|
5518
|
+
}
|
|
5405
5519
|
wake(buf) {
|
|
5406
5520
|
for (const resolve2 of buf.notify) {
|
|
5407
5521
|
resolve2();
|
|
5408
5522
|
}
|
|
5409
5523
|
buf.notify.clear();
|
|
5410
5524
|
}
|
|
5525
|
+
finish(runId, buf) {
|
|
5526
|
+
buf.ended = true;
|
|
5527
|
+
this.wake(buf);
|
|
5528
|
+
this.expireAfter(runId, buf, ENDED_GRACE_MS);
|
|
5529
|
+
}
|
|
5530
|
+
/**
|
|
5531
|
+
* The run's writer. Each call finds the run's buffer afresh, so a run that went quiet past the
|
|
5532
|
+
* live TTL (parked on a person) and then writes again starts a new buffer its next subscriber
|
|
5533
|
+
* follows, rather than writing into one nothing reads.
|
|
5534
|
+
*/
|
|
5411
5535
|
open(runId) {
|
|
5412
|
-
|
|
5536
|
+
this.buffer(runId);
|
|
5413
5537
|
return {
|
|
5414
5538
|
write: /* @__PURE__ */ __name((chunk) => {
|
|
5539
|
+
const buf = this.buffer(runId);
|
|
5415
5540
|
buf.chunks.push(chunk);
|
|
5541
|
+
buf.lastWriteAt = Date.now();
|
|
5416
5542
|
this.wake(buf);
|
|
5417
5543
|
}, "write"),
|
|
5418
5544
|
end: /* @__PURE__ */ __name(() => {
|
|
5419
|
-
|
|
5420
|
-
this.wake(buf);
|
|
5545
|
+
this.finish(runId, this.buffer(runId));
|
|
5421
5546
|
}, "end"),
|
|
5422
5547
|
fail: /* @__PURE__ */ __name((error) => {
|
|
5548
|
+
const buf = this.buffer(runId);
|
|
5423
5549
|
buf.failure = error;
|
|
5424
|
-
|
|
5425
|
-
this.wake(buf);
|
|
5550
|
+
this.finish(runId, buf);
|
|
5426
5551
|
}, "fail")
|
|
5427
5552
|
};
|
|
5428
5553
|
}
|
|
5429
|
-
async *subscribe(runId) {
|
|
5430
|
-
const
|
|
5554
|
+
async *subscribe(runId, options = {}) {
|
|
5555
|
+
const { signal } = options;
|
|
5556
|
+
let buf = this.runs.get(runId);
|
|
5557
|
+
while (buf === void 0) {
|
|
5558
|
+
const waiters = this.waiting.get(runId) ?? /* @__PURE__ */ new Set();
|
|
5559
|
+
this.waiting.set(runId, waiters);
|
|
5560
|
+
let resolve2 = /* @__PURE__ */ __name(() => {
|
|
5561
|
+
}, "resolve");
|
|
5562
|
+
const opened = new Promise((r) => {
|
|
5563
|
+
resolve2 = r;
|
|
5564
|
+
});
|
|
5565
|
+
waiters.add(resolve2);
|
|
5566
|
+
try {
|
|
5567
|
+
if (!await untilAborted(opened, signal)) {
|
|
5568
|
+
return;
|
|
5569
|
+
}
|
|
5570
|
+
} finally {
|
|
5571
|
+
waiters.delete(resolve2);
|
|
5572
|
+
if (waiters.size === 0 && this.waiting.get(runId) === waiters) {
|
|
5573
|
+
this.waiting.delete(runId);
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
buf = this.runs.get(runId);
|
|
5577
|
+
}
|
|
5431
5578
|
let index = 0;
|
|
5432
5579
|
while (true) {
|
|
5433
5580
|
while (index < buf.chunks.length) {
|
|
@@ -5443,13 +5590,56 @@ var InProcessTokenStreamSink = class {
|
|
|
5443
5590
|
}
|
|
5444
5591
|
return;
|
|
5445
5592
|
}
|
|
5446
|
-
|
|
5593
|
+
const current = buf;
|
|
5594
|
+
let resolve2 = /* @__PURE__ */ __name(() => {
|
|
5595
|
+
}, "resolve");
|
|
5596
|
+
const woken = new Promise((r) => {
|
|
5597
|
+
resolve2 = r;
|
|
5598
|
+
});
|
|
5599
|
+
current.notify.add(resolve2);
|
|
5600
|
+
try {
|
|
5601
|
+
if (!await untilAborted(woken, signal)) {
|
|
5602
|
+
return;
|
|
5603
|
+
}
|
|
5604
|
+
} finally {
|
|
5605
|
+
current.notify.delete(resolve2);
|
|
5606
|
+
}
|
|
5447
5607
|
}
|
|
5448
5608
|
}
|
|
5449
5609
|
close(runId) {
|
|
5610
|
+
const buf = this.runs.get(runId);
|
|
5611
|
+
if (buf?.expiry !== void 0) {
|
|
5612
|
+
clearTimeout(buf.expiry);
|
|
5613
|
+
}
|
|
5450
5614
|
this.runs.delete(runId);
|
|
5451
5615
|
}
|
|
5452
5616
|
};
|
|
5617
|
+
async function untilAborted(promise, signal) {
|
|
5618
|
+
if (signal === void 0) {
|
|
5619
|
+
await promise;
|
|
5620
|
+
return true;
|
|
5621
|
+
}
|
|
5622
|
+
if (signal.aborted) {
|
|
5623
|
+
return false;
|
|
5624
|
+
}
|
|
5625
|
+
let onAbort = /* @__PURE__ */ __name(() => {
|
|
5626
|
+
}, "onAbort");
|
|
5627
|
+
const aborted = new Promise((resolve2) => {
|
|
5628
|
+
onAbort = /* @__PURE__ */ __name(() => resolve2(false), "onAbort");
|
|
5629
|
+
signal.addEventListener("abort", onAbort, {
|
|
5630
|
+
once: true
|
|
5631
|
+
});
|
|
5632
|
+
});
|
|
5633
|
+
try {
|
|
5634
|
+
return await Promise.race([
|
|
5635
|
+
promise.then(() => true),
|
|
5636
|
+
aborted
|
|
5637
|
+
]);
|
|
5638
|
+
} finally {
|
|
5639
|
+
signal.removeEventListener("abort", onAbort);
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
__name(untilAborted, "untilAborted");
|
|
5453
5643
|
|
|
5454
5644
|
// src/ledger-quota-provider.ts
|
|
5455
5645
|
var import_nestjs_agent_core28 = require("@dudousxd/nestjs-agent-core");
|
|
@@ -5468,13 +5658,22 @@ var LedgerQuotaProvider = class {
|
|
|
5468
5658
|
async report(query) {
|
|
5469
5659
|
const now = query.now ?? /* @__PURE__ */ new Date();
|
|
5470
5660
|
const actorRef = query.actor.id;
|
|
5471
|
-
const
|
|
5472
|
-
|
|
5473
|
-
];
|
|
5474
|
-
if (this.store.
|
|
5475
|
-
const
|
|
5476
|
-
|
|
5477
|
-
|
|
5661
|
+
const day = (0, import_nestjs_agent_core28.quotaPeriodRange)("day", now);
|
|
5662
|
+
const month = (0, import_nestjs_agent_core28.quotaPeriodRange)("month", now);
|
|
5663
|
+
const windows = [];
|
|
5664
|
+
if (this.store.usageWindows !== void 0) {
|
|
5665
|
+
const [dayUsed, monthUsed] = await this.store.usageWindows(actorRef, [
|
|
5666
|
+
day,
|
|
5667
|
+
month
|
|
5668
|
+
]);
|
|
5669
|
+
windows.push(this.usedWindow("day", dayUsed, day.resetsAt));
|
|
5670
|
+
windows.push(this.usedWindow("month", monthUsed, month.resetsAt));
|
|
5671
|
+
} else {
|
|
5672
|
+
windows.push(this.usedWindow("day", await this.store.quotaToday(actorRef, day.fromDay), day.resetsAt));
|
|
5673
|
+
if (this.store.usageBetween !== void 0) {
|
|
5674
|
+
const used = await this.store.usageBetween(actorRef, month.fromDay, month.toDay);
|
|
5675
|
+
windows.push(this.usedWindow("month", used, month.resetsAt));
|
|
5676
|
+
}
|
|
5478
5677
|
}
|
|
5479
5678
|
const blocked = (0, import_nestjs_agent_core28.exhaustedWindow)(windows);
|
|
5480
5679
|
const warning = (0, import_nestjs_agent_core28.quotaWarning)(windows);
|
|
@@ -5488,10 +5687,8 @@ var LedgerQuotaProvider = class {
|
|
|
5488
5687
|
} : {}
|
|
5489
5688
|
};
|
|
5490
5689
|
}
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
const used = await this.store.quotaToday(actorRef, range.fromDay);
|
|
5494
|
-
return this.window("day", used.usedTokens, this.usd(used), range.resetsAt);
|
|
5690
|
+
usedWindow(period, used, resetsAt) {
|
|
5691
|
+
return this.window(period, used?.usedTokens ?? 0, used === void 0 ? 0 : this.usd(used), resetsAt);
|
|
5495
5692
|
}
|
|
5496
5693
|
/** The window's USD: every priced row, or (with `countEstimatedCost: false`) reported cost only. */
|
|
5497
5694
|
usd(used) {
|
|
@@ -7336,7 +7533,7 @@ var AgUiRunHandler = class {
|
|
|
7336
7533
|
seq: 0
|
|
7337
7534
|
};
|
|
7338
7535
|
try {
|
|
7339
|
-
const frames = (0, import_ag_ui.agUiFramesFromNdjson)(this.agent.subscribe(runId));
|
|
7536
|
+
const frames = (0, import_ag_ui.agUiFramesFromNdjson)(this.agent.subscribe(runId, readerGone(res)));
|
|
7340
7537
|
for await (const event of (0, import_ag_ui.agUiEvents)(frames, {
|
|
7341
7538
|
...options,
|
|
7342
7539
|
cursor
|
|
@@ -7667,7 +7864,7 @@ var A2uiRunHandler = class {
|
|
|
7667
7864
|
`);
|
|
7668
7865
|
}, "write");
|
|
7669
7866
|
try {
|
|
7670
|
-
const frames = (0, import_ag_ui2.agUiFramesFromNdjson)(this.agent.subscribe(runId));
|
|
7867
|
+
const frames = (0, import_ag_ui2.agUiFramesFromNdjson)(this.agent.subscribe(runId, readerGone(res)));
|
|
7671
7868
|
for await (const event of (0, import_ag_ui2.agUiEvents)(frames, {
|
|
7672
7869
|
threadId: options.threadId ?? runId,
|
|
7673
7870
|
runId,
|