operon-agents 0.1.0-alpha.2 → 0.1.0-alpha.21

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.
@@ -24,7 +24,7 @@
24
24
  * `ExtensionRuntime` is the façade that hides which physical channel a decision point arrives on;
25
25
  * extension authors only ever see one `api.on(...)` table.
26
26
  */
27
- import type { AgentEvent, AssistantMessage, ChatModel, AgentInput, ContextBreakdown, ConversationContext, Injector, LlmRequest, Machine, Message, ModelRuntime, RunResult, SessionSummary, PendingApprovalInterrupt, SessionStore, SteerContent, SteerOrigin, SteerReceipt, StepStopReason, TerminalStepStopReason, ThinkingLevel, Tool, ToolPlan, ToolResult, ToolResultContent, ToolRunContext, Usage } from "operon-agents-core";
27
+ import type { AgentEvent, AssistantMessage, ChatModel, AgentInput, ContextBreakdown, ConversationContext, Injector, LlmRequest, Environment, Message, ModelRuntime, RunResult, SessionSummary, PendingApprovalInterrupt, SessionStore, SteerContent, SteerOptions, SteerOrigin, SteerReceipt, StepStopReason, TerminalStepStopReason, ThinkingLevel, Tool, ToolPlan, ToolResult, ToolResultContent, ToolRunContext, Usage } from "operon-agents-core";
28
28
  /** Per-extension key/value state, namespaced into the session store (memory without one). */
29
29
  /** A slash command an extension carries (see `ExtensionAPI.registerCommand`). The run
30
30
  * receives only the raw argument string — an extension command closes over what it needs. */
@@ -57,7 +57,7 @@ export interface ExtensionState {
57
57
  export type ModelProvider = Parameters<ModelRuntime["models"]["setProvider"]>[0];
58
58
  /**
59
59
  * Operations that exist above the agent loop: other sessions, and the model provider registry.
60
- * Supplied by `Harness` when it builds the extensions capability. This is exactly why the
60
+ * Supplied by `Harness` when it builds an extension's capability. This is exactly why the
61
61
  * extension runtime lives in `operon-agents` and not in core — core has no concept of "another
62
62
  * session", so an interface defined down there would have been half stubs.
63
63
  *
@@ -107,17 +107,18 @@ export interface ExtensionHost {
107
107
  export interface HarnessSessionHandle {
108
108
  readonly id: string;
109
109
  prompt(input: AgentInput): Promise<RunResult>;
110
- steer(input: string): string;
111
- followUp(input: string): string | null;
110
+ steer(input: string): SteerReceipt;
111
+ followUp(input: string): SteerReceipt | null;
112
112
  /**
113
113
  * Hand a message to a specific frame in that session — `main` for its root agent,
114
- * `main/<agentId>` for one of its subagents — carrying your own provenance. `false` when no
115
- * frame is running there.
114
+ * `main/<agentId>` for one of its subagents — carrying your own provenance. Undefined when no
115
+ * frame is running there. The receipt's `steerId` (your own, via `options.id`, or minted) is
116
+ * what the recipient's journal carries as `origin.steerId` once the message is consumed.
116
117
  *
117
118
  * `steer`/`followUp` above can only ever reach the root; this is what lets an extension address
118
119
  * an individual subagent, which is what coordination between agents requires.
119
120
  */
120
- steerTo(address: string, content: string, origin: SteerOrigin): boolean;
121
+ steerTo(address: string, content: string, origin: SteerOrigin, options?: SteerOptions): SteerReceipt | undefined;
121
122
  cancel(): void;
122
123
  close(): Promise<void>;
123
124
  }
@@ -195,7 +196,7 @@ interface ExtensionContextBase {
195
196
  readonly extensionId: string;
196
197
  readonly sessionId: string;
197
198
  readonly signal: AbortSignal;
198
- readonly machine: Machine;
199
+ readonly environment: Environment;
199
200
  readonly store?: SessionStore;
200
201
  readonly state: ExtensionState;
201
202
  readonly actions: ExtensionActions;
@@ -204,18 +205,18 @@ interface ExtensionContextBase {
204
205
  export interface ExtensionEventContext extends ExtensionContextBase {
205
206
  readonly address: string;
206
207
  }
207
- /** Context for session-tier events, which have no active shard. */
208
- export interface ExtensionSessionContext extends ExtensionContextBase {
208
+ /** Context for session-tier events (`session.start` / `session.end`), which have no active shard. */
209
+ export interface ExtensionSessionEventContext extends ExtensionContextBase {
209
210
  readonly address?: never;
210
211
  }
211
- /** `attach` = added to a live session via `attachExtension`, after its `setup` succeeded. */
212
+ /** `attach` = added to a live session via `attachExtension`, after its `session` succeeded. */
212
213
  export type SessionStartReason = "open" | "resume" | "fork" | "attach";
213
214
  /** `detach` = removed from a live session via `detachExtension`; fires before teardown. */
214
215
  export type SessionEndReason = "close" | "shutdown" | "detach";
215
- export interface ExtensionSessionStartEvent extends ExtensionSessionContext {
216
+ export interface ExtensionSessionStartEvent extends ExtensionSessionEventContext {
216
217
  readonly reason: SessionStartReason;
217
218
  }
218
- export interface ExtensionSessionEndEvent extends ExtensionSessionContext {
219
+ export interface ExtensionSessionEndEvent extends ExtensionSessionEventContext {
219
220
  readonly reason: SessionEndReason;
220
221
  }
221
222
  export interface ExtensionStepStartEvent extends ExtensionEventContext {
@@ -351,12 +352,10 @@ export interface ExtensionCompactionBeforeResult {
351
352
  readonly count?: number;
352
353
  };
353
354
  }
354
- /**
355
- * Headers a provider request carries. `null` deletes a header pi would otherwise send.
356
- * Mirrors pi-ai's `ProviderHeaders`, spelled out here so the extension contract does not
357
- * depend on a type core has no reason to re-export.
358
- */
359
- export type ProviderHeaders = Record<string, string | null>;
355
+ /** Headers a provider request carries (`null` deletes a header) — core's type, the one
356
+ * capability provider hooks use too. */
357
+ export type { ProviderHeaders } from "operon-agents-core";
358
+ import type { ProviderHeaders } from "operon-agents-core";
360
359
  /**
361
360
  * These three fire BELOW the loop: the runtime folds them into the request's
362
361
  * `providerOptions`, and pi-ai calls back from inside its HTTP path. Two consequences the
@@ -503,23 +502,24 @@ export interface ExtensionAPI {
503
502
  /**
504
503
  * This extension's own journal records, oldest first — the event-sourcing read path.
505
504
  * The open-time snapshot rides the session's single shared memoized log read (no extra
506
- * traversal); records appended this session are included. Fold these in `setup` to rebuild
505
+ * traversal); records appended this session are included. Fold these in `session` to rebuild
507
506
  * sourced state; prefer `state` when a snapshot is all you need.
508
507
  */
509
508
  records(): Promise<readonly ExtensionRecordEntry[]>;
510
509
  /** Durable per-extension KV (SessionStore-backed) — the same facade handlers get via
511
- * `ctx.state`, available from `setup` so state can be loaded before the first run. */
510
+ * `ctx.state`, available from `session` so state can be loaded before the first run. */
512
511
  readonly state: ExtensionState;
513
- /** The same imperative surface handlers get via `ctx.actions`, usable from `setup`. */
512
+ /** The same imperative surface handlers get via `ctx.actions`, usable from `session`. */
514
513
  readonly actions: ExtensionActions;
515
514
  }
516
515
  /**
517
- * What an extension's `create` half is handed — the harness reach it needs to build a
516
+ * What an extension's `harness` half is handed — the harness reach it needs to build a
518
517
  * process-shared instance. Deliberately narrow: session creation (a spawn factory's one
519
- * requirement) and a data directory (the file form's own folder; absent by value). No
520
- * service-registration call: the instance IS the return value, registered under the extension's `id`.
518
+ * requirement), a data directory (the file form's own folder; absent by value) and the handles
519
+ * of the services it declared in `uses`. No service-registration call: the instance IS the
520
+ * return value, registered under the extension's `id`.
521
521
  */
522
- export interface ExtensionHostContext {
522
+ export interface ExtensionHostContext<TServices extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>> {
523
523
  /** Open a brand-new session on this harness — what a spawn factory calls. */
524
524
  createSession(options?: {
525
525
  readonly title?: string;
@@ -528,12 +528,20 @@ export interface ExtensionHostContext {
528
528
  } & Record<string, unknown>): Promise<{
529
529
  readonly id: string;
530
530
  }>;
531
+ /**
532
+ * Handles to the services named in `uses`, by name — the same handles `session` gets as
533
+ * `ctx.services`, available to the process half too. What lets a file-loaded bundle take its
534
+ * configuration from a host-registered service (`createHarness({ services })`) instead of
535
+ * baking it in: a reload re-runs `harness`, so re-reading the service IS the config update.
536
+ * Method calls resolve the CURRENT provider; the handles expose methods only.
537
+ */
538
+ readonly services: TServices;
531
539
  /** The extension's own folder when it was file-loaded; `undefined` when passed by value.
532
540
  * Code only — an update replaces it wholesale. Keep files in `dataDir`. */
533
541
  readonly dir?: string;
534
542
  /**
535
543
  * Where this extension keeps its files: a folder of its own, by id, OUTSIDE the code folder,
536
- * so replacing the bundle (update) leaves it untouched. Created before `create` runs. Present
544
+ * so replacing the bundle (update) leaves it untouched. Created before `harness` runs. Present
537
545
  * whenever the harness has a data root — `extensionDir` implies one (`<extensionDir>/.data`);
538
546
  * by value it is opt-in (`createHarness({ extensionDataDir })`).
539
547
  */
@@ -541,13 +549,16 @@ export interface ExtensionHostContext {
541
549
  warn(message: string): void;
542
550
  }
543
551
  /**
544
- * What `setup` receives besides the API: the handles the framework resolved for this extension
552
+ * What `session` receives besides the API: the handles the framework resolved for this extension
545
553
  * in this session. Nothing here is looked up by name from inside the extension — every service
546
- * it may touch was declared on the definition (`create` for its own, `uses` for others') and
554
+ * it may touch was declared on the definition (`harness` for its own, `uses` for
555
+ * others') and
547
556
  * arrives resolved.
548
557
  */
549
- export interface ExtensionSetupContext<TShared = unknown, TParams = unknown, TServices extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>> {
550
- /** Handle to this extension's own `create` result — `undefined` when it has no `create`. */
558
+ export interface ExtensionSessionContext<TShared = unknown, TParams = unknown, TServices extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>> {
559
+ /** Handle to this extension's own shared instance — its `harness` result (one per process) or
560
+ * its `workspace` result (this session's workspace's); `undefined` when it has neither. The
561
+ * session half does not know, and need not know, which tier it lives at. */
551
562
  readonly shared: TShared;
552
563
  /** This session's per-session argument (`createSession({ params: { [id]: … } })`); `undefined` when none. */
553
564
  readonly params: TParams | undefined;
@@ -561,17 +572,17 @@ export interface ExtensionSetupContext<TShared = unknown, TParams = unknown, TSe
561
572
  /**
562
573
  * An extension: a programmatic participant assembled into a session. One definition, handed to
563
574
  * the framework once — by value in `createHarness({ extensions })` or from a file in
564
- * `extensionDir` — and mounted into every session from then on. Three parts, the first two
565
- * optional:
575
+ * `extensionDir` — and mounted into every session from then on. Four parts, the first three
576
+ * optional, named for the tier each one runs at (the same three tiers as `createHarness`'s
577
+ * `harness` / `workspace` / `session` hooks):
566
578
  *
567
- * - **`create` — the process-shared half.** Runs ONCE per harness, not per session. Its return
568
- * value is registered as a service under this extension's `id`; every session's `setup` then
569
- * receives a stable handle to it as `ctx.shared`. There is no separate type and no separate
570
- * option for an extension with a `create` — only this field.
579
+ * - **`harness` — the process-shared half.** Runs ONCE per harness, not per session. Its return
580
+ * value is registered as a service under this extension's `id` in the harness scope; every
581
+ * session's `session` then receives a stable handle to it as `ctx.shared`.
571
582
  * - **`uses` — the services of others it consumes.** Names only; checked when the definition is
572
- * registered (a consumer must come after its provider) and handed to `setup` resolved as
583
+ * registered (a consumer must come after its provider) and handed to `session` resolved as
573
584
  * `ctx.services[name]`. There is no lookup by name from inside an extension.
574
- * - **`setup` — the per-session half.** Runs once per session with the resolved context. A
585
+ * - **`session` — the per-session half.** Runs once per session with the resolved context. A
575
586
  * session varies it with `createSession({ params: { [id]: … } })` — `ctx.params` — and opts
576
587
  * out of it entirely with `false`.
577
588
  *
@@ -583,12 +594,11 @@ export interface ExtensionDefinition<TShared = unknown, TParams = unknown, TServ
583
594
  readonly id: string;
584
595
  /** Per-handler invocation budget. Defaults to 30s for decision points, 1s for observers. */
585
596
  readonly timeoutMs?: number;
586
- /** The process-shared half. Absent ⇒ an ordinary per-session extension. See above. */
587
- create?(host: ExtensionHostContext): TShared | Promise<TShared>;
588
- /** Services this extension consumes, by name — other extensions' `create` results (their
589
- * `id`s) or host-registered `services`. Resolved into `ctx.services` for `setup`. */
597
+ /** The process-shared half: once per harness. See above. */
598
+ harness?(host: ExtensionHostContext<TServices>): TShared | Promise<TShared>;
599
+ /** Services this extension consumes, by name — other extensions' shared-half results (their
600
+ * `id`s) or host-registered `services`. Resolved into `ctx.services` for `session`. */
590
601
  readonly uses?: readonly (keyof TServices & string)[];
591
- setup(api: ExtensionAPI, ctx: ExtensionSetupContext<TShared, TParams, TServices>): void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>;
602
+ session(api: ExtensionAPI, ctx: ExtensionSessionContext<TShared, TParams, TServices>): void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>;
592
603
  }
593
- export {};
594
604
  //# sourceMappingURL=types.d.ts.map