@rowan-agent/agent 0.15.3 → 0.15.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/dist/index.d.ts CHANGED
@@ -1137,6 +1137,12 @@ interface OwnedStore {
1137
1137
  phaseId: string;
1138
1138
  visit: number;
1139
1139
  }): Promise<RunRecord>;
1140
+ commitPhaseOutput(input: {
1141
+ runId: RunId;
1142
+ execution: ExecutionToken;
1143
+ expectedRevision: number;
1144
+ message: AssistantMessage;
1145
+ }): Promise<RunRecord>;
1140
1146
  commitInputRequired(input: {
1141
1147
  runId: RunId;
1142
1148
  execution: ExecutionToken;
@@ -2368,6 +2374,13 @@ declare class InMemoryStore implements DurableStore {
2368
2374
  phaseId: string;
2369
2375
  visit: number;
2370
2376
  }): RunRecord;
2377
+ /** Commit a parallel Phase's reply while its Run is still running. */
2378
+ commitPhaseOutput(lease: OwnerLease, input: {
2379
+ runId: RunId;
2380
+ execution: ExecutionToken;
2381
+ expectedRevision: number;
2382
+ message: AssistantMessage;
2383
+ }): RunRecord;
2371
2384
  commitInputRequired(lease: OwnerLease, input: {
2372
2385
  runId: RunId;
2373
2386
  execution: ExecutionToken;
@@ -2571,6 +2584,12 @@ declare class SqliteStore implements DurableStore {
2571
2584
  phaseId: string;
2572
2585
  visit: number;
2573
2586
  }): Promise<RunRecord>;
2587
+ commitPhaseOutput(lease: OwnerLease, input: {
2588
+ runId: RunId;
2589
+ execution: ExecutionToken;
2590
+ expectedRevision: number;
2591
+ message: AssistantMessage;
2592
+ }): Promise<RunRecord>;
2574
2593
  commitInputRequired(lease: OwnerLease, input: {
2575
2594
  runId: RunId;
2576
2595
  execution: ExecutionToken;
package/dist/index.js CHANGED
@@ -3264,6 +3264,13 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3264
3264
  }
3265
3265
  };
3266
3266
  }
3267
+ function parallelPhaseReply(produced) {
3268
+ const last = [...produced].reverse().find((message) => message.role === "assistant");
3269
+ if (!last) return void 0;
3270
+ if (typeof last.content === "string") return last.content.trim() ? last : void 0;
3271
+ if (last.content.some((part) => part.type === "tool_use")) return void 0;
3272
+ return last.content.some((part) => part.type === "text" && part.text.trim()) ? last : void 0;
3273
+ }
3267
3274
  async function executeParallelPhase(config, state, registry, phase, payload, instruction, context, availablePhases, instanceId, groupId, index, count, sourcePhaseId) {
3268
3275
  const messages = [...context];
3269
3276
  const effectivePayload = preparePhasePayload(phase.input, payload);
@@ -3305,7 +3312,12 @@ async function executeParallelPhase(config, state, registry, phase, payload, ins
3305
3312
  const toolExecutionManager = createToolExecutionManager();
3306
3313
  const execution = createPhaseExecution(config, state, phase, messageManager, toolExecutionManager, registry);
3307
3314
  const runtime = { phase, config, state, execution, messageManager, registry, context: phaseContext };
3315
+ const phaseStart = messages.length;
3308
3316
  let output = await executePhase(runtime);
3317
+ const reply = parallelPhaseReply(messages.slice(phaseStart));
3318
+ if (reply && config.onParallelPhaseOutput) {
3319
+ await config.onParallelPhaseOutput(reply, { mode: "parallel", instanceId, groupId, index, count, sourcePhaseId });
3320
+ }
3309
3321
  if (phaseMsgId) removePhaseMessage(messages, phaseMsgId);
3310
3322
  if (config.afterPhase) {
3311
3323
  const extAfter = await config.afterPhase(phase.name, output);
@@ -3483,6 +3495,7 @@ async function executeOnce(input) {
3483
3495
  afterPhase: input.afterPhase,
3484
3496
  beforePrompt: input.beforePrompt,
3485
3497
  onMessage: input.onMessage,
3498
+ onParallelPhaseOutput: input.onParallelPhaseOutput,
3486
3499
  onMessageDelta: input.onMessageDelta,
3487
3500
  onThinkingDelta: input.onThinkingDelta,
3488
3501
  onOutcome: input.onOutcome,
@@ -4307,6 +4320,10 @@ function renderInteractionText(record) {
4307
4320
  const replyStr = record.reply ?? "";
4308
4321
  return template.replaceAll("{{prompt}}", record.prompt).replaceAll("{{answer}}", answerStr).replaceAll("{{reply}}", replyStr);
4309
4322
  }
4323
+ var PARALLEL_PHASE_METADATA_KEY = "parallelPhase";
4324
+ function isParallelPhaseOutput(message) {
4325
+ return message.role === "assistant" && message.metadata?.[PARALLEL_PHASE_METADATA_KEY] !== void 0;
4326
+ }
4310
4327
  function projectModelContext(input) {
4311
4328
  const toolInteractionTexts = /* @__PURE__ */ new Map();
4312
4329
  for (const message of input.messages) {
@@ -4322,6 +4339,7 @@ function projectModelContext(input) {
4322
4339
  }
4323
4340
  const projectedMessages = [];
4324
4341
  for (const message of input.messages) {
4342
+ if (isParallelPhaseOutput(message)) continue;
4325
4343
  if (message.role === "interaction") {
4326
4344
  if (message.toolCallId !== void 0) {
4327
4345
  continue;
@@ -6613,6 +6631,33 @@ var AgentRuntime = class _AgentRuntime {
6613
6631
  status
6614
6632
  });
6615
6633
  },
6634
+ onParallelPhaseOutput: (message, invocation) => {
6635
+ const task = toolQueue.then(async () => {
6636
+ const active = this.executions.get(run.id);
6637
+ if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
6638
+ const projected = projectAssistantMessage(message, run.agentId, run.id, 0);
6639
+ const committed = await this.owned.commitPhaseOutput({
6640
+ runId: run.id,
6641
+ execution: claim.execution,
6642
+ expectedRevision: executionRevision,
6643
+ message: {
6644
+ ...projected,
6645
+ metadata: {
6646
+ ...projected.metadata,
6647
+ [PARALLEL_PHASE_METADATA_KEY]: {
6648
+ groupId: invocation.groupId,
6649
+ instanceId: invocation.instanceId,
6650
+ index: invocation.index,
6651
+ count: invocation.count
6652
+ }
6653
+ }
6654
+ }
6655
+ });
6656
+ executionRevision = committed.revision;
6657
+ });
6658
+ toolQueue = task.then(() => void 0, () => void 0);
6659
+ return task;
6660
+ },
6616
6661
  onMessageDelta: (event) => {
6617
6662
  const active = this.executions.get(run.id);
6618
6663
  if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
@@ -6700,7 +6745,7 @@ var AgentRuntime = class _AgentRuntime {
6700
6745
  }
6701
6746
  }
6702
6747
  if (this.cancellationRequested.has(run.id) || controller.signal.aborted) {
6703
- const output = latestAssistant(run, result.messages, modelMessages.length, true);
6748
+ const output = latestAssistant(run, result.messages, executionContext.messages.length, true);
6704
6749
  const reason = this.cancellationReasons.get(run.id) ?? "Agent run stopped.";
6705
6750
  await this.owned.cancelRun({
6706
6751
  runId: run.id,
@@ -6723,7 +6768,7 @@ var AgentRuntime = class _AgentRuntime {
6723
6768
  const output = isToolCallInteraction ? void 0 : latestAssistant(
6724
6769
  run,
6725
6770
  result.messages,
6726
- modelMessages.length
6771
+ executionContext.messages.length
6727
6772
  );
6728
6773
  const prompt = isToolCallInteraction ? void 0 : output ?? (result.interactions[0]?.prompt ? promptMessage(run, result.interactions[0].prompt, result.messages.length) : void 0);
6729
6774
  await this.owned.commitInputRequired({
@@ -6741,7 +6786,7 @@ var AgentRuntime = class _AgentRuntime {
6741
6786
  return;
6742
6787
  }
6743
6788
  if (result.type === "completed") {
6744
- const output = latestAssistant(run, result.messages, modelMessages.length);
6789
+ const output = latestAssistant(run, result.messages, executionContext.messages.length);
6745
6790
  await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, outcome: durableOutcome(result.outcome), ...output ? { output } : {} });
6746
6791
  this.transientEvents.clear(run.id, claim.execution.executionId, true);
6747
6792
  return;
@@ -8125,6 +8170,32 @@ var InMemoryStore = class _InMemoryStore {
8125
8170
  this.writeOperationReceipt(operationKey, operationPayload, result);
8126
8171
  return result;
8127
8172
  }
8173
+ /** Commit a parallel Phase's reply while its Run is still running. */
8174
+ commitPhaseOutput(lease, input) {
8175
+ this.assertOwner(lease);
8176
+ const operationKey = `phase_output:${input.message.id}`;
8177
+ const operationPayload = canonicalJson([input.runId, input.execution.executionId, input.expectedRevision, input.message]);
8178
+ const replay = this.replayOperation(operationKey, operationPayload);
8179
+ if (replay) return clone(replay);
8180
+ const run = this.requireRun(input.runId);
8181
+ this.assertExecution(run, input.execution, input.expectedRevision);
8182
+ this.assertState(run, ["running"]);
8183
+ if (this.messages.has(input.message.id)) throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["running"], actual: run.state });
8184
+ const message = {
8185
+ ...clone(input.message),
8186
+ agentId: run.agentId,
8187
+ runId: run.id,
8188
+ role: "assistant",
8189
+ sequenceWithinRun: this.nextMessageSequence(run.id)
8190
+ };
8191
+ this.messages.set(message.id, message);
8192
+ run.revision += 1;
8193
+ run.updatedAt = createTimestamp();
8194
+ this.appendMessage(run, message);
8195
+ const result = clone(run);
8196
+ this.writeOperationReceipt(operationKey, operationPayload, result);
8197
+ return result;
8198
+ }
8128
8199
  commitInputRequired(lease, input) {
8129
8200
  this.assertOwner(lease);
8130
8201
  if (typeof input.phase !== "string" || input.phase.length === 0) throw new TypeError("phase must be non-empty");
@@ -8944,6 +9015,9 @@ var MemoryOwnedStore = class {
8944
9015
  async commitPhaseEntered(input) {
8945
9016
  return this.store.commitPhaseEntered(this.lease, input);
8946
9017
  }
9018
+ async commitPhaseOutput(input) {
9019
+ return this.store.commitPhaseOutput(this.lease, input);
9020
+ }
8947
9021
  async commitInputRequired(input) {
8948
9022
  return this.store.commitInputRequired(this.lease, input);
8949
9023
  }
@@ -9347,6 +9421,9 @@ var SqliteStore = class {
9347
9421
  async commitPhaseEntered(lease, input) {
9348
9422
  return this.invoke(lease, (store, current) => store.commitPhaseEntered(current, input));
9349
9423
  }
9424
+ async commitPhaseOutput(lease, input) {
9425
+ return this.invoke(lease, (store, current) => store.commitPhaseOutput(current, input));
9426
+ }
9350
9427
  async commitInputRequired(lease, input) {
9351
9428
  return this.invoke(lease, (store, current) => store.commitInputRequired(current, input));
9352
9429
  }
@@ -9740,6 +9817,9 @@ var SqliteOwnedStore = class {
9740
9817
  commitPhaseEntered(input) {
9741
9818
  return this.store.commitPhaseEntered(this.lease, input);
9742
9819
  }
9820
+ commitPhaseOutput(input) {
9821
+ return this.store.commitPhaseOutput(this.lease, input);
9822
+ }
9743
9823
  commitInputRequired(input) {
9744
9824
  return this.store.commitInputRequired(this.lease, input);
9745
9825
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.15.3",
3
+ "version": "0.15.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",