Wire pipeline DAG execution to manager with events and project context
This commit is contained in:
112
src/agents/domain-events.ts
Normal file
112
src/agents/domain-events.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import type { JsonObject } from "./types.js";
|
||||
|
||||
export type PlanningDomainEventType = "requirements_defined" | "tasks_planned";
|
||||
export type ExecutionDomainEventType = "code_committed" | "task_blocked";
|
||||
export type ValidationDomainEventType = "validation_passed" | "validation_failed";
|
||||
export type IntegrationDomainEventType = "branch_merged";
|
||||
|
||||
export type DomainEventType =
|
||||
| PlanningDomainEventType
|
||||
| ExecutionDomainEventType
|
||||
| ValidationDomainEventType
|
||||
| IntegrationDomainEventType;
|
||||
|
||||
export type DomainEventSource = "pipeline" | "actor";
|
||||
|
||||
export type DomainEventPayload = {
|
||||
summary?: string;
|
||||
details?: JsonObject;
|
||||
errorCode?: string;
|
||||
artifactPointer?: string;
|
||||
};
|
||||
|
||||
export type DomainEvent<TType extends DomainEventType = DomainEventType> = {
|
||||
id: string;
|
||||
type: TType;
|
||||
source: DomainEventSource;
|
||||
sessionId: string;
|
||||
nodeId: string;
|
||||
attempt: number;
|
||||
timestamp: string;
|
||||
payload: DomainEventPayload;
|
||||
};
|
||||
|
||||
export type DomainEventEmission<TType extends DomainEventType = DomainEventType> = {
|
||||
type: TType;
|
||||
payload?: DomainEventPayload;
|
||||
};
|
||||
|
||||
export type DomainEventHandler<TType extends DomainEventType = DomainEventType> = (
|
||||
event: DomainEvent<TType>,
|
||||
) => Promise<void> | void;
|
||||
|
||||
const DOMAIN_EVENT_TYPES = new Set<DomainEventType>([
|
||||
"requirements_defined",
|
||||
"tasks_planned",
|
||||
"code_committed",
|
||||
"task_blocked",
|
||||
"validation_passed",
|
||||
"validation_failed",
|
||||
"branch_merged",
|
||||
]);
|
||||
|
||||
export function isDomainEventType(value: string): value is DomainEventType {
|
||||
return DOMAIN_EVENT_TYPES.has(value as DomainEventType);
|
||||
}
|
||||
|
||||
export function createDomainEvent(input: {
|
||||
type: DomainEventType;
|
||||
source: DomainEventSource;
|
||||
sessionId: string;
|
||||
nodeId: string;
|
||||
attempt: number;
|
||||
payload?: DomainEventPayload;
|
||||
}): DomainEvent {
|
||||
return {
|
||||
id: randomUUID(),
|
||||
type: input.type,
|
||||
source: input.source,
|
||||
sessionId: input.sessionId,
|
||||
nodeId: input.nodeId,
|
||||
attempt: input.attempt,
|
||||
timestamp: new Date().toISOString(),
|
||||
payload: input.payload ?? {},
|
||||
};
|
||||
}
|
||||
|
||||
export class DomainEventBus {
|
||||
private readonly handlers = new Map<DomainEventType, Set<DomainEventHandler>>();
|
||||
|
||||
subscribe<TType extends DomainEventType>(
|
||||
type: TType,
|
||||
handler: DomainEventHandler<TType>,
|
||||
): () => void {
|
||||
const typedHandler = handler as DomainEventHandler;
|
||||
const set = this.handlers.get(type);
|
||||
if (set) {
|
||||
set.add(typedHandler);
|
||||
} else {
|
||||
this.handlers.set(type, new Set([typedHandler]));
|
||||
}
|
||||
|
||||
return () => {
|
||||
const current = this.handlers.get(type);
|
||||
current?.delete(typedHandler);
|
||||
if (current && current.size === 0) {
|
||||
this.handlers.delete(type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async publish<TType extends DomainEventType>(event: DomainEvent<TType>): Promise<void> {
|
||||
const set = this.handlers.get(event.type);
|
||||
if (!set || set.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const handler of set) {
|
||||
await handler(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user