merge: integrate langgraph execution runtime
# Conflicts: # agent-run-gateway.test.mjs # capabilities.mjs # package.json # server.mjs
This commit is contained in:
@@ -198,6 +198,290 @@ export type SystemDisclosurePolicyState = {
|
||||
lastRefreshError?: string | null;
|
||||
};
|
||||
|
||||
export type OrchestratorMode = 'off' | 'shadow' | 'canary' | 'active';
|
||||
|
||||
export type OrchestratorConfig = {
|
||||
mode: OrchestratorMode;
|
||||
primaryEngine: string;
|
||||
fallbackEngine: string;
|
||||
serviceUrl: string;
|
||||
requestTimeoutMs: number;
|
||||
rolloutPercent: number;
|
||||
userAllowlist: string[];
|
||||
workflowAllowlist: string[];
|
||||
fallbackToNative: boolean;
|
||||
requireHealthy: boolean;
|
||||
executionEnabled: boolean;
|
||||
};
|
||||
|
||||
export type OrchestratorRuntime = {
|
||||
killSwitch: boolean;
|
||||
configured: boolean;
|
||||
effective: boolean;
|
||||
reason: string | null;
|
||||
executesLangGraph: boolean;
|
||||
plansLangGraph: boolean;
|
||||
shadowsLangGraph: boolean;
|
||||
executionHandoff: {
|
||||
implemented: boolean;
|
||||
requested: boolean;
|
||||
enabled: boolean;
|
||||
reason: string | null;
|
||||
environmentGate: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type OrchestratorEngineDescriptor = {
|
||||
id: string;
|
||||
label: string;
|
||||
kind: string;
|
||||
configured: boolean;
|
||||
capabilities: string[];
|
||||
};
|
||||
|
||||
export type OrchestratorExecutorDescriptor = {
|
||||
id: string;
|
||||
label: string;
|
||||
kind: string;
|
||||
enabled: boolean;
|
||||
dispatchImplemented: boolean;
|
||||
status: string;
|
||||
capabilities: string[];
|
||||
};
|
||||
|
||||
export type OrchestratorConfigState = {
|
||||
config: OrchestratorConfig;
|
||||
configVersion: number;
|
||||
updatedBy: string | null;
|
||||
updatedAt: number | null;
|
||||
source: string;
|
||||
runtime: OrchestratorRuntime;
|
||||
engines: OrchestratorEngineDescriptor[];
|
||||
executors: OrchestratorExecutorDescriptor[];
|
||||
};
|
||||
|
||||
export type OrchestratorServiceHealth = {
|
||||
checkedAt: number;
|
||||
ok: boolean;
|
||||
status: 'healthy' | 'unhealthy' | 'unconfigured' | 'timeout' | 'unreachable' | 'fetch_unavailable';
|
||||
latencyMs: number;
|
||||
httpStatus: number | null;
|
||||
details: {
|
||||
service: string | null;
|
||||
checkpoint: { kind?: string; durable?: boolean } | null;
|
||||
execution: string | null;
|
||||
executorGateway: {
|
||||
dispatchImplemented: boolean;
|
||||
executionEnabled: boolean;
|
||||
store: { kind: string | null; durable: boolean } | null;
|
||||
} | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type OrchestratorRuntimeState = OrchestratorConfigState & {
|
||||
serviceHealth: OrchestratorServiceHealth;
|
||||
};
|
||||
|
||||
export type OrchestratorShadowMetrics = {
|
||||
observations: number;
|
||||
successes: number;
|
||||
failures: number;
|
||||
successRate: number | null;
|
||||
failureRate: number | null;
|
||||
latencyP50Ms: number | null;
|
||||
latencyP95Ms: number | null;
|
||||
nativeSucceeded: number;
|
||||
nativeFailed: number;
|
||||
lastObservedAt: number | null;
|
||||
sampled: boolean;
|
||||
};
|
||||
|
||||
export type OrchestratorShadowRun = {
|
||||
eventId: string;
|
||||
runId: string;
|
||||
requestId: string;
|
||||
userId: string;
|
||||
sessionId: string | null;
|
||||
nativeStatus: string;
|
||||
nativeAttempts: number;
|
||||
shadowStatus: 'succeeded' | 'failed';
|
||||
engine: string;
|
||||
configVersion: number | null;
|
||||
phase: string | null;
|
||||
taskType: string | null;
|
||||
synthetic: boolean;
|
||||
executorAdapter: string | null;
|
||||
latencyMs: number | null;
|
||||
error: { code: string; message: string } | null;
|
||||
observedAt: number;
|
||||
nativeCompletedAt: number | null;
|
||||
};
|
||||
|
||||
export type OrchestratorShadowRunList = {
|
||||
generatedAt: number;
|
||||
window: { hours: number; from: number };
|
||||
metrics: OrchestratorShadowMetrics;
|
||||
runs: OrchestratorShadowRun[];
|
||||
};
|
||||
|
||||
export type OrchestratorExecutionPlan = {
|
||||
eventId: string;
|
||||
runId: string;
|
||||
requestId: string;
|
||||
userId: string;
|
||||
sessionId: string | null;
|
||||
nativeStatus: string;
|
||||
nativeAttempts: number;
|
||||
mode: string | null;
|
||||
candidateEngine: string;
|
||||
effectiveEngine: string;
|
||||
fallbackEngine: string;
|
||||
reason: string | null;
|
||||
candidateReason: string | null;
|
||||
configVersion: number | null;
|
||||
bucket: number | null;
|
||||
taskType: string | null;
|
||||
dryRun: boolean;
|
||||
handoffAllowed: boolean;
|
||||
plannedAt: number;
|
||||
nativeCompletedAt: number | null;
|
||||
};
|
||||
|
||||
export type OrchestratorExecutionPlanMetrics = {
|
||||
decisions: number;
|
||||
candidateSelections: number;
|
||||
candidateSelectionRate: number | null;
|
||||
nativeSelections: number;
|
||||
nativeSucceeded: number;
|
||||
nativeFailed: number;
|
||||
nativeSettledRate: number | null;
|
||||
handoffAllowed: number;
|
||||
distinctSessions: number;
|
||||
lastPlannedAt: number | null;
|
||||
candidateReasons: Array<{ value: string; count: number }>;
|
||||
taskTypes: Array<{ value: string; count: number }>;
|
||||
sampled: boolean;
|
||||
};
|
||||
|
||||
export type OrchestratorExecutionPlanList = {
|
||||
generatedAt: number;
|
||||
window: { hours: number; from: number };
|
||||
metrics: OrchestratorExecutionPlanMetrics;
|
||||
plans: OrchestratorExecutionPlan[];
|
||||
};
|
||||
|
||||
export type OrchestratorCanaryReadinessCheck = {
|
||||
id: string;
|
||||
passed: boolean;
|
||||
actual: string | number | boolean | null;
|
||||
target: string | number | boolean | null;
|
||||
};
|
||||
|
||||
export type OrchestratorCanaryReadiness = {
|
||||
generatedAt: number;
|
||||
ready: boolean;
|
||||
recommendation: 'keep_shadow' | 'manual_canary_review';
|
||||
window: { hours: number; from: number };
|
||||
thresholds: {
|
||||
hours: number;
|
||||
minObservations: number;
|
||||
minSuccessRate: number;
|
||||
maxP95LatencyMs: number;
|
||||
minLatencyCoverageRate: number;
|
||||
minNativeSettledRate: number;
|
||||
minDistinctSessions: number;
|
||||
maxHoursSinceLastObservation: number;
|
||||
};
|
||||
samples: {
|
||||
totalObservations: number;
|
||||
eligibleObservations: number;
|
||||
excludedSynthetic: number;
|
||||
successes: number;
|
||||
failures: number;
|
||||
successRate: number | null;
|
||||
latencyCoverageRate: number | null;
|
||||
latencyP95Ms: number | null;
|
||||
nativeSettledRate: number | null;
|
||||
distinctSessions: number;
|
||||
lastObservedAt: number | null;
|
||||
hoursSinceLastObservation: number | null;
|
||||
sampled: boolean;
|
||||
};
|
||||
service: {
|
||||
status: string | null;
|
||||
latencyMs: number | null;
|
||||
checkpointKind: string | null;
|
||||
checkpointDurable: boolean | null;
|
||||
executorJobStoreKind: string | null;
|
||||
executorJobStoreDurable: boolean | null;
|
||||
execution: string | null;
|
||||
};
|
||||
checks: OrchestratorCanaryReadinessCheck[];
|
||||
blockers: string[];
|
||||
failureCodes: Array<{ code: string; count: number }>;
|
||||
};
|
||||
|
||||
export type OrchestratorShadowRunDetail = {
|
||||
native: {
|
||||
runId: string;
|
||||
requestId: string;
|
||||
userId: string;
|
||||
sessionId: string | null;
|
||||
status: string;
|
||||
attempts: number;
|
||||
error: string | null;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
startedAt: number | null;
|
||||
completedAt: number | null;
|
||||
};
|
||||
localEvents: Array<{
|
||||
eventId: string;
|
||||
type: string;
|
||||
data: Record<string, unknown> | null;
|
||||
createdAt: number;
|
||||
}>;
|
||||
remote: {
|
||||
available: boolean;
|
||||
state: {
|
||||
status?: string;
|
||||
phase?: string;
|
||||
plan?: Record<string, unknown>;
|
||||
result?: Record<string, unknown>;
|
||||
} | null;
|
||||
events: Array<{
|
||||
sequence?: number;
|
||||
type?: string;
|
||||
timestamp?: number;
|
||||
data?: Record<string, unknown> | null;
|
||||
}>;
|
||||
error: { code: string; message: string } | null;
|
||||
executorJob: {
|
||||
available: boolean;
|
||||
state: {
|
||||
version?: string;
|
||||
jobId?: string;
|
||||
executor?: string;
|
||||
status?: string;
|
||||
reason?: string;
|
||||
attempts?: number;
|
||||
createdAt?: number;
|
||||
updatedAt?: number;
|
||||
} | null;
|
||||
events: Array<{
|
||||
version?: string;
|
||||
eventId?: string;
|
||||
jobId?: string;
|
||||
sequence?: number;
|
||||
type?: string;
|
||||
timestamp?: number;
|
||||
data?: Record<string, unknown> | null;
|
||||
}>;
|
||||
error: { code: string; message: string } | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// ─── Summary ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function fetchAdminSummary() {
|
||||
@@ -217,6 +501,63 @@ export async function updateSystemDisclosurePolicy(config: SystemDisclosurePolic
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Workflow Orchestrator ───────────────────────────────────────────────────
|
||||
|
||||
export async function fetchOrchestratorConfig() {
|
||||
return adminFetch<OrchestratorConfigState>('/admin-api/orchestrator/config');
|
||||
}
|
||||
|
||||
export async function updateOrchestratorConfig(config: OrchestratorConfig) {
|
||||
return adminFetch<OrchestratorConfigState>('/admin-api/orchestrator/config', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ config }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchOrchestratorRuntime() {
|
||||
return adminFetch<OrchestratorRuntimeState>('/admin-api/orchestrator/runtime');
|
||||
}
|
||||
|
||||
export async function fetchOrchestratorShadowRuns(params: {
|
||||
hours?: number;
|
||||
limit?: number;
|
||||
status?: 'all' | 'succeeded' | 'failed';
|
||||
} = {}) {
|
||||
const query = new URLSearchParams();
|
||||
if (params.hours) query.set('hours', String(params.hours));
|
||||
if (params.limit) query.set('limit', String(params.limit));
|
||||
if (params.status) query.set('status', params.status);
|
||||
return adminFetch<OrchestratorShadowRunList>(
|
||||
`/admin-api/orchestrator/shadow-runs?${query}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchOrchestratorExecutionPlans(params: {
|
||||
hours?: number;
|
||||
limit?: number;
|
||||
selection?: 'all' | 'candidate' | 'native';
|
||||
} = {}) {
|
||||
const query = new URLSearchParams();
|
||||
if (params.hours) query.set('hours', String(params.hours));
|
||||
if (params.limit) query.set('limit', String(params.limit));
|
||||
if (params.selection) query.set('selection', params.selection);
|
||||
return adminFetch<OrchestratorExecutionPlanList>(
|
||||
`/admin-api/orchestrator/execution-plans?${query}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchOrchestratorCanaryReadiness() {
|
||||
return adminFetch<OrchestratorCanaryReadiness>(
|
||||
'/admin-api/orchestrator/canary-readiness',
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchOrchestratorShadowRun(runId: string) {
|
||||
return adminFetch<OrchestratorShadowRunDetail>(
|
||||
`/admin-api/orchestrator/shadow-runs/${encodeURIComponent(runId)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Users ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function fetchAdminUsers(params: {
|
||||
|
||||
Reference in New Issue
Block a user