feat(tess): add Mos coordination boundary
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
This commit is contained in:
207
packages/coord/src/mos-coordination.ts
Normal file
207
packages/coord/src/mos-coordination.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
export type MosHandoffStatus = 'queued' | 'accepted' | 'running' | 'completed' | 'failed';
|
||||
|
||||
export interface CoordinationScope {
|
||||
readonly actorId: string;
|
||||
readonly tenantId: string;
|
||||
readonly correlationId: string;
|
||||
/** Trusted gateway/configuration identity; never supplied by a channel client. */
|
||||
readonly requesterAgentId: string;
|
||||
}
|
||||
|
||||
export interface MosCoordinationIdentity {
|
||||
readonly interactionAgentId: string;
|
||||
readonly orchestrationAgentId: string;
|
||||
}
|
||||
|
||||
export interface MosHandoffRequest {
|
||||
readonly idempotencyKey: string;
|
||||
readonly summary: string;
|
||||
readonly context?: string;
|
||||
readonly missionId?: string;
|
||||
}
|
||||
|
||||
export interface MosHandoff {
|
||||
readonly handoffId: string;
|
||||
readonly targetAgentId: string;
|
||||
readonly request: MosHandoffRequest;
|
||||
readonly scope: CoordinationScope;
|
||||
}
|
||||
|
||||
export interface MosHandoffReceipt {
|
||||
readonly handoffId: string;
|
||||
readonly targetAgentId: string;
|
||||
readonly status: 'queued' | 'accepted';
|
||||
readonly correlationId: string;
|
||||
}
|
||||
|
||||
export interface MosCoordinationActivity {
|
||||
readonly occurredAt: string;
|
||||
readonly status: MosHandoffStatus;
|
||||
readonly summary: string;
|
||||
}
|
||||
|
||||
export interface CoordinationObservation {
|
||||
readonly handoffId: string;
|
||||
readonly targetAgentId: string;
|
||||
readonly status: MosHandoffStatus;
|
||||
readonly correlationId: string;
|
||||
readonly activity: readonly MosCoordinationActivity[];
|
||||
}
|
||||
|
||||
export interface CoordinationResult {
|
||||
readonly handoffId: string;
|
||||
readonly targetAgentId: string;
|
||||
readonly status: 'completed' | 'failed' | 'pending';
|
||||
readonly correlationId: string;
|
||||
readonly summary?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport-neutral boundary. The interaction plane can request work and read
|
||||
* its progress/result, but it cannot issue worker, review, merge, or other
|
||||
* general orchestration commands.
|
||||
*/
|
||||
export interface MosCoordinationPort {
|
||||
handoff(handoff: MosHandoff): Promise<MosHandoffReceipt>;
|
||||
observe(handoffId: string, scope: CoordinationScope): Promise<CoordinationObservation>;
|
||||
result(handoffId: string, scope: CoordinationScope): Promise<CoordinationResult>;
|
||||
}
|
||||
|
||||
export type MosCoordinationAuthorityErrorCode =
|
||||
| 'invalid_identity'
|
||||
| 'requester_forbidden'
|
||||
| 'target_drift'
|
||||
| 'correlation_drift';
|
||||
|
||||
export class MosCoordinationAuthorityError extends Error {
|
||||
constructor(
|
||||
readonly code: MosCoordinationAuthorityErrorCode,
|
||||
message: string,
|
||||
) {
|
||||
super(message);
|
||||
this.name = MosCoordinationAuthorityError.name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the interaction-to-orchestration authority boundary before a
|
||||
* transport is reached. Identity names remain configuration data.
|
||||
*/
|
||||
export class MosCoordinationClient {
|
||||
private readonly identity: MosCoordinationIdentity;
|
||||
|
||||
constructor(
|
||||
identity: MosCoordinationIdentity,
|
||||
private readonly port: MosCoordinationPort,
|
||||
private readonly handoffIdFactory: () => string = (): string => crypto.randomUUID(),
|
||||
) {
|
||||
this.identity = normalizeIdentity(identity);
|
||||
}
|
||||
|
||||
async handoff(request: MosHandoffRequest, scope: CoordinationScope): Promise<MosHandoffReceipt> {
|
||||
this.assertRequester(scope);
|
||||
const handoff: MosHandoff = {
|
||||
handoffId: this.handoffIdFactory(),
|
||||
targetAgentId: this.identity.orchestrationAgentId,
|
||||
request: snapshotRequest(request),
|
||||
scope: snapshotScope(scope),
|
||||
};
|
||||
const receipt = await this.port.handoff(handoff);
|
||||
if (
|
||||
receipt.handoffId !== handoff.handoffId ||
|
||||
receipt.targetAgentId !== handoff.targetAgentId
|
||||
) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'target_drift',
|
||||
'Mos coordination transport returned a mismatched handoff target',
|
||||
);
|
||||
}
|
||||
if (receipt.correlationId !== handoff.scope.correlationId) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'correlation_drift',
|
||||
'Mos coordination transport returned a mismatched correlation ID',
|
||||
);
|
||||
}
|
||||
return receipt;
|
||||
}
|
||||
|
||||
async observe(handoffId: string, scope: CoordinationScope): Promise<CoordinationObservation> {
|
||||
this.assertRequester(scope);
|
||||
return this.assertObservation(await this.port.observe(handoffId, snapshotScope(scope)), scope);
|
||||
}
|
||||
|
||||
async result(handoffId: string, scope: CoordinationScope): Promise<CoordinationResult> {
|
||||
this.assertRequester(scope);
|
||||
return this.assertResult(await this.port.result(handoffId, snapshotScope(scope)), scope);
|
||||
}
|
||||
|
||||
private assertRequester(scope: CoordinationScope): void {
|
||||
if (scope.requesterAgentId !== this.identity.interactionAgentId) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'requester_forbidden',
|
||||
'Requester is not the configured interaction agent',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private assertObservation(
|
||||
observation: CoordinationObservation,
|
||||
scope: CoordinationScope,
|
||||
): CoordinationObservation {
|
||||
if (observation.targetAgentId !== this.identity.orchestrationAgentId) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'target_drift',
|
||||
'Mos coordination transport returned an unexpected observation target',
|
||||
);
|
||||
}
|
||||
if (observation.correlationId !== scope.correlationId) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'correlation_drift',
|
||||
'Mos coordination transport returned a mismatched observation correlation ID',
|
||||
);
|
||||
}
|
||||
return observation;
|
||||
}
|
||||
|
||||
private assertResult(result: CoordinationResult, scope: CoordinationScope): CoordinationResult {
|
||||
if (result.targetAgentId !== this.identity.orchestrationAgentId) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'target_drift',
|
||||
'Mos coordination transport returned an unexpected result target',
|
||||
);
|
||||
}
|
||||
if (result.correlationId !== scope.correlationId) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'correlation_drift',
|
||||
'Mos coordination transport returned a mismatched result correlation ID',
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeIdentity(identity: MosCoordinationIdentity): MosCoordinationIdentity {
|
||||
const interactionAgentId = identity.interactionAgentId.trim();
|
||||
const orchestrationAgentId = identity.orchestrationAgentId.trim();
|
||||
if (interactionAgentId.length === 0 || orchestrationAgentId.length === 0) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'invalid_identity',
|
||||
'Interaction and orchestration identities are required',
|
||||
);
|
||||
}
|
||||
if (interactionAgentId === orchestrationAgentId) {
|
||||
throw new MosCoordinationAuthorityError(
|
||||
'invalid_identity',
|
||||
'Interaction and orchestration identities must differ',
|
||||
);
|
||||
}
|
||||
return Object.freeze({ interactionAgentId, orchestrationAgentId });
|
||||
}
|
||||
|
||||
function snapshotRequest(request: MosHandoffRequest): MosHandoffRequest {
|
||||
return Object.freeze({ ...request });
|
||||
}
|
||||
|
||||
function snapshotScope(scope: CoordinationScope): CoordinationScope {
|
||||
return Object.freeze({ ...scope });
|
||||
}
|
||||
Reference in New Issue
Block a user