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.
@@ -1,5 +1,6 @@
1
- import type { HeadlessCommand } from "operon-agents-core";
2
- import type { AssistantMessage, CapabilityContext, CompactionGate, ChatModel, ConversationContext, Injector, LlmRequest, Message, SessionContext, StepStopReason, TerminalStepStopReason, Tool, ToolPlan, ToolResult, Usage } from "operon-agents-core";
1
+ import type { Environment, EventSink, SteerBus } from "operon-agents-core";
2
+ import type { AgentRecord, HeadlessCommand } from "operon-agents-core";
3
+ import type { AssistantMessage, CapabilityProviderHooks, RunContext, CompactionGate, ChatModel, ConversationContext, Injector, LlmRequest, Message, SessionContext, SessionControls, SessionStore, StepStopReason, TerminalStepStopReason, Tool, ToolPlan, ToolResult, Usage } from "operon-agents-core";
3
4
  import type { ExtensionDefinition, ExtensionHost, ExtensionModelRequestResult, ExtensionStepEndResult, ExtensionStepStartResult, ExtensionToolAuthorizeResult, ExtensionToolCallResult, SessionEndReason, SessionStartReason } from "./types.ts";
4
5
  /** Shared shape of the loop-hook contexts the dispatch methods are fed from. */
5
6
  interface StepOrigin {
@@ -9,37 +10,48 @@ interface StepOrigin {
9
10
  readonly signal: AbortSignal;
10
11
  readonly model: ChatModel;
11
12
  }
13
+ /**
14
+ * The session services the extensions capability declares (see `extensionsCapability`). Named
15
+ * here because this is where they are used; the declaration that fills it lives next to the
16
+ * capability, so the two can be checked against each other by eye.
17
+ */
18
+ export interface ExtensionServices {
19
+ readonly environment: Environment;
20
+ readonly events: EventSink;
21
+ readonly steer: SteerBus;
22
+ readonly controls: SessionControls;
23
+ readonly readLog: () => Promise<readonly AgentRecord[]>;
24
+ readonly store: SessionStore | undefined;
25
+ }
26
+ /**
27
+ * One extension, running in one session. `extensionCapability` wraps it as that session's
28
+ * capability, so everything around the extension — assembly, hook isolation, attach and detach
29
+ * at a run boundary, its state and records — is the engine's, the same as for any capability.
30
+ * What is left here is the translation the extension API exists for: `api` registrations into
31
+ * capability parts, and the engine's decision points into the extension's event vocabulary.
32
+ */
12
33
  export declare class ExtensionRuntime {
13
- private readonly definitions;
34
+ readonly definition: ExtensionDefinition;
14
35
  private readonly handlers;
15
36
  private readonly tools;
16
- /** Stable reference: `extensionsCapability` hands this array to the assembler, and `setup`
37
+ /** Stable reference: `extensionCapability` hands this array to the assembler, and `session`
17
38
  * (which runs at openSession, before any run assembles) fills it in place. */
18
39
  private readonly injectors;
19
- /** Slash commands by normalized name — surfaced to the session's registry via the
20
- * `sessionCommands()` duck protocol. Two extensions claiming one name fail closed. */
21
- private readonly extCommands;
22
- /** Host-facing control surfaces published via `api.expose`, by extension id. */
23
- private readonly exposedHandles;
24
- /** Records read path: open-time snapshot buckets (built lazily off the session's shared
25
- * memoized log read — zero extra traversal) + everything recorded this session. */
26
- private recordSnapshot;
27
- private readonly recordWrites;
28
- /** Per-extension teardown: setup's cleanup + every registration, undone in reverse. */
29
- private readonly scopes;
30
- /** Extensions whose contributions are currently honored. An id leaves on detach (and on
31
- * setup failure), which turns every `actions`/`api` closure the extension still holds
32
- * into a warn-and-noop — a detached extension must not keep steering the session. */
33
- private readonly live;
34
- /** Changes wait here until a quiet point: mid-run requests apply at the run's stop
35
- * boundary, so a turn never sees its toolset change underneath it. */
36
- private pending;
37
- /** Serializes flushes so concurrent attach/detach apply strictly in submission order. */
38
- private flushChain;
39
- private readonly memoryState;
40
+ /** Slash commands, filled in place by `api.registerCommand` — the capability's `commands`. */
41
+ readonly commands: HeadlessCommand[];
42
+ /** The host-facing control surface published via `api.expose`. */
43
+ private exposed;
44
+ /** `session()`'s cleanup plus every registration, undone in reverse. */
45
+ private teardown;
46
+ /** False until `session` has run, and again once the extension is closed: every `actions` /
47
+ * `api` closure it still holds turns into a warn-and-noop — a detached extension must not
48
+ * keep steering the session. */
49
+ private live;
50
+ /** The session binding: the services the capability DECLARED, plus the session's id/signal. */
40
51
  private session;
41
52
  private run;
42
- /** The conversation shard the in-flight decision point belongs to; backs `actions.record`. */
53
+ /** The conversation shard the in-flight decision point belongs to — the address a
54
+ * `compaction.before` handler is told about. */
43
55
  private activeContext;
44
56
  /** Snapshot of the last assembled registry, refreshed once per turn by `filterTools`. */
45
57
  private allToolNames;
@@ -48,46 +60,31 @@ export declare class ExtensionRuntime {
48
60
  private reportingWarning;
49
61
  /** Harness reach. Absent when the capability is built standalone (bare Runner / tests). */
50
62
  private readonly host;
51
- /** This session's per-session extension arguments, by extension id. A value of `false` means
52
- * "skip this extension for this session"; any other value is passed to `setup` as `params`. */
63
+ /** This session's argument for the extension (`createSession({ params: { [id]: … } })`). */
53
64
  private readonly params;
54
- constructor(definitions: readonly ExtensionDefinition[], host?: ExtensionHost, params?: Readonly<Record<string, unknown>>);
55
- open(ctx: SessionContext, reason?: SessionStartReason): Promise<void>;
56
- attachRun(ctx: CapabilityContext): void;
57
- detachRun(): Promise<void>;
65
+ /** What `session.start` reports: `attach` for an extension added to a live session. */
66
+ private readonly startReason;
67
+ constructor(definition: ExtensionDefinition, options?: {
68
+ readonly host?: ExtensionHost;
69
+ readonly params?: unknown;
70
+ readonly startReason?: SessionStartReason;
71
+ });
72
+ get id(): string;
73
+ /** Run `session` and fire `session.start`. Throws when `session` does — the capability is then
74
+ * absent from the session, with nothing it registered left behind. */
75
+ open(services: ExtensionServices, ctx: SessionContext): Promise<void>;
76
+ attachRun(ctx: RunContext): void;
77
+ detachRun(): void;
78
+ /** Fire `session.end` while the handlers are still registered, then unwind everything. */
58
79
  close(reason?: SessionEndReason): Promise<void>;
59
- /**
60
- * Add an extension to the live session. Resolves once its `setup` has run and its
61
- * contributions are in place — with no run in flight that is immediately; mid-run it is
62
- * the current run's stop boundary, so an in-flight turn never sees its registry change.
63
- * Rejects on duplicate/empty id or when `setup` throws.
64
- */
65
- attach(definition: ExtensionDefinition): Promise<void>;
66
- /** Ids of currently attached extensions — the reshape coordinator's affected-set probe. */
67
- attachedIds(): readonly string[];
68
- /** Currently attached extensions with what each declared it `uses` — the unload consumer scan. */
69
- attachedExtensions(): readonly {
70
- readonly id: string;
71
- readonly uses: readonly string[];
72
- }[];
73
- /** The duck protocol the session's command registry consumes: dynamic commands contributed
74
- * by attached extensions (`api.registerCommand`). */
75
- sessionCommands(): readonly HeadlessCommand[];
76
- /** The control surface `extensionId` published via `api.expose`; undefined when absent
77
- * (never attached, detached, or nothing exposed). */
78
- exposedHandle<T = unknown>(extensionId: string): T | undefined;
79
- /** Remove an extension: its `session.end` fires, then its whole scope is torn down. */
80
- detach(id: string): Promise<void>;
81
- private submit;
82
- private flushPending;
83
- private drainPending;
84
- private attachNow;
85
- private detachNow;
86
- /** Runs one extension's `setup` and files its scope. Failure ⇒ skipped, contributions undone. */
80
+ /** The control surface published via `api.expose`; undefined when nothing is (or it was
81
+ * disposed, or the extension is closed). */
82
+ exposedHandle<T = unknown>(): T | undefined;
83
+ /** Runs one extension's `session` and files its scope. Failure ⇒ skipped, contributions undone. */
87
84
  private setupExtension;
88
85
  /**
89
- * Durable audit trail: replay needs "tool X only exists after record N" to reconstruct the
90
- * capability timeline. Rides the `custom` record type — audit-only, ignored by reducers.
86
+ * Durable audit trail of when this extension joined or left the session — written to the
87
+ * session's audit shard, which nothing replays from.
91
88
  */
92
89
  private logChange;
93
90
  listTools(): readonly Tool[];
@@ -127,13 +124,17 @@ export declare class ExtensionRuntime {
127
124
  } | undefined>;
128
125
  beforeModelRequest(origin: StepOrigin, request: LlmRequest, context: ConversationContext): Promise<ExtensionModelRequestResult | undefined>;
129
126
  /**
130
- * Attach `transformHeaders` / `onPayload` / `onResponse` when anything is listening. Returns
131
- * `undefined` when nothing is, so a request with no provider-tier extensions is left byte-identical.
132
- *
133
- * These fire once per HTTP ATTEMPT, so a retry re-runs them — the contract tells handlers to be
134
- * idempotent, and the runtime does not try to dedupe on their behalf.
127
+ * The capability's provider hooks — `provider.headers` / `payload` / `response`. The engine
128
+ * composes them into the request with every other capability's, so two extensions rewriting
129
+ * headers both take effect instead of the second replacing the first. They fire once per HTTP
130
+ * ATTEMPT, so a retry re-runs them — the contract tells handlers to be idempotent, and the
131
+ * runtime does not try to dedupe on their behalf.
135
132
  */
136
- private withProviderHooks;
133
+ readonly providerHooks: CapabilityProviderHooks;
134
+ /** Whether any provider-tier handler is registered — the capability omits `provider` otherwise,
135
+ * so a request with no provider-tier extension is left byte-identical. */
136
+ hasProviderHandlers(): boolean;
137
+ private providerContext;
137
138
  afterModelResponse(origin: StepOrigin, request: LlmRequest, response: AssistantMessage, context: ConversationContext): Promise<AssistantMessage | undefined>;
138
139
  beforeToolCall(origin: StepOrigin, toolName: string, toolCallId: string, tool: Tool | undefined, args: unknown): Promise<ExtensionToolCallResult | undefined>;
139
140
  authorizeToolCall(origin: StepOrigin, toolName: string, toolCallId: string, tool: Tool | undefined, args: unknown, plan: ToolPlan): Promise<ExtensionToolAuthorizeResult | undefined>;
@@ -173,12 +174,6 @@ export declare class ExtensionRuntime {
173
174
  private viaHost;
174
175
  private sessionContext;
175
176
  private eventContext;
176
- /** Open-time record buckets, built ONCE off the session's shared memoized log read — the
177
- * same single read goal/plan/todo fold from, so `records()` adds zero log traversals. One
178
- * filter pass buckets every extension's records; ids are colon-free slugs so the
179
- * "extension:<id>:" prefix parse is unambiguous. */
180
- private ensureRecordSnapshot;
181
- private stateFor;
182
177
  private handlersFor;
183
178
  private invoke;
184
179
  private warn;