@harness-engineering/orchestrator 0.2.16 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +241 -20
- package/dist/index.d.ts +241 -20
- package/dist/index.js +1385 -327
- package/dist/index.mjs +1389 -328
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Issue, AgentEvent, WorkflowConfig, IssueTrackerClient, TokenUsage, ConcernSignal, ScopeTier, EscalationConfig, RoutingDecision, Result, WorkflowDefinition, TrackerConfig, WorkspaceConfig, HooksConfig, AgentBackend, SessionStartParams, AgentSession, AgentError, TurnParams, TurnResult } from '@harness-engineering/types';
|
|
1
|
+
import { Issue, AgentEvent, WorkflowConfig, IssueTrackerClient, TokenUsage, ConcernSignal, ScopeTier, EscalationConfig, RoutingDecision, Result, WorkflowDefinition, TrackerConfig, WorkspaceConfig, HooksConfig, AgentBackend, SessionStartParams, AgentSession, AgentError, TurnParams, TurnResult, BackendDef, RoutingConfig, RoutingUseCase, ContainerConfig, SecretConfig, AgentConfig } from '@harness-engineering/types';
|
|
2
2
|
import { EnrichedSpec, ComplexityScore, SimulationResult, IntelligencePipeline, WeightedRecommendation } from '@harness-engineering/intelligence';
|
|
3
3
|
import { GraphStore } from '@harness-engineering/graph';
|
|
4
4
|
import { execFile } from 'node:child_process';
|
|
@@ -1093,22 +1093,38 @@ interface MaintenanceStatus {
|
|
|
1093
1093
|
history: RunResult[];
|
|
1094
1094
|
}
|
|
1095
1095
|
|
|
1096
|
-
/**
|
|
1097
|
-
* The central orchestrator that manages the lifecycle of coding agents.
|
|
1098
|
-
*
|
|
1099
|
-
* It polls an issue tracker for candidate tasks, manages ephemeral workspaces,
|
|
1100
|
-
* runs agents to resolve issues, and updates the tracker with progress.
|
|
1101
|
-
*
|
|
1102
|
-
* @fires Orchestrator#state_change Emitted when the internal state machine transitions
|
|
1103
|
-
* @fires Orchestrator#agent_event Emitted when an agent produces an output or thought
|
|
1104
|
-
*/
|
|
1105
1096
|
declare class Orchestrator extends EventEmitter {
|
|
1106
1097
|
private state;
|
|
1107
1098
|
private config;
|
|
1108
1099
|
private tracker;
|
|
1109
1100
|
private workspace;
|
|
1110
1101
|
private hooks;
|
|
1111
|
-
|
|
1102
|
+
/**
|
|
1103
|
+
* Spec 2 SC30 / Task 11: per-dispatch backend factory replaces the
|
|
1104
|
+
* Phase 1 `runner` / `localRunner` two-runner split. Each
|
|
1105
|
+
* `dispatchIssue()` call asks the factory for a `RoutingUseCase`-routed
|
|
1106
|
+
* `AgentBackend`, then wraps it in a fresh `AgentRunner`.
|
|
1107
|
+
*
|
|
1108
|
+
* `AgentRunner` is stateless (just `{ backend, options }`), so
|
|
1109
|
+
* per-dispatch construction is safe and avoids the cross-call state
|
|
1110
|
+
* the old two-runner split had to coordinate.
|
|
1111
|
+
*
|
|
1112
|
+
* Null only in the legacy fallback path: when `migrateAgentConfig`
|
|
1113
|
+
* throws (legacy configs missing supplemental fields, e.g.
|
|
1114
|
+
* `agent.backend='anthropic'` with no `agent.model`) AND no
|
|
1115
|
+
* `overrides.backend` is supplied, factory construction is skipped to
|
|
1116
|
+
* preserve the prior behavior of failing at dispatch time rather than
|
|
1117
|
+
* construction time. Eliminating this fallback is autopilot Phase 4+.
|
|
1118
|
+
*/
|
|
1119
|
+
private backendFactory;
|
|
1120
|
+
/**
|
|
1121
|
+
* Test-only: when overrides.backend is provided, dispatch uses this
|
|
1122
|
+
* instance directly (bypassing the factory). Mirrors Phase 1
|
|
1123
|
+
* `overrides.backend → this.runner.backend` behavior so existing
|
|
1124
|
+
* MockBackend-injection tests keep working without touching the
|
|
1125
|
+
* factory's routing path.
|
|
1126
|
+
*/
|
|
1127
|
+
private overrideBackend;
|
|
1112
1128
|
private renderer;
|
|
1113
1129
|
private promptTemplate;
|
|
1114
1130
|
private server?;
|
|
@@ -1116,7 +1132,22 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1116
1132
|
private heartbeatInterval?;
|
|
1117
1133
|
private logger;
|
|
1118
1134
|
private interactionQueue;
|
|
1119
|
-
|
|
1135
|
+
/**
|
|
1136
|
+
* Per-named-backend resolver map (Spec 2 SC37). Each `local`/`pi` entry
|
|
1137
|
+
* in `agent.backends` spawns one `LocalModelResolver`. Legacy
|
|
1138
|
+
* single-backend configs converge here via `migrateAgentConfig` (Task 9),
|
|
1139
|
+
* so this map is the single source of truth post-migration.
|
|
1140
|
+
*/
|
|
1141
|
+
private localResolvers;
|
|
1142
|
+
/**
|
|
1143
|
+
* Per-resolver `onStatusChange` unsubscribe callbacks. Spec 2 Phase 5
|
|
1144
|
+
* (SC39): each local/pi resolver gets its own listener emitting a
|
|
1145
|
+
* `NamedLocalModelStatus` event tagged with `backendName` + `endpoint`.
|
|
1146
|
+
* The previous single-resolver field (`localModelStatusUnsubscribe`)
|
|
1147
|
+
* is replaced by this list so multi-local configs can teardown all
|
|
1148
|
+
* listeners on `stop()` without a Map mutation.
|
|
1149
|
+
*/
|
|
1150
|
+
private localModelStatusUnsubscribes;
|
|
1120
1151
|
private pipeline;
|
|
1121
1152
|
private analysisArchive;
|
|
1122
1153
|
private graphStore;
|
|
@@ -1156,7 +1187,6 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1156
1187
|
execFileFn?: ExecFileFn;
|
|
1157
1188
|
});
|
|
1158
1189
|
private createTracker;
|
|
1159
|
-
private createBackend;
|
|
1160
1190
|
/**
|
|
1161
1191
|
* Creates a TaskRunner for the maintenance scheduler.
|
|
1162
1192
|
* CheckCommandRunner and CommandExecutor use real child_process execution.
|
|
@@ -1168,17 +1198,35 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1168
1198
|
* Extracted from start() to keep function length under threshold.
|
|
1169
1199
|
*/
|
|
1170
1200
|
private initMaintenance;
|
|
1171
|
-
private createLocalBackend;
|
|
1172
1201
|
private createIntelligencePipeline;
|
|
1173
1202
|
/**
|
|
1174
|
-
* Create the AnalysisProvider for
|
|
1203
|
+
* Create the AnalysisProvider for an intelligence-pipeline layer
|
|
1204
|
+
* (`sel` by default; `pesl` when constructing a distinct PESL
|
|
1205
|
+
* provider per Spec 2 SC35).
|
|
1206
|
+
*
|
|
1207
|
+
* Spec 2 Phase 4 (SC31–SC36) — resolution order:
|
|
1208
|
+
* 1. Explicit `intelligence.provider` config wins (preserves Phase 0–3 behavior; SC33).
|
|
1209
|
+
* 2. Otherwise, consult `agent.routing.intelligence.<layer>` (or
|
|
1210
|
+
* `routing.default`) to pick a `BackendDef` from `agent.backends`,
|
|
1211
|
+
* then translate via `buildAnalysisProvider` (the per-type factory).
|
|
1175
1212
|
*
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1213
|
+
* Closes the Phase 2 deferral (P2-DEF-638): the legacy
|
|
1214
|
+
* `this.config.agent.backend` read at the bottom of this method is
|
|
1215
|
+
* removed; routing is the sole source for non-explicit configs.
|
|
1216
|
+
*
|
|
1217
|
+
* Cyclomatic complexity: pre-Phase-4 was 33 (factory dispatch was
|
|
1218
|
+
* inlined here). Phase 4 extracts the per-type tree into
|
|
1219
|
+
* `buildAnalysisProvider`, dropping this method to ≤ 5 branches
|
|
1220
|
+
* (under the 15 threshold).
|
|
1180
1221
|
*/
|
|
1181
1222
|
private createAnalysisProvider;
|
|
1223
|
+
/**
|
|
1224
|
+
* Look up the routed BackendDef for an intelligence layer, falling
|
|
1225
|
+
* back through `routing.intelligence.<layer>` → `routing.default`
|
|
1226
|
+
* → null. Returns the resolved name alongside the def so callers can
|
|
1227
|
+
* key into the per-name resolver map.
|
|
1228
|
+
*/
|
|
1229
|
+
private resolveRoutedBackendForIntelligence;
|
|
1182
1230
|
private createProviderFromExplicitConfig;
|
|
1183
1231
|
/**
|
|
1184
1232
|
* Lazily initializes the ClaimManager if it hasn't been created yet.
|
|
@@ -1262,6 +1310,14 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1262
1310
|
* Used by the dashboard's "Dispatch Now" action.
|
|
1263
1311
|
*/
|
|
1264
1312
|
dispatchAdHoc(issue: Issue): Promise<void>;
|
|
1313
|
+
/**
|
|
1314
|
+
* Initialize the LocalModelResolver and intelligence pipeline.
|
|
1315
|
+
*
|
|
1316
|
+
* Runs the initial probe (so resolver state reflects server availability)
|
|
1317
|
+
* before constructing the intelligence pipeline. Subscribes the dashboard
|
|
1318
|
+
* broadcast stub to status changes. Called exactly once from start().
|
|
1319
|
+
*/
|
|
1320
|
+
private initLocalModelAndPipeline;
|
|
1265
1321
|
/**
|
|
1266
1322
|
* Starts the polling loop and the internal HTTP server.
|
|
1267
1323
|
* Runs startup reconciliation to release orphaned claims before the first tick.
|
|
@@ -1292,4 +1348,169 @@ declare function launchTUI(orchestrator: Orchestrator): {
|
|
|
1292
1348
|
waitUntilExit: () => Promise<void>;
|
|
1293
1349
|
};
|
|
1294
1350
|
|
|
1295
|
-
|
|
1351
|
+
interface BackendRouterOptions {
|
|
1352
|
+
backends: Record<string, BackendDef>;
|
|
1353
|
+
routing: RoutingConfig;
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* BackendRouter
|
|
1357
|
+
*
|
|
1358
|
+
* Owns the lookup from a `RoutingUseCase` (a discriminated query — tier,
|
|
1359
|
+
* intelligence layer, maintenance, chat) to a named backend.
|
|
1360
|
+
* Construction-time validation guarantees every name referenced by
|
|
1361
|
+
* `routing` is present in `backends` so runtime lookups are total and
|
|
1362
|
+
* never throw on unknown-name references (D6/D7).
|
|
1363
|
+
*
|
|
1364
|
+
* Lookups for tier/intelligence use cases that fall through to undefined
|
|
1365
|
+
* mappings return `routing.default` without throwing — this matches the
|
|
1366
|
+
* spec's "every use case inherits default unless explicitly routed"
|
|
1367
|
+
* semantics. The `maintenance` and `chat` kinds always resolve to
|
|
1368
|
+
* `routing.default` (SC19, SC20).
|
|
1369
|
+
*/
|
|
1370
|
+
declare class BackendRouter {
|
|
1371
|
+
private readonly backends;
|
|
1372
|
+
private readonly routing;
|
|
1373
|
+
constructor(opts: BackendRouterOptions);
|
|
1374
|
+
/**
|
|
1375
|
+
* Returns the backend name for a given use case.
|
|
1376
|
+
*
|
|
1377
|
+
* - `tier`: per-tier override, falling back to `routing.default`.
|
|
1378
|
+
* - `intelligence`: per-layer override under `routing.intelligence`,
|
|
1379
|
+
* falling back to `routing.default`.
|
|
1380
|
+
* - `maintenance` / `chat`: always `routing.default`.
|
|
1381
|
+
*/
|
|
1382
|
+
resolve(useCase: RoutingUseCase): string;
|
|
1383
|
+
/**
|
|
1384
|
+
* Returns the BackendDef reference for the resolved name. Returns the
|
|
1385
|
+
* exact reference held in `backends` (no copy) so identity comparisons
|
|
1386
|
+
* succeed (SC21).
|
|
1387
|
+
*/
|
|
1388
|
+
resolveDefinition(useCase: RoutingUseCase): BackendDef;
|
|
1389
|
+
private validateReferences;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Options for `OrchestratorBackendFactory`.
|
|
1394
|
+
*
|
|
1395
|
+
* `sandboxPolicy` and `container`/`secrets` mirror the orchestrator's own
|
|
1396
|
+
* agent-config fields. `getResolverModelFor` is a registration hook the
|
|
1397
|
+
* orchestrator calls to bind each `local`/`pi` backend to its
|
|
1398
|
+
* `LocalModelResolver` (so multi-resolver array-fallback works without
|
|
1399
|
+
* leaking resolver lifetimes into the factory).
|
|
1400
|
+
*/
|
|
1401
|
+
interface OrchestratorBackendFactoryOptions {
|
|
1402
|
+
backends: Record<string, BackendDef>;
|
|
1403
|
+
routing: RoutingConfig;
|
|
1404
|
+
sandboxPolicy: 'none' | 'docker';
|
|
1405
|
+
container?: ContainerConfig;
|
|
1406
|
+
secrets?: SecretConfig;
|
|
1407
|
+
/**
|
|
1408
|
+
* Hook for resolver injection. Invoked per `local`/`pi` backend at
|
|
1409
|
+
* `forUseCase()` time with the backend's name. When the hook returns a
|
|
1410
|
+
* function, the factory rebuilds the local/pi instance using that
|
|
1411
|
+
* function as `getModel` (overriding the head-of-array placeholder
|
|
1412
|
+
* baked into `createBackend`). Returning `undefined` means "no
|
|
1413
|
+
* resolver registered for this name" — the placeholder stays in place.
|
|
1414
|
+
*
|
|
1415
|
+
* This indirection keeps the factory ignorant of `LocalModelResolver`'s
|
|
1416
|
+
* existence and lifecycle while still letting it produce backends that
|
|
1417
|
+
* route through the resolver Map.
|
|
1418
|
+
*/
|
|
1419
|
+
getResolverModelFor?: (backendName: string) => (() => string | null) | undefined;
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* High-level factory wrapping `BackendRouter` + `createBackend` plus
|
|
1423
|
+
* orchestrator-side concerns (sandbox wrapping, resolver binding).
|
|
1424
|
+
*
|
|
1425
|
+
* Spec 2 SC22-SC25: every `forUseCase(useCase)` call returns a fresh
|
|
1426
|
+
* `AgentBackend` whose class matches the routed `BackendDef.type`.
|
|
1427
|
+
* `local`/`pi` defs are bound to their per-name resolver before being
|
|
1428
|
+
* returned, and the result is wrapped in `ContainerBackend` when
|
|
1429
|
+
* sandboxPolicy is 'docker'.
|
|
1430
|
+
*/
|
|
1431
|
+
declare class OrchestratorBackendFactory {
|
|
1432
|
+
private readonly router;
|
|
1433
|
+
private readonly opts;
|
|
1434
|
+
constructor(opts: OrchestratorBackendFactoryOptions);
|
|
1435
|
+
/**
|
|
1436
|
+
* Resolve `useCase` to a backend name, materialize a fresh
|
|
1437
|
+
* `AgentBackend`, optionally rebind its model resolver, and apply
|
|
1438
|
+
* sandbox wrapping. Idempotent across calls (no caching) — the AgentRunner
|
|
1439
|
+
* holds the per-dispatch reference and discards it when the run ends.
|
|
1440
|
+
*/
|
|
1441
|
+
/**
|
|
1442
|
+
* Resolve `useCase` to its routed backend name, exposing the
|
|
1443
|
+
* router lookup without materializing a backend. Used by callers
|
|
1444
|
+
* (e.g., the orchestrator's dispatch site) that need to label
|
|
1445
|
+
* telemetry with the routed name BEFORE constructing the backend.
|
|
1446
|
+
*
|
|
1447
|
+
* Spec 2 P2-I2: previously the orchestrator labelled `LiveSession`
|
|
1448
|
+
* + `StreamRecorder` with the legacy `agent.backend` field, which
|
|
1449
|
+
* is `undefined` for pure-modern configs. Threading the routed name
|
|
1450
|
+
* through dispatch eliminates that gap.
|
|
1451
|
+
*/
|
|
1452
|
+
resolveName(useCase: RoutingUseCase): string;
|
|
1453
|
+
forUseCase(useCase: RoutingUseCase): AgentBackend;
|
|
1454
|
+
/**
|
|
1455
|
+
* Rebuild a `local`/`pi` backend with a resolver-bound `getModel`,
|
|
1456
|
+
* mirroring `createBackend`'s local/pi branches but substituting the
|
|
1457
|
+
* head-of-array placeholder with the orchestrator-owned resolver.
|
|
1458
|
+
*/
|
|
1459
|
+
private buildLocalLikeWithResolver;
|
|
1460
|
+
/**
|
|
1461
|
+
* Apply ContainerBackend wrapping (PFC-3). Pulls the runtime + secret
|
|
1462
|
+
* backend per call so each dispatch sees a fresh container handle map
|
|
1463
|
+
* (ContainerBackend keeps its own per-instance Map<sessionId, handle>).
|
|
1464
|
+
*/
|
|
1465
|
+
private wrapInContainer;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* Result of running `migrateAgentConfig`.
|
|
1470
|
+
*
|
|
1471
|
+
* `config` is the *effective* AgentConfig — either the input unchanged
|
|
1472
|
+
* (when `agent.backends` is already set or no migration is needed) or
|
|
1473
|
+
* the input augmented with synthesized `backends` and `routing` fields.
|
|
1474
|
+
*
|
|
1475
|
+
* `warnings` is a list of human-readable deprecation messages, one per
|
|
1476
|
+
* legacy field encountered. Each message names the deprecated field
|
|
1477
|
+
* (dotted path) and includes a pointer to the migration guide. The
|
|
1478
|
+
* orchestrator emits these as `warn`-level log entries at startup.
|
|
1479
|
+
*/
|
|
1480
|
+
interface MigrationResult {
|
|
1481
|
+
config: AgentConfig;
|
|
1482
|
+
warnings: string[];
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Translate legacy `agent.backend` / `agent.localBackend` /
|
|
1486
|
+
* `agent.escalation.autoExecute` into the new `agent.backends` +
|
|
1487
|
+
* `agent.routing` shape (Spec 2 D3, D4, D8, D11).
|
|
1488
|
+
*
|
|
1489
|
+
* Behavior matrix:
|
|
1490
|
+
* - `agent.backends` already set, no legacy fields:
|
|
1491
|
+
* no-op; returns input config unchanged, warnings = [].
|
|
1492
|
+
* - `agent.backends` already set + at least one legacy field:
|
|
1493
|
+
* no-op on config; warnings name each ignored legacy field (D4).
|
|
1494
|
+
* - No `agent.backends`, at least one of `agent.backend` /
|
|
1495
|
+
* `agent.localBackend` / `agent.localEndpoint` / etc. set:
|
|
1496
|
+
* synthesize `backends.primary` (always, from `agent.backend`)
|
|
1497
|
+
* and `backends.local` (when `localBackend` is set), plus a
|
|
1498
|
+
* `routing` map driven by `escalation.autoExecute` (D3).
|
|
1499
|
+
* - No `agent.backends`, no legacy fields:
|
|
1500
|
+
* no-op; the caller's downstream Zod validation surfaces the gap
|
|
1501
|
+
* as a missing-required-field error.
|
|
1502
|
+
*
|
|
1503
|
+
* Throws on internal inconsistencies (e.g., `agent.backend = 'pi'`
|
|
1504
|
+
* with no `localEndpoint`/`localModel`) — these are user-config bugs
|
|
1505
|
+
* that would have produced a runtime crash today.
|
|
1506
|
+
*/
|
|
1507
|
+
declare function migrateAgentConfig(agent: AgentConfig): MigrationResult;
|
|
1508
|
+
|
|
1509
|
+
/**
|
|
1510
|
+
* Pure constructor: BackendDef -> concrete AgentBackend instance.
|
|
1511
|
+
* No side effects beyond the underlying class constructors.
|
|
1512
|
+
* Container wrapping (sandbox policy) is the orchestrator's job, not the factory's.
|
|
1513
|
+
*/
|
|
1514
|
+
declare function createBackend(def: BackendDef): AgentBackend;
|
|
1515
|
+
|
|
1516
|
+
export { type AgentUpdateEvent, AnalysisArchive, type AnalysisRecord, type ApplyEventResult, type ArtifactPresence, type AttemptStats, BackendRouter, type BackendRouterOptions, ClaimManager, type ClaimManagerConfig, type CleanWorkspaceEffect, type DispatchEffect, type EmitLogEffect, type EscalateEffect, type ExecFileFn, type Highlight, type HighlightsInfo, InteractionQueue, type LinearGraphQLExtension, LinearGraphQLStub, type LiveSession, type MigrationResult, MockBackend, ORCHESTRATOR_IDENTITY_FILE, Orchestrator, OrchestratorBackendFactory, type OrchestratorBackendFactoryOptions, type OrchestratorContext, type OrchestratorEvent, type OrchestratorState, PRDetector, type PRDetectorLogger, type PendingInteraction, PromptRenderer, type PublishedIndex, type RateLimitSnapshot as RateLimitComputeSnapshot, type RateLimitConfig, type RateLimitSnapshot$1 as RateLimitSnapshot, type ReleaseClaimEffect, type RetryEntry, type RetryFiredEvent, RoadmapTrackerAdapter, type RunAttemptPhase, type RunningEntry, type ScheduleRetryEffect, type SideEffect, type StallDetectedEvent, type StopEffect, type StreamManifest, StreamRecorder, type TickEvent, type TokenTotals, type TriageConfig, type TriageDecision, type TriageSignals, type TriageSkill, type UpdateTokensEffect, type WorkerExitEvent, WorkflowLoader, WorkspaceHooks, WorkspaceManager, applyEvent, artifactPresenceFromIssue, calculateRetryDelay, canDispatch, computeRateLimitDelay, createBackend, createEmptyState, detectScopeTier, extractHighlights, extractTitlePrefix, getAvailableSlots, getDefaultConfig, getPerStateCount, isEligible, launchTUI, loadPublishedIndex, migrateAgentConfig, reconcile, renderAnalysisComment, renderPRComment, resolveEscalationConfig, resolveOrchestratorId, routeIssue, savePublishedIndex, selectCandidates, sortCandidates, triageIssue, validateWorkflowConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Issue, AgentEvent, WorkflowConfig, IssueTrackerClient, TokenUsage, ConcernSignal, ScopeTier, EscalationConfig, RoutingDecision, Result, WorkflowDefinition, TrackerConfig, WorkspaceConfig, HooksConfig, AgentBackend, SessionStartParams, AgentSession, AgentError, TurnParams, TurnResult } from '@harness-engineering/types';
|
|
1
|
+
import { Issue, AgentEvent, WorkflowConfig, IssueTrackerClient, TokenUsage, ConcernSignal, ScopeTier, EscalationConfig, RoutingDecision, Result, WorkflowDefinition, TrackerConfig, WorkspaceConfig, HooksConfig, AgentBackend, SessionStartParams, AgentSession, AgentError, TurnParams, TurnResult, BackendDef, RoutingConfig, RoutingUseCase, ContainerConfig, SecretConfig, AgentConfig } from '@harness-engineering/types';
|
|
2
2
|
import { EnrichedSpec, ComplexityScore, SimulationResult, IntelligencePipeline, WeightedRecommendation } from '@harness-engineering/intelligence';
|
|
3
3
|
import { GraphStore } from '@harness-engineering/graph';
|
|
4
4
|
import { execFile } from 'node:child_process';
|
|
@@ -1093,22 +1093,38 @@ interface MaintenanceStatus {
|
|
|
1093
1093
|
history: RunResult[];
|
|
1094
1094
|
}
|
|
1095
1095
|
|
|
1096
|
-
/**
|
|
1097
|
-
* The central orchestrator that manages the lifecycle of coding agents.
|
|
1098
|
-
*
|
|
1099
|
-
* It polls an issue tracker for candidate tasks, manages ephemeral workspaces,
|
|
1100
|
-
* runs agents to resolve issues, and updates the tracker with progress.
|
|
1101
|
-
*
|
|
1102
|
-
* @fires Orchestrator#state_change Emitted when the internal state machine transitions
|
|
1103
|
-
* @fires Orchestrator#agent_event Emitted when an agent produces an output or thought
|
|
1104
|
-
*/
|
|
1105
1096
|
declare class Orchestrator extends EventEmitter {
|
|
1106
1097
|
private state;
|
|
1107
1098
|
private config;
|
|
1108
1099
|
private tracker;
|
|
1109
1100
|
private workspace;
|
|
1110
1101
|
private hooks;
|
|
1111
|
-
|
|
1102
|
+
/**
|
|
1103
|
+
* Spec 2 SC30 / Task 11: per-dispatch backend factory replaces the
|
|
1104
|
+
* Phase 1 `runner` / `localRunner` two-runner split. Each
|
|
1105
|
+
* `dispatchIssue()` call asks the factory for a `RoutingUseCase`-routed
|
|
1106
|
+
* `AgentBackend`, then wraps it in a fresh `AgentRunner`.
|
|
1107
|
+
*
|
|
1108
|
+
* `AgentRunner` is stateless (just `{ backend, options }`), so
|
|
1109
|
+
* per-dispatch construction is safe and avoids the cross-call state
|
|
1110
|
+
* the old two-runner split had to coordinate.
|
|
1111
|
+
*
|
|
1112
|
+
* Null only in the legacy fallback path: when `migrateAgentConfig`
|
|
1113
|
+
* throws (legacy configs missing supplemental fields, e.g.
|
|
1114
|
+
* `agent.backend='anthropic'` with no `agent.model`) AND no
|
|
1115
|
+
* `overrides.backend` is supplied, factory construction is skipped to
|
|
1116
|
+
* preserve the prior behavior of failing at dispatch time rather than
|
|
1117
|
+
* construction time. Eliminating this fallback is autopilot Phase 4+.
|
|
1118
|
+
*/
|
|
1119
|
+
private backendFactory;
|
|
1120
|
+
/**
|
|
1121
|
+
* Test-only: when overrides.backend is provided, dispatch uses this
|
|
1122
|
+
* instance directly (bypassing the factory). Mirrors Phase 1
|
|
1123
|
+
* `overrides.backend → this.runner.backend` behavior so existing
|
|
1124
|
+
* MockBackend-injection tests keep working without touching the
|
|
1125
|
+
* factory's routing path.
|
|
1126
|
+
*/
|
|
1127
|
+
private overrideBackend;
|
|
1112
1128
|
private renderer;
|
|
1113
1129
|
private promptTemplate;
|
|
1114
1130
|
private server?;
|
|
@@ -1116,7 +1132,22 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1116
1132
|
private heartbeatInterval?;
|
|
1117
1133
|
private logger;
|
|
1118
1134
|
private interactionQueue;
|
|
1119
|
-
|
|
1135
|
+
/**
|
|
1136
|
+
* Per-named-backend resolver map (Spec 2 SC37). Each `local`/`pi` entry
|
|
1137
|
+
* in `agent.backends` spawns one `LocalModelResolver`. Legacy
|
|
1138
|
+
* single-backend configs converge here via `migrateAgentConfig` (Task 9),
|
|
1139
|
+
* so this map is the single source of truth post-migration.
|
|
1140
|
+
*/
|
|
1141
|
+
private localResolvers;
|
|
1142
|
+
/**
|
|
1143
|
+
* Per-resolver `onStatusChange` unsubscribe callbacks. Spec 2 Phase 5
|
|
1144
|
+
* (SC39): each local/pi resolver gets its own listener emitting a
|
|
1145
|
+
* `NamedLocalModelStatus` event tagged with `backendName` + `endpoint`.
|
|
1146
|
+
* The previous single-resolver field (`localModelStatusUnsubscribe`)
|
|
1147
|
+
* is replaced by this list so multi-local configs can teardown all
|
|
1148
|
+
* listeners on `stop()` without a Map mutation.
|
|
1149
|
+
*/
|
|
1150
|
+
private localModelStatusUnsubscribes;
|
|
1120
1151
|
private pipeline;
|
|
1121
1152
|
private analysisArchive;
|
|
1122
1153
|
private graphStore;
|
|
@@ -1156,7 +1187,6 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1156
1187
|
execFileFn?: ExecFileFn;
|
|
1157
1188
|
});
|
|
1158
1189
|
private createTracker;
|
|
1159
|
-
private createBackend;
|
|
1160
1190
|
/**
|
|
1161
1191
|
* Creates a TaskRunner for the maintenance scheduler.
|
|
1162
1192
|
* CheckCommandRunner and CommandExecutor use real child_process execution.
|
|
@@ -1168,17 +1198,35 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1168
1198
|
* Extracted from start() to keep function length under threshold.
|
|
1169
1199
|
*/
|
|
1170
1200
|
private initMaintenance;
|
|
1171
|
-
private createLocalBackend;
|
|
1172
1201
|
private createIntelligencePipeline;
|
|
1173
1202
|
/**
|
|
1174
|
-
* Create the AnalysisProvider for
|
|
1203
|
+
* Create the AnalysisProvider for an intelligence-pipeline layer
|
|
1204
|
+
* (`sel` by default; `pesl` when constructing a distinct PESL
|
|
1205
|
+
* provider per Spec 2 SC35).
|
|
1206
|
+
*
|
|
1207
|
+
* Spec 2 Phase 4 (SC31–SC36) — resolution order:
|
|
1208
|
+
* 1. Explicit `intelligence.provider` config wins (preserves Phase 0–3 behavior; SC33).
|
|
1209
|
+
* 2. Otherwise, consult `agent.routing.intelligence.<layer>` (or
|
|
1210
|
+
* `routing.default`) to pick a `BackendDef` from `agent.backends`,
|
|
1211
|
+
* then translate via `buildAnalysisProvider` (the per-type factory).
|
|
1175
1212
|
*
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1213
|
+
* Closes the Phase 2 deferral (P2-DEF-638): the legacy
|
|
1214
|
+
* `this.config.agent.backend` read at the bottom of this method is
|
|
1215
|
+
* removed; routing is the sole source for non-explicit configs.
|
|
1216
|
+
*
|
|
1217
|
+
* Cyclomatic complexity: pre-Phase-4 was 33 (factory dispatch was
|
|
1218
|
+
* inlined here). Phase 4 extracts the per-type tree into
|
|
1219
|
+
* `buildAnalysisProvider`, dropping this method to ≤ 5 branches
|
|
1220
|
+
* (under the 15 threshold).
|
|
1180
1221
|
*/
|
|
1181
1222
|
private createAnalysisProvider;
|
|
1223
|
+
/**
|
|
1224
|
+
* Look up the routed BackendDef for an intelligence layer, falling
|
|
1225
|
+
* back through `routing.intelligence.<layer>` → `routing.default`
|
|
1226
|
+
* → null. Returns the resolved name alongside the def so callers can
|
|
1227
|
+
* key into the per-name resolver map.
|
|
1228
|
+
*/
|
|
1229
|
+
private resolveRoutedBackendForIntelligence;
|
|
1182
1230
|
private createProviderFromExplicitConfig;
|
|
1183
1231
|
/**
|
|
1184
1232
|
* Lazily initializes the ClaimManager if it hasn't been created yet.
|
|
@@ -1262,6 +1310,14 @@ declare class Orchestrator extends EventEmitter {
|
|
|
1262
1310
|
* Used by the dashboard's "Dispatch Now" action.
|
|
1263
1311
|
*/
|
|
1264
1312
|
dispatchAdHoc(issue: Issue): Promise<void>;
|
|
1313
|
+
/**
|
|
1314
|
+
* Initialize the LocalModelResolver and intelligence pipeline.
|
|
1315
|
+
*
|
|
1316
|
+
* Runs the initial probe (so resolver state reflects server availability)
|
|
1317
|
+
* before constructing the intelligence pipeline. Subscribes the dashboard
|
|
1318
|
+
* broadcast stub to status changes. Called exactly once from start().
|
|
1319
|
+
*/
|
|
1320
|
+
private initLocalModelAndPipeline;
|
|
1265
1321
|
/**
|
|
1266
1322
|
* Starts the polling loop and the internal HTTP server.
|
|
1267
1323
|
* Runs startup reconciliation to release orphaned claims before the first tick.
|
|
@@ -1292,4 +1348,169 @@ declare function launchTUI(orchestrator: Orchestrator): {
|
|
|
1292
1348
|
waitUntilExit: () => Promise<void>;
|
|
1293
1349
|
};
|
|
1294
1350
|
|
|
1295
|
-
|
|
1351
|
+
interface BackendRouterOptions {
|
|
1352
|
+
backends: Record<string, BackendDef>;
|
|
1353
|
+
routing: RoutingConfig;
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* BackendRouter
|
|
1357
|
+
*
|
|
1358
|
+
* Owns the lookup from a `RoutingUseCase` (a discriminated query — tier,
|
|
1359
|
+
* intelligence layer, maintenance, chat) to a named backend.
|
|
1360
|
+
* Construction-time validation guarantees every name referenced by
|
|
1361
|
+
* `routing` is present in `backends` so runtime lookups are total and
|
|
1362
|
+
* never throw on unknown-name references (D6/D7).
|
|
1363
|
+
*
|
|
1364
|
+
* Lookups for tier/intelligence use cases that fall through to undefined
|
|
1365
|
+
* mappings return `routing.default` without throwing — this matches the
|
|
1366
|
+
* spec's "every use case inherits default unless explicitly routed"
|
|
1367
|
+
* semantics. The `maintenance` and `chat` kinds always resolve to
|
|
1368
|
+
* `routing.default` (SC19, SC20).
|
|
1369
|
+
*/
|
|
1370
|
+
declare class BackendRouter {
|
|
1371
|
+
private readonly backends;
|
|
1372
|
+
private readonly routing;
|
|
1373
|
+
constructor(opts: BackendRouterOptions);
|
|
1374
|
+
/**
|
|
1375
|
+
* Returns the backend name for a given use case.
|
|
1376
|
+
*
|
|
1377
|
+
* - `tier`: per-tier override, falling back to `routing.default`.
|
|
1378
|
+
* - `intelligence`: per-layer override under `routing.intelligence`,
|
|
1379
|
+
* falling back to `routing.default`.
|
|
1380
|
+
* - `maintenance` / `chat`: always `routing.default`.
|
|
1381
|
+
*/
|
|
1382
|
+
resolve(useCase: RoutingUseCase): string;
|
|
1383
|
+
/**
|
|
1384
|
+
* Returns the BackendDef reference for the resolved name. Returns the
|
|
1385
|
+
* exact reference held in `backends` (no copy) so identity comparisons
|
|
1386
|
+
* succeed (SC21).
|
|
1387
|
+
*/
|
|
1388
|
+
resolveDefinition(useCase: RoutingUseCase): BackendDef;
|
|
1389
|
+
private validateReferences;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Options for `OrchestratorBackendFactory`.
|
|
1394
|
+
*
|
|
1395
|
+
* `sandboxPolicy` and `container`/`secrets` mirror the orchestrator's own
|
|
1396
|
+
* agent-config fields. `getResolverModelFor` is a registration hook the
|
|
1397
|
+
* orchestrator calls to bind each `local`/`pi` backend to its
|
|
1398
|
+
* `LocalModelResolver` (so multi-resolver array-fallback works without
|
|
1399
|
+
* leaking resolver lifetimes into the factory).
|
|
1400
|
+
*/
|
|
1401
|
+
interface OrchestratorBackendFactoryOptions {
|
|
1402
|
+
backends: Record<string, BackendDef>;
|
|
1403
|
+
routing: RoutingConfig;
|
|
1404
|
+
sandboxPolicy: 'none' | 'docker';
|
|
1405
|
+
container?: ContainerConfig;
|
|
1406
|
+
secrets?: SecretConfig;
|
|
1407
|
+
/**
|
|
1408
|
+
* Hook for resolver injection. Invoked per `local`/`pi` backend at
|
|
1409
|
+
* `forUseCase()` time with the backend's name. When the hook returns a
|
|
1410
|
+
* function, the factory rebuilds the local/pi instance using that
|
|
1411
|
+
* function as `getModel` (overriding the head-of-array placeholder
|
|
1412
|
+
* baked into `createBackend`). Returning `undefined` means "no
|
|
1413
|
+
* resolver registered for this name" — the placeholder stays in place.
|
|
1414
|
+
*
|
|
1415
|
+
* This indirection keeps the factory ignorant of `LocalModelResolver`'s
|
|
1416
|
+
* existence and lifecycle while still letting it produce backends that
|
|
1417
|
+
* route through the resolver Map.
|
|
1418
|
+
*/
|
|
1419
|
+
getResolverModelFor?: (backendName: string) => (() => string | null) | undefined;
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* High-level factory wrapping `BackendRouter` + `createBackend` plus
|
|
1423
|
+
* orchestrator-side concerns (sandbox wrapping, resolver binding).
|
|
1424
|
+
*
|
|
1425
|
+
* Spec 2 SC22-SC25: every `forUseCase(useCase)` call returns a fresh
|
|
1426
|
+
* `AgentBackend` whose class matches the routed `BackendDef.type`.
|
|
1427
|
+
* `local`/`pi` defs are bound to their per-name resolver before being
|
|
1428
|
+
* returned, and the result is wrapped in `ContainerBackend` when
|
|
1429
|
+
* sandboxPolicy is 'docker'.
|
|
1430
|
+
*/
|
|
1431
|
+
declare class OrchestratorBackendFactory {
|
|
1432
|
+
private readonly router;
|
|
1433
|
+
private readonly opts;
|
|
1434
|
+
constructor(opts: OrchestratorBackendFactoryOptions);
|
|
1435
|
+
/**
|
|
1436
|
+
* Resolve `useCase` to a backend name, materialize a fresh
|
|
1437
|
+
* `AgentBackend`, optionally rebind its model resolver, and apply
|
|
1438
|
+
* sandbox wrapping. Idempotent across calls (no caching) — the AgentRunner
|
|
1439
|
+
* holds the per-dispatch reference and discards it when the run ends.
|
|
1440
|
+
*/
|
|
1441
|
+
/**
|
|
1442
|
+
* Resolve `useCase` to its routed backend name, exposing the
|
|
1443
|
+
* router lookup without materializing a backend. Used by callers
|
|
1444
|
+
* (e.g., the orchestrator's dispatch site) that need to label
|
|
1445
|
+
* telemetry with the routed name BEFORE constructing the backend.
|
|
1446
|
+
*
|
|
1447
|
+
* Spec 2 P2-I2: previously the orchestrator labelled `LiveSession`
|
|
1448
|
+
* + `StreamRecorder` with the legacy `agent.backend` field, which
|
|
1449
|
+
* is `undefined` for pure-modern configs. Threading the routed name
|
|
1450
|
+
* through dispatch eliminates that gap.
|
|
1451
|
+
*/
|
|
1452
|
+
resolveName(useCase: RoutingUseCase): string;
|
|
1453
|
+
forUseCase(useCase: RoutingUseCase): AgentBackend;
|
|
1454
|
+
/**
|
|
1455
|
+
* Rebuild a `local`/`pi` backend with a resolver-bound `getModel`,
|
|
1456
|
+
* mirroring `createBackend`'s local/pi branches but substituting the
|
|
1457
|
+
* head-of-array placeholder with the orchestrator-owned resolver.
|
|
1458
|
+
*/
|
|
1459
|
+
private buildLocalLikeWithResolver;
|
|
1460
|
+
/**
|
|
1461
|
+
* Apply ContainerBackend wrapping (PFC-3). Pulls the runtime + secret
|
|
1462
|
+
* backend per call so each dispatch sees a fresh container handle map
|
|
1463
|
+
* (ContainerBackend keeps its own per-instance Map<sessionId, handle>).
|
|
1464
|
+
*/
|
|
1465
|
+
private wrapInContainer;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* Result of running `migrateAgentConfig`.
|
|
1470
|
+
*
|
|
1471
|
+
* `config` is the *effective* AgentConfig — either the input unchanged
|
|
1472
|
+
* (when `agent.backends` is already set or no migration is needed) or
|
|
1473
|
+
* the input augmented with synthesized `backends` and `routing` fields.
|
|
1474
|
+
*
|
|
1475
|
+
* `warnings` is a list of human-readable deprecation messages, one per
|
|
1476
|
+
* legacy field encountered. Each message names the deprecated field
|
|
1477
|
+
* (dotted path) and includes a pointer to the migration guide. The
|
|
1478
|
+
* orchestrator emits these as `warn`-level log entries at startup.
|
|
1479
|
+
*/
|
|
1480
|
+
interface MigrationResult {
|
|
1481
|
+
config: AgentConfig;
|
|
1482
|
+
warnings: string[];
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Translate legacy `agent.backend` / `agent.localBackend` /
|
|
1486
|
+
* `agent.escalation.autoExecute` into the new `agent.backends` +
|
|
1487
|
+
* `agent.routing` shape (Spec 2 D3, D4, D8, D11).
|
|
1488
|
+
*
|
|
1489
|
+
* Behavior matrix:
|
|
1490
|
+
* - `agent.backends` already set, no legacy fields:
|
|
1491
|
+
* no-op; returns input config unchanged, warnings = [].
|
|
1492
|
+
* - `agent.backends` already set + at least one legacy field:
|
|
1493
|
+
* no-op on config; warnings name each ignored legacy field (D4).
|
|
1494
|
+
* - No `agent.backends`, at least one of `agent.backend` /
|
|
1495
|
+
* `agent.localBackend` / `agent.localEndpoint` / etc. set:
|
|
1496
|
+
* synthesize `backends.primary` (always, from `agent.backend`)
|
|
1497
|
+
* and `backends.local` (when `localBackend` is set), plus a
|
|
1498
|
+
* `routing` map driven by `escalation.autoExecute` (D3).
|
|
1499
|
+
* - No `agent.backends`, no legacy fields:
|
|
1500
|
+
* no-op; the caller's downstream Zod validation surfaces the gap
|
|
1501
|
+
* as a missing-required-field error.
|
|
1502
|
+
*
|
|
1503
|
+
* Throws on internal inconsistencies (e.g., `agent.backend = 'pi'`
|
|
1504
|
+
* with no `localEndpoint`/`localModel`) — these are user-config bugs
|
|
1505
|
+
* that would have produced a runtime crash today.
|
|
1506
|
+
*/
|
|
1507
|
+
declare function migrateAgentConfig(agent: AgentConfig): MigrationResult;
|
|
1508
|
+
|
|
1509
|
+
/**
|
|
1510
|
+
* Pure constructor: BackendDef -> concrete AgentBackend instance.
|
|
1511
|
+
* No side effects beyond the underlying class constructors.
|
|
1512
|
+
* Container wrapping (sandbox policy) is the orchestrator's job, not the factory's.
|
|
1513
|
+
*/
|
|
1514
|
+
declare function createBackend(def: BackendDef): AgentBackend;
|
|
1515
|
+
|
|
1516
|
+
export { type AgentUpdateEvent, AnalysisArchive, type AnalysisRecord, type ApplyEventResult, type ArtifactPresence, type AttemptStats, BackendRouter, type BackendRouterOptions, ClaimManager, type ClaimManagerConfig, type CleanWorkspaceEffect, type DispatchEffect, type EmitLogEffect, type EscalateEffect, type ExecFileFn, type Highlight, type HighlightsInfo, InteractionQueue, type LinearGraphQLExtension, LinearGraphQLStub, type LiveSession, type MigrationResult, MockBackend, ORCHESTRATOR_IDENTITY_FILE, Orchestrator, OrchestratorBackendFactory, type OrchestratorBackendFactoryOptions, type OrchestratorContext, type OrchestratorEvent, type OrchestratorState, PRDetector, type PRDetectorLogger, type PendingInteraction, PromptRenderer, type PublishedIndex, type RateLimitSnapshot as RateLimitComputeSnapshot, type RateLimitConfig, type RateLimitSnapshot$1 as RateLimitSnapshot, type ReleaseClaimEffect, type RetryEntry, type RetryFiredEvent, RoadmapTrackerAdapter, type RunAttemptPhase, type RunningEntry, type ScheduleRetryEffect, type SideEffect, type StallDetectedEvent, type StopEffect, type StreamManifest, StreamRecorder, type TickEvent, type TokenTotals, type TriageConfig, type TriageDecision, type TriageSignals, type TriageSkill, type UpdateTokensEffect, type WorkerExitEvent, WorkflowLoader, WorkspaceHooks, WorkspaceManager, applyEvent, artifactPresenceFromIssue, calculateRetryDelay, canDispatch, computeRateLimitDelay, createBackend, createEmptyState, detectScopeTier, extractHighlights, extractTitlePrefix, getAvailableSlots, getDefaultConfig, getPerStateCount, isEligible, launchTUI, loadPublishedIndex, migrateAgentConfig, reconcile, renderAnalysisComment, renderPRComment, resolveEscalationConfig, resolveOrchestratorId, routeIssue, savePublishedIndex, selectCandidates, sortCandidates, triageIssue, validateWorkflowConfig };
|