@dudousxd/nestjs-agent-core 0.37.0 → 0.38.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/dist/index.cjs CHANGED
@@ -91,6 +91,7 @@ __export(src_exports, {
91
91
  SCHEMA_EXTENSION: () => SCHEMA_EXTENSION,
92
92
  SKILL_TOOL_DESCRIPTION: () => SKILL_TOOL_DESCRIPTION,
93
93
  SKILL_TOOL_NAME: () => SKILL_TOOL_NAME,
94
+ SqlTokenStreamSink: () => SqlTokenStreamSink,
94
95
  StructuredOutputError: () => StructuredOutputError,
95
96
  THREAD_DETAIL_CONTENT_CHARS: () => THREAD_DETAIL_CONTENT_CHARS,
96
97
  ToolDisabledError: () => ToolDisabledError,
@@ -321,7 +322,7 @@ __name(decodeStreamEvent, "decodeStreamEvent");
321
322
 
322
323
  // src/turn-frames.ts
323
324
  function observeTurnFrames(writer, now = Date.now) {
324
- const decoder2 = new TextDecoder();
325
+ const decoder3 = new TextDecoder();
325
326
  let pending = "";
326
327
  let reasoning = "";
327
328
  let reasoningMs = 0;
@@ -361,7 +362,7 @@ function observeTurnFrames(writer, now = Date.now) {
361
362
  }
362
363
  __name(observeLine, "observeLine");
363
364
  function observe(chunk) {
364
- pending += decoder2.decode(chunk, {
365
+ pending += decoder3.decode(chunk, {
365
366
  stream: true
366
367
  });
367
368
  let newline = pending.indexOf("\n");
@@ -6330,6 +6331,245 @@ function defineConfirmedTool(options, steps) {
6330
6331
  };
6331
6332
  }
6332
6333
  __name(defineConfirmedTool, "defineConfirmedTool");
6334
+
6335
+ // src/sql-token-stream-sink.ts
6336
+ var DEFAULT_TTL_SECONDS = 3600;
6337
+ var DEFAULT_POLL_INTERVAL_MS = 250;
6338
+ var DEFAULT_IDLE_POLL_INTERVAL_MS = 1e3;
6339
+ var IDLE_AFTER_MS = 5e3;
6340
+ var DEFAULT_FLUSH_MS = 50;
6341
+ var READ_PAGE = 500;
6342
+ var PURGE_CHUNK = 200;
6343
+ var AUTO_PURGE_EVERY_MS = 6e4;
6344
+ var APPEND_ATTEMPTS = 8;
6345
+ var decoder2 = new TextDecoder();
6346
+ var encoder2 = new TextEncoder();
6347
+ var sleep = /* @__PURE__ */ __name((ms) => new Promise((resolve) => setTimeout(resolve, ms)), "sleep");
6348
+ function textOf(line) {
6349
+ if (!line.startsWith('{"kind":"text"')) return null;
6350
+ try {
6351
+ const parsed = JSON.parse(line);
6352
+ if (typeof parsed === "object" && parsed !== null && Object.keys(parsed).length === 2 && parsed.kind === "text" && typeof parsed.text === "string") {
6353
+ return parsed.text;
6354
+ }
6355
+ } catch {
6356
+ }
6357
+ return null;
6358
+ }
6359
+ __name(textOf, "textOf");
6360
+ var SqlTokenStreamSink = class {
6361
+ static {
6362
+ __name(this, "SqlTokenStreamSink");
6363
+ }
6364
+ table;
6365
+ pollIntervalMs;
6366
+ idlePollIntervalMs;
6367
+ flushMs;
6368
+ ttlSeconds;
6369
+ autoPurge;
6370
+ writes = /* @__PURE__ */ new Map();
6371
+ lastAutoPurge = 0;
6372
+ constructor(table, options = {}) {
6373
+ this.table = table;
6374
+ this.pollIntervalMs = Math.max(1, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
6375
+ this.idlePollIntervalMs = Math.max(this.pollIntervalMs, options.idlePollIntervalMs ?? DEFAULT_IDLE_POLL_INTERVAL_MS);
6376
+ this.flushMs = Math.max(0, options.flushMs ?? DEFAULT_FLUSH_MS);
6377
+ this.ttlSeconds = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;
6378
+ this.autoPurge = options.autoPurge ?? true;
6379
+ }
6380
+ runWrites(runId) {
6381
+ let state = this.writes.get(runId);
6382
+ if (state === void 0) {
6383
+ state = {
6384
+ text: null,
6385
+ timer: void 0,
6386
+ tail: Promise.resolve(),
6387
+ pending: 0,
6388
+ failure: void 0
6389
+ };
6390
+ this.writes.set(runId, state);
6391
+ }
6392
+ return state;
6393
+ }
6394
+ /** Forget a run's write state once nothing is gathered, queued or left to report. */
6395
+ release(runId, state) {
6396
+ if (state.pending === 0 && state.text === null && state.failure === void 0 && this.writes.get(runId) === state) {
6397
+ this.writes.delete(runId);
6398
+ }
6399
+ }
6400
+ /** Queue `work` behind every write already queued for the run, so rows land in call order. */
6401
+ enqueue(runId, state, work) {
6402
+ state.pending += 1;
6403
+ const next = state.tail.then(work);
6404
+ state.tail = next.then(() => void 0, () => void 0).then(() => {
6405
+ state.pending -= 1;
6406
+ this.release(runId, state);
6407
+ });
6408
+ return next;
6409
+ }
6410
+ /** Queue the gathered text (if any) as one `text` row. */
6411
+ flushText(runId, state) {
6412
+ if (state.timer !== void 0) {
6413
+ clearTimeout(state.timer);
6414
+ state.timer = void 0;
6415
+ }
6416
+ if (state.text === null) return Promise.resolve();
6417
+ const line = decoder2.decode(encodeStreamEvent({
6418
+ kind: "text",
6419
+ text: state.text
6420
+ }));
6421
+ state.text = null;
6422
+ return this.enqueue(runId, state, () => this.append(runId, line, null));
6423
+ }
6424
+ /** Raise, once, a gathered write that failed with nobody awaiting it. */
6425
+ raiseFailure(state) {
6426
+ const failure = state.failure;
6427
+ if (failure !== void 0) {
6428
+ state.failure = void 0;
6429
+ throw failure.error;
6430
+ }
6431
+ }
6432
+ /** Append one row — a frame, or the terminal row (`frame: null`, with `error` on a failure). */
6433
+ async append(runId, frame, error) {
6434
+ for (let attempt = 1; ; attempt += 1) {
6435
+ try {
6436
+ await this.table.append(runId, {
6437
+ frame,
6438
+ error,
6439
+ createdAt: Date.now()
6440
+ });
6441
+ return;
6442
+ } catch (caught) {
6443
+ if (attempt >= APPEND_ATTEMPTS || !this.table.isUniqueViolation(caught)) throw caught;
6444
+ }
6445
+ }
6446
+ }
6447
+ /** Write out what is gathered, then a terminal row; raise a failure nobody saw. */
6448
+ async terminate(runId, error) {
6449
+ const state = this.runWrites(runId);
6450
+ const flushed = this.flushText(runId, state);
6451
+ const ended = this.enqueue(runId, state, () => this.append(runId, null, error));
6452
+ await Promise.all([
6453
+ flushed,
6454
+ ended
6455
+ ]);
6456
+ this.raiseFailure(state);
6457
+ this.release(runId, state);
6458
+ this.purgeInBackground();
6459
+ }
6460
+ /**
6461
+ * The run's writer. Writers opened for the same run in one process share what they are gathering,
6462
+ * so a delegated run's text (forwarded through a child writer) and its parent's next frame keep
6463
+ * the order they were written in.
6464
+ */
6465
+ open(runId) {
6466
+ return {
6467
+ write: /* @__PURE__ */ __name(async (chunk) => {
6468
+ const state = this.runWrites(runId);
6469
+ this.raiseFailure(state);
6470
+ const line = decoder2.decode(chunk);
6471
+ const text = this.flushMs > 0 ? textOf(line.trimEnd()) : null;
6472
+ if (text !== null) {
6473
+ state.text = (state.text ?? "") + text;
6474
+ if (state.timer === void 0) {
6475
+ state.timer = setTimeout(() => {
6476
+ state.timer = void 0;
6477
+ this.flushText(runId, state).catch((error) => {
6478
+ state.failure = {
6479
+ error
6480
+ };
6481
+ });
6482
+ }, this.flushMs);
6483
+ }
6484
+ return;
6485
+ }
6486
+ const flushed = this.flushText(runId, state);
6487
+ const appended = this.enqueue(runId, state, () => this.append(runId, line, null));
6488
+ await Promise.all([
6489
+ flushed,
6490
+ appended
6491
+ ]);
6492
+ }, "write"),
6493
+ flush: /* @__PURE__ */ __name(async () => {
6494
+ const state = this.runWrites(runId);
6495
+ const flushed = this.flushText(runId, state);
6496
+ await Promise.all([
6497
+ flushed,
6498
+ state.tail
6499
+ ]);
6500
+ this.raiseFailure(state);
6501
+ this.release(runId, state);
6502
+ }, "flush"),
6503
+ end: /* @__PURE__ */ __name(() => this.terminate(runId, null), "end"),
6504
+ fail: /* @__PURE__ */ __name((error) => this.terminate(runId, JSON.stringify({
6505
+ code: error.code,
6506
+ message: error.message
6507
+ })), "fail")
6508
+ };
6509
+ }
6510
+ async *subscribe(runId) {
6511
+ let cursor = 0;
6512
+ let quietSince = Date.now();
6513
+ while (true) {
6514
+ const rows = await this.table.read(runId, cursor, READ_PAGE);
6515
+ for (const row of rows) {
6516
+ cursor = row.seq;
6517
+ if (row.frame === null) {
6518
+ if (row.error !== null) {
6519
+ throw new AgentStreamError(JSON.parse(row.error));
6520
+ }
6521
+ return;
6522
+ }
6523
+ yield encoder2.encode(row.frame);
6524
+ }
6525
+ if (rows.length > 0) {
6526
+ quietSince = Date.now();
6527
+ if (rows.length >= READ_PAGE) continue;
6528
+ }
6529
+ await sleep(Date.now() - quietSince >= IDLE_AFTER_MS ? this.idlePollIntervalMs : this.pollIntervalMs);
6530
+ }
6531
+ }
6532
+ /** Does the table hold anything for the run — a frame, or its end? */
6533
+ has(runId) {
6534
+ return this.table.has(runId);
6535
+ }
6536
+ async close(runId) {
6537
+ const state = this.writes.get(runId);
6538
+ if (state !== void 0) {
6539
+ if (state.timer !== void 0) clearTimeout(state.timer);
6540
+ state.timer = void 0;
6541
+ state.text = null;
6542
+ state.failure = void 0;
6543
+ await state.tail;
6544
+ this.writes.delete(runId);
6545
+ }
6546
+ await this.table.remove([
6547
+ runId
6548
+ ]);
6549
+ }
6550
+ /**
6551
+ * Delete every run whose last write is older than `ttlSeconds` at `now` (epoch-ms) — ended runs
6552
+ * past their replay window and runs that crashed without ending alike. Returns how many runs went.
6553
+ * Safe from any replica, and from several at once. A no-op under `ttlSeconds: 0`.
6554
+ */
6555
+ async purgeExpired(now = Date.now()) {
6556
+ if (this.ttlSeconds <= 0) return 0;
6557
+ const lapsed = await this.table.lapsedRuns(now - this.ttlSeconds * 1e3);
6558
+ for (let index = 0; index < lapsed.length; index += PURGE_CHUNK) {
6559
+ await this.table.remove(lapsed.slice(index, index + PURGE_CHUNK));
6560
+ }
6561
+ return lapsed.length;
6562
+ }
6563
+ /** {@link purgeExpired}, unawaited and at most once a minute. Its failure is not the run's. */
6564
+ purgeInBackground() {
6565
+ if (!this.autoPurge || this.ttlSeconds <= 0) return;
6566
+ const now = Date.now();
6567
+ if (now - this.lastAutoPurge < AUTO_PURGE_EVERY_MS) return;
6568
+ this.lastAutoPurge = now;
6569
+ this.purgeExpired(now).catch(() => {
6570
+ });
6571
+ }
6572
+ };
6333
6573
  // Annotate the CommonJS export names for ESM import in node:
6334
6574
  0 && (module.exports = {
6335
6575
  AGENT_ACTOR_DIRECTORY,
@@ -6402,6 +6642,7 @@ __name(defineConfirmedTool, "defineConfirmedTool");
6402
6642
  SCHEMA_EXTENSION,
6403
6643
  SKILL_TOOL_DESCRIPTION,
6404
6644
  SKILL_TOOL_NAME,
6645
+ SqlTokenStreamSink,
6405
6646
  StructuredOutputError,
6406
6647
  THREAD_DETAIL_CONTENT_CHARS,
6407
6648
  ToolDisabledError,