blob: 093eac2ae4ba1fb5170cfcc5b84d2d7b9df80592 [file]
import { isDeepStrictEqual } from 'node:util';
import type {
SandboxBoundaryDecisionAckEvent,
SandboxBoundaryRequestEvent,
UserQuestionAnswerAckEvent,
UserQuestionRequestEvent,
} from '@maka/core';
import type {
InteractionCanonicalPermissionOutcome,
InteractionClosureReason,
InteractionPermissionRequest,
SandboxBoundarySettlement,
} from '@maka/core';
import type {
HostedInteractionBridge,
HostedSandboxBoundarySettlement,
HostedUserQuestionAnswer,
HostedUserQuestionSettlement,
} from '@maka/core';
export type RuntimeInteractionClosureReason = InteractionClosureReason;
export type RuntimeInteractionRunClosureReason = Extract<
RuntimeInteractionClosureReason,
'turn_stopped' | 'turn_terminal'
>;
export type RuntimeUserQuestionClosureReason = Exclude<InteractionClosureReason, 'timed_out'>;
export interface RuntimeInteractionContinuationIdentity {
readonly requestId: string;
readonly turnId: string;
readonly runId: string;
}
export interface RuntimeInteractionRunIdentity {
readonly sessionId: string;
readonly turnId: string;
readonly runId: string;
}
export type RuntimeUserQuestionAnswer = HostedUserQuestionAnswer;
export type RuntimeUserQuestionOutcome =
| { kind: 'question_answer'; answer: RuntimeUserQuestionAnswer }
| { kind: 'closure'; reason: RuntimeUserQuestionClosureReason };
export type RuntimeSandboxBoundaryOutcome =
| { kind: 'sandbox_boundary_decision'; settlement: SandboxBoundarySettlement }
| { kind: 'closure'; reason: RuntimeUserQuestionClosureReason };
export type RuntimeInteractionFatalError =
| RuntimeInteractionFailStopError
| RuntimeInteractionInvariantError;
export interface RuntimeUserQuestionContinuation
extends RuntimeInteractionContinuationIdentity,
HostedUserQuestionSettlement {
waitForPublication(): Promise<void>;
}
export interface RuntimeSandboxBoundaryContinuation
extends RuntimeInteractionContinuationIdentity,
HostedSandboxBoundarySettlement {
waitForPublication(): Promise<void>;
}
export interface RuntimeInteractionContinuationAuthority {
acceptUserQuestionRequest(input: {
request: UserQuestionRequestEvent;
continuation: RuntimeUserQuestionContinuation;
}): Promise<void>;
acceptSandboxBoundaryRequest(input: {
request: SandboxBoundaryRequestEvent;
continuation: RuntimeSandboxBoundaryContinuation;
}): Promise<void>;
}
export interface RuntimeInteractionRunFacet
extends RuntimeInteractionContinuationAuthority,
RuntimeInteractionRunIdentity {}
export interface RuntimeInteractionRunOwner extends RuntimeInteractionRunFacet {
close(reason: RuntimeInteractionRunClosureReason): Promise<void>;
release(): void;
}
export interface CanonicalPermissionOutcomeRecord {
readonly sessionId: string;
readonly runId: string;
readonly turnId: string;
readonly requestId: string;
readonly request: InteractionPermissionRequest;
readonly outcome: InteractionCanonicalPermissionOutcome;
}
export interface CanonicalPermissionOutcomeReader {
readPermissionOutcome(requestId: string): Promise<CanonicalPermissionOutcomeRecord | undefined>;
}
export interface RuntimeInteractionAuthority {
bindRun(identity: RuntimeInteractionRunIdentity): RuntimeInteractionRunOwner;
}
export class RuntimeInteractionClosedError extends Error {
readonly name = 'RuntimeInteractionClosedError';
constructor(
readonly requestId: string,
readonly reason: RuntimeInteractionClosureReason,
) {
super(`Interaction request ${requestId} was already closed: ${reason}`);
}
}
export type RuntimeInteractionAdmissionRejectionReason =
| 'capacity_exceeded'
| 'invalid_request'
| 'not_published'
| 'run_closed'
| 'request_settled'
| 'authority_draining';
export class RuntimeInteractionAdmissionRejectedError extends Error {
readonly name = 'RuntimeInteractionAdmissionRejectedError';
readonly closureReason: RuntimeInteractionRunClosureReason | undefined;
constructor(
readonly requestId: string,
readonly reason: RuntimeInteractionAdmissionRejectionReason,
authorityFailureOrClosureReason?: unknown,
) {
const closureReason =
reason === 'run_closed'
? (authorityFailureOrClosureReason as RuntimeInteractionRunClosureReason)
: undefined;
super(
reason === 'run_closed'
? `Interaction request ${requestId} was not admitted because its run closed: ${closureReason}`
: `Interaction request ${requestId} was not admitted: ${reason}`,
reason === 'not_published' ? { cause: authorityFailureOrClosureReason } : undefined,
);
this.closureReason = closureReason;
}
}
export class RuntimeInteractionInvariantError extends Error {
readonly name = 'RuntimeInteractionInvariantError';
}
export class RuntimeInteractionFailStopError extends Error {
readonly name = 'RuntimeInteractionFailStopError';
constructor(
message: string,
readonly authorityFailure: unknown,
) {
super(message, { cause: authorityFailure });
}
}
type LocalClosureFinalizer = () => void;
type HostedInteractionRequestEvent = UserQuestionRequestEvent | SandboxBoundaryRequestEvent;
type HostedInteractionSettlementAckEvent =
| UserQuestionAnswerAckEvent
| SandboxBoundaryDecisionAckEvent;
type RuntimeHostedInteractionOutcome = RuntimeUserQuestionOutcome | RuntimeSandboxBoundaryOutcome;
interface TrackedContinuationBase {
readonly requestId: string;
readonly request: HostedInteractionRequestEvent;
readonly publicationBarrier: Promise<void>;
completePublicationBarrier(): void;
admissionState: 'pending' | 'settled' | undefined;
published: boolean;
settlementStarted: boolean;
settled: boolean;
outcome?: RuntimeHostedInteractionOutcome;
settlementPromise?: Promise<void>;
}
interface TrackedQuestionContinuation extends TrackedContinuationBase {
readonly continuation: RuntimeUserQuestionContinuation;
}
interface TrackedSandboxBoundaryContinuation extends TrackedContinuationBase {
readonly request: SandboxBoundaryRequestEvent;
readonly continuation: RuntimeSandboxBoundaryContinuation;
}
type TrackedContinuation = TrackedQuestionContinuation | TrackedSandboxBoundaryContinuation;
/** Exact-Run bridge between RuntimeKernel and backend Interaction producers. */
export class RuntimeInteractionRunBinding implements HostedInteractionBridge {
private closeReason: RuntimeInteractionRunClosureReason | undefined;
private closePromise: Promise<void> | undefined;
private localSettlementPromise: Promise<void> | undefined;
private localClosuresSettled = false;
private publicationsSealed = false;
private released = false;
private readonly localClosureFinalizers: LocalClosureFinalizer[] = [];
private readonly continuations = new Map<string, TrackedContinuation>();
constructor(readonly owner: RuntimeInteractionRunOwner) {}
get sessionId(): string {
return this.owner.sessionId;
}
get turnId(): string {
return this.owner.turnId;
}
get runId(): string {
return this.owner.runId;
}
async canResumeAfterSettlementAck(event: HostedInteractionSettlementAckEvent): Promise<boolean> {
const settled = this.continuations.get(event.requestId);
if (
!settled ||
settled.request.turnId !== event.turnId ||
settled.request.toolUseId !== event.toolUseId ||
!settled.settlementPromise
) {
throw new RuntimeInteractionInvariantError(
`Interaction acknowledgement ${event.requestId} has no exact local settlement`,
);
}
await settled.settlementPromise;
if (!settled.settled || !settlementMatchesAck(settled, event)) {
throw new RuntimeInteractionInvariantError(
`Interaction acknowledgement ${event.requestId} has no exact local settlement`,
);
}
for (const tracked of this.continuations.values()) {
if (tracked === settled) continue;
if (!tracked.settled) return false;
}
return true;
}
async admitUserQuestionRequest(input: {
request: UserQuestionRequestEvent;
settlement: HostedUserQuestionSettlement;
}): Promise<void> {
const tracked = this.trackQuestion(input.request, input.settlement);
try {
await this.owner.acceptUserQuestionRequest({
request: input.request,
continuation: tracked.continuation,
});
} catch (error) {
tracked.completePublicationBarrier();
if (!tracked.settlementStarted) this.continuations.delete(tracked.requestId);
throw error;
}
if (tracked.settlementStarted) {
try {
await tracked.settlementPromise;
throw new RuntimeInteractionInvariantError(
`Question ${tracked.requestId} settled during pending-only admission`,
);
} finally {
tracked.completePublicationBarrier();
}
}
tracked.admissionState = 'pending';
if (this.publicationsSealed) {
tracked.completePublicationBarrier();
throw new RuntimeInteractionInvariantError(
`Question ${tracked.requestId} completed admission after Interaction publication sealed`,
);
}
}
async admitSandboxBoundaryRequest(input: {
request: SandboxBoundaryRequestEvent;
settlement: HostedSandboxBoundarySettlement;
}): Promise<void> {
const tracked = this.trackSandboxBoundary(input.request, input.settlement);
try {
await this.owner.acceptSandboxBoundaryRequest({
request: input.request,
continuation: tracked.continuation,
});
} catch (error) {
tracked.completePublicationBarrier();
if (!tracked.settlementStarted) this.continuations.delete(tracked.requestId);
throw error;
}
if (tracked.settlementStarted) {
try {
await tracked.settlementPromise;
throw new RuntimeInteractionInvariantError(
`Sandbox boundary ${tracked.requestId} settled during pending-only admission`,
);
} finally {
tracked.completePublicationBarrier();
}
}
tracked.admissionState = 'pending';
if (this.publicationsSealed) {
tracked.completePublicationBarrier();
throw new RuntimeInteractionInvariantError(
`Sandbox boundary ${tracked.requestId} completed admission after Interaction publication sealed`,
);
}
}
assertPendingAdmission(request: HostedInteractionRequestEvent): void {
const tracked = this.continuations.get(request.requestId);
// This synchronous guard is the publication linearization point. Close
// blocks new tracking but lets its pre-existing exact admissions reach
// this point; settlement still invalidates publication synchronously.
if (
this.publicationsSealed ||
!tracked ||
tracked.admissionState !== 'pending' ||
tracked.settlementStarted ||
tracked.settled ||
tracked.published ||
!isDeepStrictEqual(tracked.request, request)
) {
this.sealPublications();
throw new RuntimeInteractionInvariantError(
`Interaction request ${request.requestId} has no exact pending admission for Run ${this.runId}`,
);
}
tracked.published = true;
tracked.completePublicationBarrier();
}
sealPublications(): void {
if (this.publicationsSealed) return;
this.publicationsSealed = true;
for (const tracked of this.continuations.values()) {
if (
tracked.admissionState === 'pending' &&
!tracked.published &&
!tracked.settlementStarted
) {
tracked.completePublicationBarrier();
}
}
}
close(reason: RuntimeInteractionRunClosureReason): Promise<void> {
if (this.released) {
throw new RuntimeInteractionInvariantError(
`Interaction Run ${this.runId} was released before close`,
);
}
if (this.closePromise) return this.closePromise;
this.closeReason = reason;
const publicationBarriers = [...this.continuations.values()].map(
(tracked) => tracked.publicationBarrier,
);
this.closePromise = Promise.all(publicationBarriers)
.then(() => this.owner.close(reason))
.catch((error: unknown) => {
if (
error instanceof RuntimeInteractionAdmissionRejectedError ||
error instanceof RuntimeInteractionClosedError ||
error instanceof RuntimeInteractionInvariantError ||
error instanceof RuntimeInteractionFailStopError
) {
throw error;
}
throw new RuntimeInteractionFailStopError(
`Could not durably close Interaction Run ${this.runId}`,
error,
);
});
return this.closePromise;
}
deferLocalClosure(finalizer: LocalClosureFinalizer): void {
if (this.localSettlementPromise || this.localClosuresSettled || this.released) {
throw new RuntimeInteractionInvariantError(
`Interaction Run ${this.runId} registered local closure after settlement`,
);
}
this.localClosureFinalizers.push(finalizer);
}
settleLocalClosures(): Promise<void> {
if (!this.closePromise) {
throw new RuntimeInteractionInvariantError(
`Interaction Run ${this.runId} settled local continuations before durable close`,
);
}
this.localSettlementPromise ??= (async () => {
await this.closePromise;
for (const finalizer of this.localClosureFinalizers) finalizer();
const escaped = [...this.continuations.values()].filter((tracked) => !tracked.settled);
if (escaped.length > 0) {
throw new RuntimeInteractionInvariantError(
`Interaction Run ${this.runId} closed with unsettled continuations: ${escaped
.map((tracked) => tracked.requestId)
.join(', ')}`,
);
}
this.localClosuresSettled = true;
})();
return this.localSettlementPromise;
}
release(): void {
if (!this.closePromise || !this.localClosuresSettled) {
throw new RuntimeInteractionInvariantError(
`Interaction Run ${this.runId} released before durable close and local settlement`,
);
}
if (this.released) return;
try {
this.owner.release();
} catch (error) {
throw error instanceof RuntimeInteractionInvariantError ||
error instanceof RuntimeInteractionFailStopError
? error
: new RuntimeInteractionFailStopError(
`Could not release Interaction Run ${this.runId}`,
error,
);
}
this.released = true;
this.continuations.clear();
}
private trackQuestion(
request: UserQuestionRequestEvent,
local: HostedUserQuestionSettlement,
): TrackedQuestionContinuation {
this.assertNewContinuation(request);
let tracked!: TrackedQuestionContinuation;
const publication = createInteractionPublicationBarrier();
const continuation: RuntimeUserQuestionContinuation = Object.freeze({
requestId: request.requestId,
turnId: this.turnId,
runId: this.runId,
waitForPublication: () => publication.publicationBarrier,
applyAnswer: (answer: RuntimeUserQuestionAnswer) =>
this.settleTracked(
tracked,
() => local.applyAnswer(answer),
{ kind: 'question_answer', answer },
'question answer',
),
applyClosure: (reason: RuntimeUserQuestionClosureReason) =>
this.settleTracked(
tracked,
() => local.applyClosure(reason),
{ kind: 'closure', reason },
'question closure',
),
});
tracked = {
requestId: request.requestId,
request,
continuation,
...publication,
admissionState: undefined,
published: false,
settlementStarted: false,
settled: false,
};
this.continuations.set(request.requestId, tracked);
return tracked;
}
private trackSandboxBoundary(
request: SandboxBoundaryRequestEvent,
local: HostedSandboxBoundarySettlement,
): TrackedSandboxBoundaryContinuation {
this.assertNewContinuation(request);
let tracked!: TrackedSandboxBoundaryContinuation;
const publication = createInteractionPublicationBarrier();
const continuation: RuntimeSandboxBoundaryContinuation = Object.freeze({
requestId: request.requestId,
turnId: this.turnId,
runId: this.runId,
waitForPublication: () => publication.publicationBarrier,
applyDecision: (settlement: SandboxBoundarySettlement) =>
this.settleTracked(
tracked,
() => local.applyDecision(settlement),
{ kind: 'sandbox_boundary_decision', settlement },
'sandbox boundary decision',
),
applyClosure: (reason: RuntimeUserQuestionClosureReason) =>
this.settleTracked(
tracked,
() => local.applyClosure(reason),
{ kind: 'closure', reason },
'sandbox boundary closure',
),
});
tracked = {
requestId: request.requestId,
request,
continuation,
...publication,
admissionState: undefined,
published: false,
settlementStarted: false,
settled: false,
};
this.continuations.set(request.requestId, tracked);
return tracked;
}
private assertNewContinuation(request: HostedInteractionRequestEvent): void {
if (this.closeReason !== undefined) {
throw new RuntimeInteractionAdmissionRejectedError(
request.requestId,
'run_closed',
this.closeReason,
);
}
if (this.publicationsSealed || this.released) {
throw new RuntimeInteractionInvariantError(
`Interaction request ${request.requestId} registered after Run ${this.runId} sealed Interaction publication`,
);
}
if (request.turnId !== this.turnId) {
throw new RuntimeInteractionInvariantError(
`Interaction request ${request.requestId} has mismatched Run identity`,
);
}
if (this.continuations.has(request.requestId)) {
throw new RuntimeInteractionInvariantError(
`Interaction request ${request.requestId} registered more than once`,
);
}
}
private settleTracked(
tracked: TrackedContinuation,
apply: () => Promise<void>,
outcome: RuntimeHostedInteractionOutcome,
operation: string,
): Promise<void> {
if (tracked.settlementStarted) {
return Promise.reject(
new RuntimeInteractionInvariantError(
`Interaction ${operation} did not exact-take ${tracked.requestId}`,
),
);
}
tracked.settlementStarted = true;
const settlement = Promise.resolve()
.then(apply)
.then(() => {
tracked.outcome = outcome;
tracked.settled = true;
})
.finally(() => tracked.completePublicationBarrier());
tracked.settlementPromise = settlement;
return settlement;
}
}
function createInteractionPublicationBarrier(): Pick<
TrackedContinuationBase,
'publicationBarrier' | 'completePublicationBarrier'
> {
let complete!: () => void;
const publicationBarrier = new Promise<void>((resolve) => {
complete = resolve;
});
return {
publicationBarrier,
completePublicationBarrier: complete,
};
}
function settlementMatchesAck(
tracked: TrackedContinuation,
event: HostedInteractionSettlementAckEvent,
): boolean {
const outcome = tracked.outcome;
if (!outcome) return false;
if (event.type === 'user_question_answer_ack') return outcome.kind === 'question_answer';
if (outcome.kind !== 'sandbox_boundary_decision') return false;
const { request, boundary } = outcome.settlement;
return (
event.decision === (request.status === 'denied' ? 'deny' : 'allow') &&
event.status === request.status &&
event.revision === boundary.revision
);
}
export async function bindRuntimeInteractionRun(
authority: RuntimeInteractionAuthority,
identity: RuntimeInteractionRunIdentity,
): Promise<RuntimeInteractionRunBinding> {
let owner: RuntimeInteractionRunOwner;
try {
owner = authority.bindRun(identity);
} catch (error) {
throw error instanceof RuntimeInteractionInvariantError ||
error instanceof RuntimeInteractionFailStopError
? error
: new RuntimeInteractionFailStopError(
`Could not bind Interaction Run ${identity.runId}`,
error,
);
}
if (
owner.sessionId !== identity.sessionId ||
owner.turnId !== identity.turnId ||
owner.runId !== identity.runId
) {
const mismatch = new RuntimeInteractionInvariantError(
'Interaction authority returned a mismatched Run',
);
try {
await owner.close('turn_terminal');
owner.release();
} catch (error) {
throw new RuntimeInteractionFailStopError(
`Could not reclaim mismatched Interaction Run ${identity.runId}`,
new AggregateError([mismatch, error]),
);
}
throw mismatch;
}
return new RuntimeInteractionRunBinding(owner);
}