@sema-agent/core
Version:
Stateless, task-oriented AI agent core
93 lines (92 loc) • 6.36 kB
TypeScript
import type { PeerInboundChainRef } from "../../agents/peer-admission.js";
import { type SafeNotifier } from "../safe-notify.js";
import { type NotificationInjectionOutcome, type PendingSessionNotifications, type SystemInjectionPriority, type TaskNotificationPayload } from "../task-notification.js";
import type { PushQueue } from "../push-queue.js";
import type { TaskEvent, TaskSpec } from "../types.js";
import type { Stats } from "./assemble-result.js";
import type { CaptureOptOutRef, LiveHandle, ManualCompactRef, McpRedialRef, NotificationLaneBindings, NotifyRef, Prepared, RunInternals, RunnerDepsSeat, TaskIdRef } from "./contracts.js";
export interface RunIdentityWiringInput {
/** borrowed-readonly — the task spec: the task id and the memory / notification seats it names. */
spec: TaskSpec;
/** borrowed-mutable — the run's event queue: the manifest, roster-delta, compaction_outcome and redelivered
* task_notification frames. */
queue: PushQueue<TaskEvent>;
/** borrowed-mutable — the leg's prepared seat: the harness sinks (`onUndrainedEngineNotes`, `engineInjectionsHeld`,
* `onUndrainedUserInputs`, `onEngineNoteConsumed`) are installed, `nextTurn` is appended to; the ids, the identity
* envelope, the hold refs, the memory session and the listing / roster faces are read. */
prepared: Prepared;
/** borrowed-readonly — the trusted run-scoped channel: `parentToolCallId`, `onNotifyInjectorReady`. */
internals: RunInternals | undefined;
/** borrowed-mutable — the stream layer's backstop carrier: the memory scopes, the edited-files reader and the
* owed delegation terminal are published here the moment they exist. */
taskIdRef: TaskIdRef | undefined;
/** borrowed-readonly — the stream layer's readiness callback, fired ONCE with the live-task handle. */
onReady: (handle: LiveHandle) => void;
/** borrowed-mutable — the manual /compact seat: its mooted-frame channel is installed here. */
manualCompactRef: ManualCompactRef;
/** borrowed-mutable — the notify() bridge: `inject` is bound here (absent on the public path). */
notifyRef: NotifyRef | undefined;
/** borrowed-mutable — the capture opt-out bridge: `flip` is bound here when a memory session mounted. */
captureOptOutRef: CaptureOptOutRef | undefined;
/** borrowed-mutable — the MCP re-dial bridge: `redial` is bound here when the leg declared MCP servers. */
mcpRedialRef: McpRedialRef | undefined;
/** borrowed-readonly — the notification lane's ONE injection entry (the R0 lane's). */
injectTaskNotification: (notification: TaskNotificationPayload, opts?: {
priority?: SystemInjectionPriority;
}) => Promise<NotificationInjectionOutcome>;
/** borrowed-mutable — the turn-open dedup set (the cross-layer double-park dedup): a redelivered frame's key is registered here. */
deliveredAtTurnOpen: Set<string>;
/** borrowed-mutable — the peer inbound chain, overwritten by each consumed peer-class payload. */
peerInboundChainRef: PeerInboundChainRef;
/** borrowed-mutable — the notification lane's bindings seat (its own `let`s behind getters / setters, never a copy):
* this lane binds the harness, the session anchor and the identity mint the lane's closures read, and reads the
* anchor back in the undrained-notes sink. */
notificationLane: NotificationLaneBindings;
/** borrowed-mutable — the Runner's per-session parked-notification store: drained at turn open, re-pended on failure. */
pendingSessionNotifications: PendingSessionNotifications;
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onDelegationLifecycle`, `onNotice`). */
runner: RunnerDepsSeat;
}
export interface RunIdentityWiringResult {
/** The run's canonical task id (`spec.taskId ?? sessionId`) — one source, shared with `ident()`. */
runSourceTaskId: string;
/** The spawning tool call's id when this task runs AS A SUB-AGENT; undefined on a top-level run. */
parentToolCallId: string | undefined;
/** The event-identity mint: a fresh eventId per event, plus the sub-agent attribution when there is one. */
ident: () => {
eventId: string;
parentToolCallId?: string;
sourceTaskId?: string;
};
/** The delegation-lifecycle emission closure both stations share (spawn here, terminal in the driver). */
emitDelegationLifecycle: (event: import("../types.js").DelegationLifecycleEvent) => void;
/** The loop-liveness latch and the two attribution seats (ended / userInterrupted / userHalted). */
loopLatch: {
ended: boolean;
userInterrupted: boolean;
userHalted: boolean;
};
/** This leg's usage counters, zeroed here; the harness-handlers lane is their writer from the first turn on. */
stats: Stats;
/** The held agent_end account, a READ FACE over this lane's own `let` (the undrained-inputs sink writes it
* when the run committed a durable park); the terminal-adoption lane settles it minus what the park carried. */
undrainedUserAtEnd: {
readonly current: {
steer: number;
followUp: number;
} | undefined;
};
/** The run's ONE isolation scope for the {@link RunInternals} observation sinks: minted here because
* the manifest sink below is the run's first call into one, and handed on to the harness-handlers lane
* so its activity beats are contained by the SAME account — bounded disclosure is per notifier, so a
* second scope would report one broken sink twice and count it in two places. */
internalsNotifier: SafeNotifier;
/** Did the run END with a person's steer / follow-up still pending (queued, or drained at the final boundary and
* never served)? A READ FACE over this lane's own `let`, written by the same undrained-inputs sink on BOTH its arms
* (park or not): the terminal-adoption lane folds it into the answer-settled verdict — a "stop" answer the person had
* already asked to continue past is not a settled answer, so a stop that cut that continuation is a stop on work. */
userInputLostAtEnd: {
readonly current: boolean;
};
}
export declare function runIdentityWiring(input: RunIdentityWiringInput): RunIdentityWiringResult;