@bluecopa/harness 0.1.0-snapshot.85 → 0.1.0-snapshot.87

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.
@@ -20,6 +20,7 @@ declare class ArcLoop {
20
20
  /** Maps normalized action text → process ID for dedup. */
21
21
  private readonly actionIndex;
22
22
  private readonly processListeners;
23
+ private readonly pendingEventResolvers;
23
24
  private readonly skillResolver;
24
25
  private readonly createModel;
25
26
  /** Cached session memo facts — loaded once at stream start, injected into all threads. */
@@ -34,6 +35,9 @@ declare class ArcLoop {
34
35
  /** Wait for all process listener promises to settle (process outboxes closed). */
35
36
  private waitForProcessListeners;
36
37
  private drainPendingEvents;
38
+ private enqueuePendingEvent;
39
+ private hasRunningProcesses;
40
+ private waitForPendingEvent;
37
41
  private toProcessRequest;
38
42
  private buildAssistantMessages;
39
43
  }
@@ -1931,6 +1931,7 @@ var ArcLoop = class {
1931
1931
  /** Maps normalized action text → process ID for dedup. */
1932
1932
  actionIndex = /* @__PURE__ */ new Map();
1933
1933
  processListeners = [];
1934
+ pendingEventResolvers = /* @__PURE__ */ new Set();
1934
1935
  skillResolver;
1935
1936
  createModel;
1936
1937
  /** Cached session memo facts — loaded once at stream start, injected into all threads. */
@@ -2002,6 +2003,13 @@ var ArcLoop = class {
2002
2003
  this.trace({ type: "turn_start", turn });
2003
2004
  yield { type: "turn_start", turn };
2004
2005
  yield* this.drainPendingEvents();
2006
+ if (this.hasRunningProcesses() && this.pendingEvents.length === 0) {
2007
+ await this.waitForPendingEvent(signal, 400);
2008
+ if (this.pendingEvents.length > 0) {
2009
+ yield* this.drainPendingEvents();
2010
+ continue;
2011
+ }
2012
+ }
2005
2013
  const prepared = await this.ctx.prepare(signal);
2006
2014
  this.trace({
2007
2015
  type: "context_prepare",
@@ -2424,7 +2432,7 @@ ${hints.join("\n")}`
2424
2432
  if (skillRefPromise) {
2425
2433
  skillRefPromise.then((ref) => {
2426
2434
  if (ref) {
2427
- this.pendingEvents.push({
2435
+ this.enqueuePendingEvent({
2428
2436
  type: "skill_resolved",
2429
2437
  processId: proc.id,
2430
2438
  skillName: ref.name,
@@ -2447,7 +2455,7 @@ ${hints.join("\n")}`
2447
2455
  for await (const event of proc.outbox) {
2448
2456
  if (event.type === "activity") {
2449
2457
  this.traceProcessRunning(proc.id);
2450
- this.pendingEvents.push({
2458
+ this.enqueuePendingEvent({
2451
2459
  type: "process_activity",
2452
2460
  id: proc.id,
2453
2461
  activity: event.activity
@@ -2456,7 +2464,7 @@ ${hints.join("\n")}`
2456
2464
  this.traceProcessRunning(proc.id);
2457
2465
  this.trace({ type: "process_transition", id: proc.id, from: "running", to: "completed" });
2458
2466
  this.ctx.addEpisode(event.result.episode);
2459
- this.pendingEvents.push({
2467
+ this.enqueuePendingEvent({
2460
2468
  type: "process_completed",
2461
2469
  id: proc.id,
2462
2470
  episodeId: event.result.episode.id,
@@ -2467,7 +2475,7 @@ ${hints.join("\n")}`
2467
2475
  this.traceProcessRunning(proc.id);
2468
2476
  const toStatus = event.error === "cancelled" ? "cancelled" : "failed";
2469
2477
  this.trace({ type: "process_transition", id: proc.id, from: "running", to: toStatus });
2470
- this.pendingEvents.push({
2478
+ this.enqueuePendingEvent({
2471
2479
  type: "process_failed",
2472
2480
  id: proc.id,
2473
2481
  error: event.error
@@ -2486,6 +2494,47 @@ ${hints.join("\n")}`
2486
2494
  yield this.pendingEvents.shift();
2487
2495
  }
2488
2496
  }
2497
+ enqueuePendingEvent(event) {
2498
+ this.pendingEvents.push(event);
2499
+ for (const resolve of this.pendingEventResolvers) {
2500
+ resolve();
2501
+ }
2502
+ this.pendingEventResolvers.clear();
2503
+ }
2504
+ hasRunningProcesses() {
2505
+ for (const proc of this.processes.values()) {
2506
+ if (proc.status === "running" || proc.status === "pending") {
2507
+ return true;
2508
+ }
2509
+ }
2510
+ return false;
2511
+ }
2512
+ waitForPendingEvent(signal, timeoutMs) {
2513
+ if (this.pendingEvents.length > 0) {
2514
+ return Promise.resolve();
2515
+ }
2516
+ return new Promise((resolve) => {
2517
+ const onAbort = () => {
2518
+ cleanup();
2519
+ resolve();
2520
+ };
2521
+ const onEvent = () => {
2522
+ cleanup();
2523
+ resolve();
2524
+ };
2525
+ const timer = setTimeout(() => {
2526
+ cleanup();
2527
+ resolve();
2528
+ }, timeoutMs);
2529
+ const cleanup = () => {
2530
+ clearTimeout(timer);
2531
+ signal.removeEventListener("abort", onAbort);
2532
+ this.pendingEventResolvers.delete(onEvent);
2533
+ };
2534
+ signal.addEventListener("abort", onAbort, { once: true });
2535
+ this.pendingEventResolvers.add(onEvent);
2536
+ });
2537
+ }
2489
2538
  // ── Helpers ──
2490
2539
  toProcessRequest(args) {
2491
2540
  const req = { action: String(args.action ?? "") };