operon-agents 0.1.0-alpha.23 → 0.1.0-alpha.25

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/harness.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * low-level "assemble it yourself / stateless server" path, import from
12
12
  * `operon-agents/core` instead.
13
13
  */
14
- import { type AgentEvent, type EventPublicationMode, type TelemetryService, type AgentEventListener, type AgentInput, SessionProjection, type SessionSnapshot, type SnapshotOptions, type DirectoryEntry, type ProjectionObservation, type ProjectionListener, type ApprovalRequest, type ApprovalResponse, type Capability, type InterruptAnswer, type ChatModel, ListenerSink, type PermissionManagerOptions, type PermissionMode, type PendingRunInterrupt, type QuestionRequest, type QuestionResult, type Responder, type RunHandle, type RunResult, type SessionStore, type SessionHandle, type SessionSummary, type ListSessionsFilter, type OpenSessionOptions, type DeleteSessionOptions, type ThinkingLevel, type Tool, type SteerMessage, type SteerOptions, type SteerOrigin, type SteerReceipt, Agent, Runner, Session, McpOAuthService, SkillRegistry, type HookDef, type McpServerConfig, type McpTransportKind, type McpCredentialProvider, type PluginManager, type ApprovalRequestOptions, type Environment, type EnvironmentFactory, type SessionRepository, type ResolvedAgentProfile, type SubagentProvider } from "operon-agents-core";
14
+ import { type EventPublicationMode, type TelemetryService, type AgentEventListener, type AgentInput, SessionProjection, type SessionSnapshot, type SnapshotOptions, type DirectoryEntry, type ProjectionObservation, type ProjectionListener, type ApprovalRequest, type ApprovalResponse, type Capability, type InterruptAnswer, type ChatModel, ListenerSink, type PermissionManagerOptions, type PermissionMode, type PendingRunInterrupt, type QuestionRequest, type QuestionResult, type Responder, type RunHandle, type RunResult, type SessionHandle, type SessionSummary, type ListSessionsFilter, type OpenSessionOptions, type DeleteSessionOptions, type ThinkingLevel, type Tool, type SteerMessage, type SteerOptions, type SteerOrigin, type SteerReceipt, Agent, Runner, Session, McpOAuthService, SkillRegistry, type HookDef, type McpServerConfig, type McpTransportKind, type McpCredentialProvider, type PluginManager, type ApprovalRequestOptions, type Environment, type EnvironmentFactory, type SessionRepository, type ResolvedAgentProfile, type SubagentProvider } from "operon-agents-core";
15
15
  import type { SkillsService, CompactionService, BackgroundManager, McpServersHandle, GoalStore, PlanMode, Logger, ModelRuntime, TracingProcessor } from "operon-agents-core";
16
16
  import { type WorkspaceMcpPool } from "./workspace-mcp.ts";
17
17
  import { HarnessExtensionManager, ServiceRegistry, type ExtensionDefinition, type ServiceOptions } from "./extensions/index.ts";
@@ -874,26 +874,6 @@ export declare class Harness<TContext = unknown> {
874
874
  private allDefinitions;
875
875
  private contextFor;
876
876
  }
877
- /**
878
- * A cold open proves that no in-process run still owns lifecycle frames left open in the
879
- * previous journal. Close those frames durably so historical event consumers and Projection
880
- * agree with HarnessSession.status. A durable interruption is excluded by the caller: its
881
- * open turn is intentional continuation state, not a crash remnant.
882
- */
883
- /**
884
- * Close the turns a dead process left open, without opening the session.
885
- *
886
- * A worker that dies mid-turn journals no `turn.ended`; to every reader the turn is still
887
- * running. Opening the session repairs that (the same recovery runs inside `resumeSession`),
888
- * but opening boots capabilities and an environment just to write two records. This does only the
889
- * repair: fold the log, and for every frame still inside a turn append `turn.ended` with
890
- * `reason: "failed"` (and `agent.ended` for a live sub-agent). Returns the events those records
891
- * project to, so a host that has live subscribers can hand them on — a record appended here
892
- * reaches the log, not any broadcast channel.
893
- *
894
- * A session paused for an answer is left alone: its open turn is waiting, not dead.
895
- */
896
- export declare function closeOrphanedTurns(sessionId: string, store: SessionStore): Promise<readonly AgentEvent[]>;
897
877
  /** A reshape rendezvous that did not converge in time. Nothing was changed; the sessions that
898
878
  * never reached their run boundary are named so the caller can act on them and retry. */
899
879
  export declare class BarrierTimeout extends Error {
package/dist/harness.js CHANGED
@@ -11,7 +11,7 @@
11
11
  * low-level "assemble it yourself / stateless server" path, import from
12
12
  * `operon-agents/core` instead.
13
13
  */
14
- import { readSessionTails, SessionProjection, ListenerSink, agentEventFromRecord, newAgentEventId, Agent, buildAgentFromProfile, INTERRUPTION_STATE_KEY, flattenPendingInterrupts, parseInterruptionState, Runner, Session, emptyUsage, isGuardrailTripwireError, askUserQuestionTool, backgroundCapability, compactionCapability, filesystemTools, goalCapability, LocalEnvironment, McpOAuthService, MemorySessionRepository, SessionRepositoryNotFoundError, planCapability, skillsCapability, SkillRegistry, mcpServersCapability, pluginsCapability, userHooksCapability, taskCapability, workflowCapability, DEFAULT_AGENT_PROFILES, DEFAULT_AGENT_PROFILE_NAME, DEFAULT_SUBAGENT_NAMES, profileSubagentProvider, DEFAULT_ADDRESS, envLogger, noopLogger, } from "operon-agents-core";
14
+ import { readSessionTails, SessionProjection, ListenerSink, recoverOrphanedTurns, Agent, buildAgentFromProfile, INTERRUPTION_STATE_KEY, flattenPendingInterrupts, parseInterruptionState, Runner, Session, emptyUsage, isGuardrailTripwireError, askUserQuestionTool, backgroundCapability, compactionCapability, filesystemTools, goalCapability, LocalEnvironment, McpOAuthService, MemorySessionRepository, SessionRepositoryNotFoundError, planCapability, skillsCapability, SkillRegistry, mcpServersCapability, pluginsCapability, userHooksCapability, taskCapability, workflowCapability, DEFAULT_AGENT_PROFILES, DEFAULT_AGENT_PROFILE_NAME, DEFAULT_SUBAGENT_NAMES, profileSubagentProvider, DEFAULT_ADDRESS, envLogger, noopLogger, } from "operon-agents-core";
15
15
  import { mkdirSync } from "node:fs";
16
16
  import { workspaceMcpCapability } from "./workspace-mcp.js";
17
17
  import { join } from "node:path";
@@ -1515,9 +1515,12 @@ export class Harness {
1515
1515
  projection = await SessionProjection.attach({ id, store, events }, preloadedLog);
1516
1516
  const interrupted = await store.getState(INTERRUPTION_STATE_KEY) !== null;
1517
1517
  if (!interrupted) {
1518
- const recoveryRecords = await closeOrphanedProjectionFrames(id, store, projection);
1519
- if (recoveryRecords.length > 0)
1518
+ const recoveryRecords = await recoverOrphanedTurns(id, store, preloadedLog);
1519
+ if (recoveryRecords.length > 0) {
1520
+ for (const record of recoveryRecords)
1521
+ projection.applyRecord(record);
1520
1522
  preloadedLog = [...preloadedLog, ...recoveryRecords];
1523
+ }
1521
1524
  }
1522
1525
  const capabilities = await this.resolveCapabilities({
1523
1526
  sessionId: id,
@@ -1620,70 +1623,6 @@ export class Harness {
1620
1623
  return hasOwnContext(options) ? options.context : this.options.context;
1621
1624
  }
1622
1625
  }
1623
- /**
1624
- * A cold open proves that no in-process run still owns lifecycle frames left open in the
1625
- * previous journal. Close those frames durably so historical event consumers and Projection
1626
- * agree with HarnessSession.status. A durable interruption is excluded by the caller: its
1627
- * open turn is intentional continuation state, not a crash remnant.
1628
- */
1629
- /**
1630
- * Close the turns a dead process left open, without opening the session.
1631
- *
1632
- * A worker that dies mid-turn journals no `turn.ended`; to every reader the turn is still
1633
- * running. Opening the session repairs that (the same recovery runs inside `resumeSession`),
1634
- * but opening boots capabilities and an environment just to write two records. This does only the
1635
- * repair: fold the log, and for every frame still inside a turn append `turn.ended` with
1636
- * `reason: "failed"` (and `agent.ended` for a live sub-agent). Returns the events those records
1637
- * project to, so a host that has live subscribers can hand them on — a record appended here
1638
- * reaches the log, not any broadcast channel.
1639
- *
1640
- * A session paused for an answer is left alone: its open turn is waiting, not dead.
1641
- */
1642
- export async function closeOrphanedTurns(sessionId, store) {
1643
- if ((await store.getState(INTERRUPTION_STATE_KEY)) !== null)
1644
- return [];
1645
- const projection = await SessionProjection.attach({ id: sessionId, store, events: new ListenerSink() }, await readSessionTails(store));
1646
- const records = await closeOrphanedProjectionFrames(sessionId, store, projection);
1647
- const events = [];
1648
- for (const record of records) {
1649
- const event = agentEventFromRecord(record, sessionId);
1650
- if (event !== undefined)
1651
- events.push(event);
1652
- }
1653
- return events;
1654
- }
1655
- async function closeOrphanedProjectionFrames(sessionId, store, projection) {
1656
- const recovered = [];
1657
- const snapshot = projection.snapshot({ maxMessages: 0 });
1658
- for (const agent of snapshot.agents) {
1659
- if (agent.turn !== undefined) {
1660
- await appendRecoveryLifecycle({
1661
- type: "event.lifecycle",
1662
- eventId: newAgentEventId(),
1663
- time: Date.now(),
1664
- address: agent.address,
1665
- event: { type: "turn.ended", turnId: agent.turn.turnId, reason: "failed" },
1666
- });
1667
- }
1668
- if (agent.live && agent.agent !== undefined) {
1669
- await appendRecoveryLifecycle({
1670
- type: "event.lifecycle",
1671
- eventId: newAgentEventId(),
1672
- time: Date.now(),
1673
- address: agent.address,
1674
- event: { type: "agent.ended", agent: agent.agent },
1675
- });
1676
- }
1677
- }
1678
- return recovered;
1679
- async function appendRecoveryLifecycle(record) {
1680
- await store.appendRecord(record);
1681
- recovered.push(record);
1682
- const event = agentEventFromRecord(record, sessionId);
1683
- if (event !== undefined)
1684
- projection.apply(event, record.time ?? Date.now());
1685
- }
1686
- }
1687
1626
  /** A reshape rendezvous that did not converge in time. Nothing was changed; the sessions that
1688
1627
  * never reached their run boundary are named so the caller can act on them and retry. */
1689
1628
  export class BarrierTimeout extends Error {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "operon-agents",
3
- "version": "0.1.0-alpha.23",
3
+ "version": "0.1.0-alpha.25",
4
4
  "description": "Public SDK entrypoint for building agents.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -73,11 +73,11 @@
73
73
  "posthog-node": "^5.51.6",
74
74
  "zod": "^4.4.3",
75
75
  "smol-toml": "^1.6.1",
76
- "@earendil-works/pi-ai": "1.3.0",
77
- "operon-agents-core": "0.1.0-alpha.23"
76
+ "@earendil-works/pi-ai": "1.5.0",
77
+ "operon-agents-core": "0.1.0-alpha.25"
78
78
  },
79
79
  "devDependencies": {
80
- "@earendil-works/pi-ai": "1.3.0"
80
+ "@earendil-works/pi-ai": "1.5.0"
81
81
  },
82
82
  "scripts": {
83
83
  "clean": "rm -rf dist *.tsbuildinfo",