@elizaos/plugin-agent-orchestrator 0.3.11 → 0.3.12

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.js CHANGED
@@ -537,7 +537,8 @@ __export(exports_swarm_decision_loop, {
537
537
  handleBlocked: () => handleBlocked,
538
538
  handleAutonomousDecision: () => handleAutonomousDecision,
539
539
  executeDecision: () => executeDecision,
540
- checkAllTasksComplete: () => checkAllTasksComplete
540
+ checkAllTasksComplete: () => checkAllTasksComplete,
541
+ POST_SEND_COOLDOWN_MS: () => POST_SEND_COOLDOWN_MS
541
542
  });
542
543
  import * as path from "node:path";
543
544
  import { ModelType as ModelType3 } from "@elizaos/core";
@@ -786,7 +787,8 @@ async function executeDecision(ctx, sessionId, decision) {
786
787
  if (!ctx.ptyService)
787
788
  return;
788
789
  switch (decision.action) {
789
- case "respond":
790
+ case "respond": {
791
+ const taskCtx = ctx.tasks.get(sessionId);
790
792
  if (decision.useKeys && decision.keys) {
791
793
  await ctx.ptyService.sendKeysToSession(sessionId, decision.keys);
792
794
  } else if (decision.response !== undefined) {
@@ -796,7 +798,10 @@ async function executeDecision(ctx, sessionId, decision) {
796
798
  commitSharedDecisionIndex(ctx, sessionId, snapshotIndex);
797
799
  }
798
800
  }
801
+ if (taskCtx)
802
+ taskCtx.lastInputSentAt = Date.now();
799
803
  break;
804
+ }
800
805
  case "complete": {
801
806
  const taskCtx = ctx.tasks.get(sessionId);
802
807
  if (taskCtx) {
@@ -958,6 +963,13 @@ async function handleTurnComplete(ctx, sessionId, taskCtx, data) {
958
963
  ctx.pendingTurnComplete.set(sessionId, data);
959
964
  return;
960
965
  }
966
+ if (taskCtx.lastInputSentAt) {
967
+ const elapsed = Date.now() - taskCtx.lastInputSentAt;
968
+ if (elapsed < POST_SEND_COOLDOWN_MS) {
969
+ ctx.log(`Suppressing turn-complete for "${taskCtx.label}" — ` + `${Math.round(elapsed / 1000)}s since last input (cooldown ${POST_SEND_COOLDOWN_MS / 1000}s)`);
970
+ return;
971
+ }
972
+ }
961
973
  ctx.inFlightDecisions.add(sessionId);
962
974
  try {
963
975
  ctx.log(`Turn complete for "${taskCtx.label}" — assessing whether task is done`);
@@ -1207,7 +1219,7 @@ async function handleConfirmDecision(ctx, sessionId, taskCtx, promptText, recent
1207
1219
  await drainPendingBlocked(ctx, sessionId);
1208
1220
  }
1209
1221
  }
1210
- var DECISION_CB_TIMEOUT_MS = 30000, MAX_AUTO_RESPONSES = 10;
1222
+ var DECISION_CB_TIMEOUT_MS = 30000, MAX_AUTO_RESPONSES = 10, POST_SEND_COOLDOWN_MS = 15000;
1211
1223
  var init_swarm_decision_loop = __esm(() => {
1212
1224
  init_ansi_utils();
1213
1225
  init_swarm_event_triage();
@@ -2230,13 +2242,13 @@ var sendToAgentAction = {
2230
2242
  import * as os from "node:os";
2231
2243
  import * as path2 from "node:path";
2232
2244
  import {
2233
- logger as logger3
2245
+ logger as logger4
2234
2246
  } from "@elizaos/core";
2235
2247
 
2236
2248
  // src/services/pty-service.ts
2237
2249
  import { appendFile, mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
2238
2250
  import { dirname, join as join2 } from "node:path";
2239
- import { logger as logger2 } from "@elizaos/core";
2251
+ import { logger as logger3 } from "@elizaos/core";
2240
2252
  import {
2241
2253
  checkAdapters,
2242
2254
  createAdapter,
@@ -3141,6 +3153,9 @@ async function classifyAndDecideForCoordinator(ctx) {
3141
3153
  }
3142
3154
  }
3143
3155
 
3156
+ // src/services/pty-service.ts
3157
+ init_swarm_decision_loop();
3158
+
3144
3159
  // src/services/swarm-coordinator.ts
3145
3160
  init_ansi_utils();
3146
3161
  init_swarm_decision_loop();
@@ -3822,6 +3837,65 @@ class SwarmCoordinator {
3822
3837
  }
3823
3838
  }
3824
3839
 
3840
+ // src/services/debug-capture.ts
3841
+ import { logger as logger2 } from "@elizaos/core";
3842
+ var captureManager = null;
3843
+ var initAttempted = false;
3844
+ function isDebugCaptureEnabled() {
3845
+ return process.env.PARALLAX_DEBUG_CAPTURE === "1";
3846
+ }
3847
+ async function ensureCaptureManager() {
3848
+ if (captureManager)
3849
+ return captureManager;
3850
+ if (initAttempted)
3851
+ return null;
3852
+ initAttempted = true;
3853
+ if (!isDebugCaptureEnabled())
3854
+ return null;
3855
+ try {
3856
+ const mod = await import("pty-state-capture");
3857
+ const { PTYStateCaptureManager } = mod;
3858
+ captureManager = new PTYStateCaptureManager({
3859
+ outputRootDir: ".parallax/pty-captures",
3860
+ defaultRows: 80,
3861
+ defaultCols: 220
3862
+ });
3863
+ logger2.info("[debug-capture] PTY state capture enabled — writing to .parallax/pty-captures/");
3864
+ return captureManager;
3865
+ } catch {
3866
+ logger2.debug("[debug-capture] pty-state-capture not available — capture disabled");
3867
+ return null;
3868
+ }
3869
+ }
3870
+ async function captureSessionOpen(sessionId, agentType) {
3871
+ const mgr = await ensureCaptureManager();
3872
+ if (!mgr)
3873
+ return;
3874
+ try {
3875
+ await mgr.openSession(sessionId, { source: agentType });
3876
+ } catch (err) {
3877
+ logger2.debug(`[debug-capture] Failed to open session ${sessionId}: ${err}`);
3878
+ }
3879
+ }
3880
+ async function captureFeed(sessionId, chunk, direction = "stdout") {
3881
+ if (!captureManager)
3882
+ return;
3883
+ try {
3884
+ await captureManager.feed(sessionId, chunk, direction);
3885
+ } catch (err) {
3886
+ logger2.debug(`[debug-capture] Feed error for ${sessionId}: ${err}`);
3887
+ }
3888
+ }
3889
+ async function captureLifecycle(sessionId, event, detail) {
3890
+ if (!captureManager)
3891
+ return;
3892
+ try {
3893
+ await captureManager.lifecycle(sessionId, event, detail);
3894
+ } catch (err) {
3895
+ logger2.debug(`[debug-capture] Lifecycle error for ${sessionId}: ${err}`);
3896
+ }
3897
+ }
3898
+
3825
3899
  // src/services/pty-service.ts
3826
3900
  function getCoordinator(runtime) {
3827
3901
  const ptyService = runtime.getService("PTY_SERVICE");
@@ -3865,16 +3939,16 @@ class PTYService {
3865
3939
  const existing = servicesMap?.get?.("SWARM_COORDINATOR");
3866
3940
  if (existing && existing.length > 0) {
3867
3941
  service.coordinator = existing[0];
3868
- logger2.info("[PTYService] SwarmCoordinator already registered, skipping duplicate start");
3942
+ logger3.info("[PTYService] SwarmCoordinator already registered, skipping duplicate start");
3869
3943
  } else {
3870
3944
  try {
3871
3945
  const coordinator = new SwarmCoordinator(runtime);
3872
3946
  coordinator.start(service);
3873
3947
  service.coordinator = coordinator;
3874
3948
  servicesMap?.set?.("SWARM_COORDINATOR", [coordinator]);
3875
- logger2.info("[PTYService] SwarmCoordinator wired and started");
3949
+ logger3.info("[PTYService] SwarmCoordinator wired and started");
3876
3950
  } catch (err) {
3877
- logger2.error(`[PTYService] Failed to wire SwarmCoordinator: ${err}`);
3951
+ logger3.error(`[PTYService] Failed to wire SwarmCoordinator: ${err}`);
3878
3952
  }
3879
3953
  }
3880
3954
  return service;
@@ -4098,6 +4172,21 @@ class PTYService {
4098
4172
  if (this.usingBunWorker) {
4099
4173
  setupOutputBuffer(ctx, session.id);
4100
4174
  }
4175
+ if (isDebugCaptureEnabled()) {
4176
+ captureSessionOpen(session.id, resolvedAgentType).catch(() => {});
4177
+ if (this.usingBunWorker) {
4178
+ this.manager.onSessionData(session.id, (data) => {
4179
+ captureFeed(session.id, data, "stdout");
4180
+ });
4181
+ } else {
4182
+ const ptySession = this.manager.getSession(session.id);
4183
+ if (ptySession) {
4184
+ ptySession.on("output", (data) => {
4185
+ captureFeed(session.id, data, "stdout");
4186
+ });
4187
+ }
4188
+ }
4189
+ }
4101
4190
  if (resolvedInitialTask) {
4102
4191
  setupDeferredTaskDelivery(ctx, session, resolvedInitialTask, resolvedAgentType);
4103
4192
  }
@@ -4125,6 +4214,7 @@ class PTYService {
4125
4214
  async sendToSession(sessionId, input) {
4126
4215
  if (!this.manager)
4127
4216
  throw new Error("PTYService not initialized");
4217
+ captureFeed(sessionId, input, "stdin");
4128
4218
  return sendToSession(this.ioContext(), sessionId, input);
4129
4219
  }
4130
4220
  async sendKeysToSession(sessionId, keys) {
@@ -4135,6 +4225,7 @@ class PTYService {
4135
4225
  async stopSession(sessionId, force = false) {
4136
4226
  if (!this.manager)
4137
4227
  throw new Error("PTYService not initialized");
4228
+ captureLifecycle(sessionId, "session_stopped", force ? "force" : undefined);
4138
4229
  return stopSession(this.ioContext(), sessionId, this.sessionMetadata, this.sessionWorkdirs, (msg) => this.log(msg), force);
4139
4230
  }
4140
4231
  get defaultApprovalPreset() {
@@ -4210,12 +4301,12 @@ class PTYService {
4210
4301
  handleHookEvent(sessionId, event, data) {
4211
4302
  const summary = event === "tool_running" ? `tool=${data.toolName ?? "?"}` : event === "permission_approved" ? `tool=${data.tool ?? "?"}` : JSON.stringify(data);
4212
4303
  if (event === "tool_running" || event === "permission_approved") {
4213
- logger2.debug(`[PTYService] Hook event for ${sessionId}: ${event} ${summary}`);
4304
+ logger3.debug(`[PTYService] Hook event for ${sessionId}: ${event} ${summary}`);
4214
4305
  } else {
4215
4306
  this.log(`Hook event for ${sessionId}: ${event} ${summary}`);
4216
4307
  }
4217
4308
  if (this.manager && this.usingBunWorker) {
4218
- this.manager.notifyHookEvent(sessionId, event).catch((err) => logger2.debug(`[PTYService] Failed to forward hook event to session: ${err}`));
4309
+ this.manager.notifyHookEvent(sessionId, event).catch((err) => logger3.debug(`[PTYService] Failed to forward hook event to session: ${err}`));
4219
4310
  }
4220
4311
  switch (event) {
4221
4312
  case "tool_running":
@@ -4249,6 +4340,13 @@ class PTYService {
4249
4340
  if (meta?.coordinatorManaged && this.coordinator?.getSupervisionLevel() === "autonomous") {
4250
4341
  const taskCtx = this.coordinator.getTaskContext(sessionId);
4251
4342
  if (taskCtx) {
4343
+ if (taskCtx.lastInputSentAt) {
4344
+ const elapsed = Date.now() - taskCtx.lastInputSentAt;
4345
+ if (elapsed < POST_SEND_COOLDOWN_MS) {
4346
+ this.log(`Suppressing stall classification for ${sessionId} — ` + `${Math.round(elapsed / 1000)}s since coordinator sent input`);
4347
+ return null;
4348
+ }
4349
+ }
4252
4350
  return classifyAndDecideForCoordinator({
4253
4351
  sessionId,
4254
4352
  recentOutput,
@@ -4413,7 +4511,7 @@ class PTYService {
4413
4511
  return this.metricsTracker.getAll();
4414
4512
  }
4415
4513
  log(message) {
4416
- logger2.debug(`[PTYService] ${message}`);
4514
+ logger3.debug(`[PTYService] ${message}`);
4417
4515
  }
4418
4516
  }
4419
4517
 
@@ -4459,7 +4557,7 @@ var spawnAgentAction = {
4459
4557
  validate: async (runtime, _message) => {
4460
4558
  const ptyService = runtime.getService("PTY_SERVICE");
4461
4559
  if (!ptyService) {
4462
- logger3.warn("[SPAWN_CODING_AGENT] PTYService not available");
4560
+ logger4.warn("[SPAWN_CODING_AGENT] PTYService not available");
4463
4561
  return false;
4464
4562
  }
4465
4563
  return true;
@@ -4572,7 +4670,7 @@ var spawnAgentAction = {
4572
4670
  ptyService.onSessionEvent((sessionId, event, data) => {
4573
4671
  if (sessionId !== session.id)
4574
4672
  return;
4575
- logger3.debug(`[Session ${sessionId}] ${event}: ${JSON.stringify(data)}`);
4673
+ logger4.debug(`[Session ${sessionId}] ${event}: ${JSON.stringify(data)}`);
4576
4674
  if (!coordinator) {
4577
4675
  if (event === "blocked" && callback) {
4578
4676
  callback({
@@ -4624,7 +4722,7 @@ var spawnAgentAction = {
4624
4722
  };
4625
4723
  } catch (error) {
4626
4724
  const errorMessage = error instanceof Error ? error.message : String(error);
4627
- logger3.error("[SPAWN_CODING_AGENT] Failed to spawn agent:", errorMessage);
4725
+ logger4.error("[SPAWN_CODING_AGENT] Failed to spawn agent:", errorMessage);
4628
4726
  if (callback) {
4629
4727
  await callback({
4630
4728
  text: `Failed to spawn coding agent: ${errorMessage}`
@@ -4672,7 +4770,7 @@ var spawnAgentAction = {
4672
4770
 
4673
4771
  // src/actions/coding-task-handlers.ts
4674
4772
  import {
4675
- logger as logger5,
4773
+ logger as logger6,
4676
4774
  ModelType as ModelType5
4677
4775
  } from "@elizaos/core";
4678
4776
  // src/services/trajectory-feedback.ts
@@ -4749,12 +4847,12 @@ async function queryPastExperience(runtime, options = {}) {
4749
4847
  taskDescription,
4750
4848
  repo
4751
4849
  } = options;
4752
- const logger4 = getTrajectoryLogger(runtime);
4753
- if (!logger4)
4850
+ const logger5 = getTrajectoryLogger(runtime);
4851
+ if (!logger5)
4754
4852
  return [];
4755
4853
  const startDate = new Date(Date.now() - lookbackHours * 60 * 60 * 1000).toISOString();
4756
4854
  try {
4757
- const result = await withTimeout2(logger4.listTrajectories({
4855
+ const result = await withTimeout2(logger5.listTrajectories({
4758
4856
  source: "orchestrator",
4759
4857
  limit: maxTrajectories,
4760
4858
  startDate
@@ -4765,7 +4863,7 @@ async function queryPastExperience(runtime, options = {}) {
4765
4863
  const maxScans = Math.min(result.trajectories.length, maxTrajectories);
4766
4864
  for (let scanIdx = 0;scanIdx < maxScans; scanIdx++) {
4767
4865
  const summary = result.trajectories[scanIdx];
4768
- const detail = await withTimeout2(logger4.getTrajectoryDetail(summary.id), QUERY_TIMEOUT_MS).catch(() => null);
4866
+ const detail = await withTimeout2(logger5.getTrajectoryDetail(summary.id), QUERY_TIMEOUT_MS).catch(() => null);
4769
4867
  if (!detail?.steps)
4770
4868
  continue;
4771
4869
  const metadata = detail.metadata;
@@ -4843,7 +4941,7 @@ import * as fs from "node:fs";
4843
4941
  import * as os2 from "node:os";
4844
4942
  import * as path3 from "node:path";
4845
4943
  import {
4846
- logger as logger4
4944
+ logger as logger5
4847
4945
  } from "@elizaos/core";
4848
4946
  function createScratchDir() {
4849
4947
  const baseDir = path3.join(os2.homedir(), ".milady", "workspaces");
@@ -4888,7 +4986,7 @@ ${preview}` : `Agent "${label}" completed the task.`
4888
4986
  });
4889
4987
  }
4890
4988
  ptyService.stopSession(sessionId, true).catch((err) => {
4891
- logger4.warn(`[START_CODING_TASK] Failed to stop session for "${label}" after task complete: ${err}`);
4989
+ logger5.warn(`[START_CODING_TASK] Failed to stop session for "${label}" after task complete: ${err}`);
4892
4990
  });
4893
4991
  }
4894
4992
  if (event === "error" && callback) {
@@ -4901,7 +4999,7 @@ ${preview}` : `Agent "${label}" completed the task.`
4901
4999
  const wsService = runtime.getService("CODING_WORKSPACE_SERVICE");
4902
5000
  if (wsService) {
4903
5001
  wsService.removeScratchDir(scratchDir).catch((err) => {
4904
- logger4.warn(`[START_CODING_TASK] Failed to cleanup scratch dir for "${label}": ${err}`);
5002
+ logger5.warn(`[START_CODING_TASK] Failed to cleanup scratch dir for "${label}": ${err}`);
4905
5003
  });
4906
5004
  }
4907
5005
  }
@@ -4988,7 +5086,7 @@ ${taskList}
4988
5086
  }));
4989
5087
  return result?.trim() || "";
4990
5088
  } catch (err) {
4991
- logger5.warn(`Swarm context generation failed: ${err}`);
5089
+ logger6.warn(`Swarm context generation failed: ${err}`);
4992
5090
  return "";
4993
5091
  }
4994
5092
  }
@@ -5160,7 +5258,7 @@ ${swarmContext}
5160
5258
  }
5161
5259
  } catch (error) {
5162
5260
  const errorMessage = error instanceof Error ? error.message : String(error);
5163
- logger5.error(`[START_CODING_TASK] Failed to spawn agent ${i + 1}:`, errorMessage);
5261
+ logger6.error(`[START_CODING_TASK] Failed to spawn agent ${i + 1}:`, errorMessage);
5164
5262
  results.push({
5165
5263
  sessionId: "",
5166
5264
  agentType: specAgentType,
@@ -5192,7 +5290,7 @@ ${swarmContext}
5192
5290
  };
5193
5291
  }
5194
5292
  async function handleSingleAgent(ctx, task) {
5195
- logger5.debug(`[START_CODING_TASK] handleSingleAgent called, agentType=${ctx.defaultAgentType}, task=${task ? "yes" : "none"}, repo=${ctx.repo ?? "none"}`);
5293
+ logger6.debug(`[START_CODING_TASK] handleSingleAgent called, agentType=${ctx.defaultAgentType}, task=${task ? "yes" : "none"}, repo=${ctx.repo ?? "none"}`);
5196
5294
  const {
5197
5295
  runtime,
5198
5296
  ptyService,
@@ -5252,14 +5350,14 @@ async function handleSingleAgent(ctx, task) {
5252
5350
  } else {
5253
5351
  workdir = createScratchDir();
5254
5352
  }
5255
- logger5.debug(`[START_CODING_TASK] Spawning ${agentType} agent, task: ${task ? `"${task.slice(0, 80)}..."` : "(none)"}, workdir: ${workdir}`);
5353
+ logger6.debug(`[START_CODING_TASK] Spawning ${agentType} agent, task: ${task ? `"${task.slice(0, 80)}..."` : "(none)"}, workdir: ${workdir}`);
5256
5354
  try {
5257
5355
  if (agentType !== "shell" && agentType !== "pi") {
5258
5356
  const [preflight] = await ptyService.checkAvailableAgents([
5259
5357
  agentType
5260
5358
  ]);
5261
5359
  if (preflight && !preflight.installed) {
5262
- logger5.warn(`[START_CODING_TASK] ${preflight.adapter} CLI not installed`);
5360
+ logger6.warn(`[START_CODING_TASK] ${preflight.adapter} CLI not installed`);
5263
5361
  if (callback) {
5264
5362
  await callback({
5265
5363
  text: `${preflight.adapter} CLI is not installed.
@@ -5269,7 +5367,7 @@ Docs: ${preflight.docsUrl}`
5269
5367
  }
5270
5368
  return { success: false, error: "AGENT_NOT_INSTALLED" };
5271
5369
  }
5272
- logger5.debug(`[START_CODING_TASK] Preflight OK: ${preflight?.adapter} installed`);
5370
+ logger6.debug(`[START_CODING_TASK] Preflight OK: ${preflight?.adapter} installed`);
5273
5371
  }
5274
5372
  const piRequested = isPiAgentType(rawAgentType);
5275
5373
  const initialTask = piRequested ? toPiCommand(task) : task;
@@ -5285,7 +5383,7 @@ Docs: ${preflight.docsUrl}`
5285
5383
 
5286
5384
  `) || undefined;
5287
5385
  const coordinator = getCoordinator(runtime);
5288
- logger5.debug(`[START_CODING_TASK] Calling spawnSession (${agentType}, coordinator=${!!coordinator})`);
5386
+ logger6.debug(`[START_CODING_TASK] Calling spawnSession (${agentType}, coordinator=${!!coordinator})`);
5289
5387
  const session = await ptyService.spawnSession({
5290
5388
  name: `coding-${Date.now()}`,
5291
5389
  agentType,
@@ -5304,7 +5402,7 @@ Docs: ${preflight.docsUrl}`
5304
5402
  label
5305
5403
  }
5306
5404
  });
5307
- logger5.debug(`[START_CODING_TASK] Session spawned: ${session.id} (${session.status})`);
5405
+ logger6.debug(`[START_CODING_TASK] Session spawned: ${session.id} (${session.status})`);
5308
5406
  const isScratchWorkspace = !repo;
5309
5407
  const scratchDir = isScratchWorkspace ? workdir : null;
5310
5408
  registerSessionEvents(ptyService, runtime, session.id, label, scratchDir, callback, !!coordinator);
@@ -5345,7 +5443,7 @@ Session ID: ${session.id}` });
5345
5443
  };
5346
5444
  } catch (error) {
5347
5445
  const errorMessage = error instanceof Error ? error.message : String(error);
5348
- logger5.error("[START_CODING_TASK] Failed to spawn agent:", errorMessage);
5446
+ logger6.error("[START_CODING_TASK] Failed to spawn agent:", errorMessage);
5349
5447
  if (callback) {
5350
5448
  await callback({
5351
5449
  text: `Failed to start coding agent: ${errorMessage}`
@@ -5526,7 +5624,7 @@ var startCodingTaskAction = {
5526
5624
 
5527
5625
  // src/actions/stop-agent.ts
5528
5626
  import {
5529
- logger as logger6
5627
+ logger as logger7
5530
5628
  } from "@elizaos/core";
5531
5629
  var stopAgentAction = {
5532
5630
  name: "STOP_CODING_AGENT",
@@ -5605,7 +5703,7 @@ var stopAgentAction = {
5605
5703
  try {
5606
5704
  await ptyService.stopSession(session2.id);
5607
5705
  } catch (err) {
5608
- logger6.error(`Failed to stop session ${session2.id}: ${err}`);
5706
+ logger7.error(`Failed to stop session ${session2.id}: ${err}`);
5609
5707
  }
5610
5708
  }
5611
5709
  if (state?.codingSession) {
@@ -7370,5 +7468,5 @@ export {
7370
7468
  CodingWorkspaceService
7371
7469
  };
7372
7470
 
7373
- //# debugId=1AF5CF89CDA1169464756E2164756E21
7471
+ //# debugId=4383E51DF7A1F4A764756E2164756E21
7374
7472
  //# sourceMappingURL=index.js.map