@orc-brain/core 1.0.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/LICENSE +21 -0
- package/dist/autoLoop.d.ts +70 -0
- package/dist/autoLoop.d.ts.map +1 -0
- package/dist/autoLoop.js +178 -0
- package/dist/autoLoop.js.map +1 -0
- package/dist/backpressure.d.ts +38 -0
- package/dist/backpressure.d.ts.map +1 -0
- package/dist/backpressure.js +103 -0
- package/dist/backpressure.js.map +1 -0
- package/dist/budgetTracker.d.ts +53 -0
- package/dist/budgetTracker.d.ts.map +1 -0
- package/dist/budgetTracker.js +93 -0
- package/dist/budgetTracker.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +107 -0
- package/dist/config.js.map +1 -0
- package/dist/escalation.d.ts +43 -0
- package/dist/escalation.d.ts.map +1 -0
- package/dist/escalation.js +81 -0
- package/dist/escalation.js.map +1 -0
- package/dist/eventBus.d.ts +30 -0
- package/dist/eventBus.d.ts.map +1 -0
- package/dist/eventBus.js +42 -0
- package/dist/eventBus.js.map +1 -0
- package/dist/goalJudge.d.ts +92 -0
- package/dist/goalJudge.d.ts.map +1 -0
- package/dist/goalJudge.js +254 -0
- package/dist/goalJudge.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/modelRouter.d.ts +40 -0
- package/dist/modelRouter.d.ts.map +1 -0
- package/dist/modelRouter.js +114 -0
- package/dist/modelRouter.js.map +1 -0
- package/dist/orchestrator.d.ts +242 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +975 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pacing.d.ts +34 -0
- package/dist/pacing.d.ts.map +1 -0
- package/dist/pacing.js +49 -0
- package/dist/pacing.js.map +1 -0
- package/dist/planValidation.d.ts +24 -0
- package/dist/planValidation.d.ts.map +1 -0
- package/dist/planValidation.js +134 -0
- package/dist/planValidation.js.map +1 -0
- package/dist/planner.d.ts +70 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +210 -0
- package/dist/planner.js.map +1 -0
- package/dist/plugins/host.d.ts +39 -0
- package/dist/plugins/host.d.ts.map +1 -0
- package/dist/plugins/host.js +109 -0
- package/dist/plugins/host.js.map +1 -0
- package/dist/plugins/registry.d.ts +71 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +269 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/secrets.d.ts +30 -0
- package/dist/plugins/secrets.d.ts.map +1 -0
- package/dist/plugins/secrets.js +99 -0
- package/dist/plugins/secrets.js.map +1 -0
- package/dist/preflight.d.ts +38 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +108 -0
- package/dist/preflight.js.map +1 -0
- package/dist/reporting.d.ts +41 -0
- package/dist/reporting.d.ts.map +1 -0
- package/dist/reporting.js +229 -0
- package/dist/reporting.js.map +1 -0
- package/dist/safety/denyRules.d.ts +57 -0
- package/dist/safety/denyRules.d.ts.map +1 -0
- package/dist/safety/denyRules.js +498 -0
- package/dist/safety/denyRules.js.map +1 -0
- package/dist/safety/envClassifier.d.ts +45 -0
- package/dist/safety/envClassifier.d.ts.map +1 -0
- package/dist/safety/envClassifier.js +99 -0
- package/dist/safety/envClassifier.js.map +1 -0
- package/dist/safety/index.d.ts +83 -0
- package/dist/safety/index.d.ts.map +1 -0
- package/dist/safety/index.js +184 -0
- package/dist/safety/index.js.map +1 -0
- package/dist/safety/limitSignals.d.ts +36 -0
- package/dist/safety/limitSignals.d.ts.map +1 -0
- package/dist/safety/limitSignals.js +79 -0
- package/dist/safety/limitSignals.js.map +1 -0
- package/dist/safety/paths.d.ts +32 -0
- package/dist/safety/paths.d.ts.map +1 -0
- package/dist/safety/paths.js +102 -0
- package/dist/safety/paths.js.map +1 -0
- package/dist/safety/redact.d.ts +17 -0
- package/dist/safety/redact.d.ts.map +1 -0
- package/dist/safety/redact.js +85 -0
- package/dist/safety/redact.js.map +1 -0
- package/dist/spawnEnv.d.ts +18 -0
- package/dist/spawnEnv.d.ts.map +1 -0
- package/dist/spawnEnv.js +43 -0
- package/dist/spawnEnv.js.map +1 -0
- package/dist/store/auditLog.d.ts +28 -0
- package/dist/store/auditLog.d.ts.map +1 -0
- package/dist/store/auditLog.js +48 -0
- package/dist/store/auditLog.js.map +1 -0
- package/dist/store/index.d.ts +140 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +648 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/schema.d.ts +17 -0
- package/dist/store/schema.d.ts.map +1 -0
- package/dist/store/schema.js +197 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/system.d.ts +69 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +135 -0
- package/dist/system.js.map +1 -0
- package/dist/workerManager.d.ts +80 -0
- package/dist/workerManager.d.ts.map +1 -0
- package/dist/workerManager.js +280 -0
- package/dist/workerManager.js.map +1 -0
- package/dist/worktrees.d.ts +74 -0
- package/dist/worktrees.d.ts.map +1 -0
- package/dist/worktrees.js +210 -0
- package/dist/worktrees.js.map +1 -0
- package/package.json +48 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default orchestrator configuration (§6, §7, §8). These are the recommended
|
|
3
|
+
* defaults from §14; `orchestrator.toml` overrides land in Phase 2. Values are
|
|
4
|
+
* exported so the router, budget tracker, and safety layer share one source.
|
|
5
|
+
*/
|
|
6
|
+
/** Recommended defaults (§14: concurrency 3, warn 70%, hard-stop 90%). */
|
|
7
|
+
export const DEFAULT_CONFIG = {
|
|
8
|
+
concurrency_limit: 3,
|
|
9
|
+
// Fleet-wide worker cap across all runs (spec 002 §R13). ≥ concurrency_limit
|
|
10
|
+
// so a single-run setup behaves exactly as before.
|
|
11
|
+
global_concurrency_limit: 4,
|
|
12
|
+
budget: {
|
|
13
|
+
warn_at: 0.7,
|
|
14
|
+
hard_stop_at: 0.9,
|
|
15
|
+
per_task_min_usd: 0.5,
|
|
16
|
+
per_task_max_usd: 5,
|
|
17
|
+
max_tasks_per_run: 200,
|
|
18
|
+
max_tasks_per_hour: 120,
|
|
19
|
+
},
|
|
20
|
+
routing: {
|
|
21
|
+
// Order matters: first matching rule wins (§6). R1 (scope pin) is applied
|
|
22
|
+
// in the router before this table; R5–R7 are dynamic escalations.
|
|
23
|
+
rules: [
|
|
24
|
+
{
|
|
25
|
+
id: "R2",
|
|
26
|
+
description: "architecture-level planning/research/review → opus",
|
|
27
|
+
when: { task_types: ["planning", "research", "review"] },
|
|
28
|
+
model: "opus",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "R3",
|
|
32
|
+
description: "codegen/refactor/test → sonnet",
|
|
33
|
+
when: { task_types: ["codegen", "refactor", "test"] },
|
|
34
|
+
model: "sonnet",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "R4",
|
|
38
|
+
description: "mechanical work → haiku",
|
|
39
|
+
when: { task_types: ["mechanical"] },
|
|
40
|
+
model: "haiku",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
default_model: "sonnet",
|
|
44
|
+
// No forced model by default; set via config or ORC_FORCE_MODEL (§6 R-F).
|
|
45
|
+
force_model: null,
|
|
46
|
+
},
|
|
47
|
+
safety: {
|
|
48
|
+
// Default treats any non-local/non-RFC-1918 host as unknown ⇒ production
|
|
49
|
+
// (§8.1, Open Decision 12). Seed with real prod hosts to loosen dev friction.
|
|
50
|
+
prod_host_indicators: [],
|
|
51
|
+
prod_branches: ["main", "master", "prod", "production", "release/*"],
|
|
52
|
+
// Open Decision 5: require-approval for VCS/db/infra in dev, allow-with-audit
|
|
53
|
+
// for filesystem-within-allowlist. Prod scopes always deny regardless.
|
|
54
|
+
dev_posture: {
|
|
55
|
+
filesystem: "allow_with_audit",
|
|
56
|
+
vcs: "require_approval",
|
|
57
|
+
database: "require_approval",
|
|
58
|
+
infra: "require_approval",
|
|
59
|
+
publish: "require_approval",
|
|
60
|
+
credential: "deny",
|
|
61
|
+
network: "require_approval",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
limits: {
|
|
65
|
+
patterns: {
|
|
66
|
+
session_limit: "session limit|resets? (at )?\\d",
|
|
67
|
+
weekly_limit: "weekly limit",
|
|
68
|
+
model_limit: "(opus|sonnet|haiku) limit",
|
|
69
|
+
},
|
|
70
|
+
backoff_ms: [60_000, 120_000, 240_000, 480_000, 960_000],
|
|
71
|
+
backoff_cap_ms: 1_800_000,
|
|
72
|
+
},
|
|
73
|
+
planner: {
|
|
74
|
+
// Pinned to Opus in plan mode with read-only tools (§3). It inspects the
|
|
75
|
+
// repo to decompose the goal but can never edit or run Bash.
|
|
76
|
+
model: "opus",
|
|
77
|
+
allowed_tools: ["Read", "Glob", "Grep"],
|
|
78
|
+
max_turns: 40,
|
|
79
|
+
},
|
|
80
|
+
retry: {
|
|
81
|
+
// failed → queued, bounded (§5). 3 attempts feeds router R5 (escalate a
|
|
82
|
+
// tier after ≥2 attempts on the current model).
|
|
83
|
+
max_attempts: 3,
|
|
84
|
+
},
|
|
85
|
+
reporting: {
|
|
86
|
+
// Interval reports every 15 min while Running (§11, Open Decision 10).
|
|
87
|
+
interval_minutes: 15,
|
|
88
|
+
},
|
|
89
|
+
escalation: {
|
|
90
|
+
// Halt-scope-and-ask on the 2nd same-rule denial (§8.5, Open Decision 11).
|
|
91
|
+
block_on_denial_count: 2,
|
|
92
|
+
},
|
|
93
|
+
pause: {
|
|
94
|
+
// 60s grace, then SIGTERM, then SIGKILL after 10s (§5).
|
|
95
|
+
grace_ms: 60_000,
|
|
96
|
+
sigkill_after_ms: 10_000,
|
|
97
|
+
},
|
|
98
|
+
autoLoop: {
|
|
99
|
+
// Opt-in; default is the static plan-once behavior (autonomous-loop.md §3.5,
|
|
100
|
+
// AC1). Supervised keeps the human approval gate; runaway ceiling of 5.
|
|
101
|
+
enabled: false,
|
|
102
|
+
mode: "supervised",
|
|
103
|
+
replan_on: "scope",
|
|
104
|
+
max_replan_cycles: 5,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAuB;IAChD,iBAAiB,EAAE,CAAC;IACpB,6EAA6E;IAC7E,mDAAmD;IACnD,wBAAwB,EAAE,CAAC;IAC3B,MAAM,EAAE;QACN,OAAO,EAAE,GAAG;QACZ,YAAY,EAAE,GAAG;QACjB,gBAAgB,EAAE,GAAG;QACrB,gBAAgB,EAAE,CAAC;QACnB,iBAAiB,EAAE,GAAG;QACtB,kBAAkB,EAAE,GAAG;KACxB;IACD,OAAO,EAAE;QACP,0EAA0E;QAC1E,kEAAkE;QAClE,KAAK,EAAE;YACL;gBACE,EAAE,EAAE,IAAI;gBACR,WAAW,EAAE,oDAAoD;gBACjE,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE;gBACxD,KAAK,EAAE,MAAM;aACd;YACD;gBACE,EAAE,EAAE,IAAI;gBACR,WAAW,EAAE,gCAAgC;gBAC7C,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE;gBACrD,KAAK,EAAE,QAAQ;aAChB;YACD;gBACE,EAAE,EAAE,IAAI;gBACR,WAAW,EAAE,yBAAyB;gBACtC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;gBACpC,KAAK,EAAE,OAAO;aACf;SACF;QACD,aAAa,EAAE,QAAQ;QACvB,0EAA0E;QAC1E,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,yEAAyE;QACzE,8EAA8E;QAC9E,oBAAoB,EAAE,EAAE;QACxB,aAAa,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC;QACpE,8EAA8E;QAC9E,uEAAuE;QACvE,WAAW,EAAE;YACX,UAAU,EAAE,kBAAkB;YAC9B,GAAG,EAAE,kBAAkB;YACvB,QAAQ,EAAE,kBAAkB;YAC5B,KAAK,EAAE,kBAAkB;YACzB,OAAO,EAAE,kBAAkB;YAC3B,UAAU,EAAE,MAAM;YAClB,OAAO,EAAE,kBAAkB;SAC5B;KACF;IACD,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,aAAa,EAAE,iCAAiC;YAChD,YAAY,EAAE,cAAc;YAC5B,WAAW,EAAE,2BAA2B;SACzC;QACD,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;QACxD,cAAc,EAAE,SAAS;KAC1B;IACD,OAAO,EAAE;QACP,yEAAyE;QACzE,6DAA6D;QAC7D,KAAK,EAAE,MAAM;QACb,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QACvC,SAAS,EAAE,EAAE;KACd;IACD,KAAK,EAAE;QACL,wEAAwE;QACxE,gDAAgD;QAChD,YAAY,EAAE,CAAC;KAChB;IACD,SAAS,EAAE;QACT,uEAAuE;QACvE,gBAAgB,EAAE,EAAE;KACrB;IACD,UAAU,EAAE;QACV,2EAA2E;QAC3E,qBAAqB,EAAE,CAAC;KACzB;IACD,KAAK,EAAE;QACL,wDAAwD;QACxD,QAAQ,EAAE,MAAM;QAChB,gBAAgB,EAAE,MAAM;KACzB;IACD,QAAQ,EAAE;QACR,6EAA6E;QAC7E,wEAAwE;QACxE,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,YAAY;QAClB,SAAS,EAAE,OAAO;QAClB,iBAAiB,EAAE,CAAC;KACrB;CACF,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escalation manager (§8.5). The safety layer denies a blocked tool call and
|
|
3
|
+
* notifies this manager. On the Nth same-rule denial within one task
|
|
4
|
+
* (`escalation.block_on_denial_count`, default 2), the task transitions to
|
|
5
|
+
* `blocked`, an {@link Escalation} is raised for the operator, and the run keeps
|
|
6
|
+
* going elsewhere. Resolution (deny-&-instruct / approve-once / skip) is applied
|
|
7
|
+
* by the orchestrator, which owns task-state transitions.
|
|
8
|
+
*
|
|
9
|
+
* Default posture is halt-scope-and-ask, never log-and-skip: silent skips hide
|
|
10
|
+
* broken assumptions.
|
|
11
|
+
*/
|
|
12
|
+
import type { Escalation, OrchestratorConfig } from "@orc-brain/shared";
|
|
13
|
+
import type { Store } from "./store/index.js";
|
|
14
|
+
import type { EventBus } from "./eventBus.js";
|
|
15
|
+
/** A single denial the safety layer reports for escalation accounting. */
|
|
16
|
+
export interface DenialInput {
|
|
17
|
+
run_id: string | null;
|
|
18
|
+
task_id: string | null;
|
|
19
|
+
rule_id: string;
|
|
20
|
+
tool_name: string;
|
|
21
|
+
/** Redacted, truncated tool input for operator display (§8.6). */
|
|
22
|
+
input_summary: string;
|
|
23
|
+
stated_intent?: string | null;
|
|
24
|
+
}
|
|
25
|
+
/** Detects blockable denials and raises escalations (§8.5). */
|
|
26
|
+
export declare class EscalationManager {
|
|
27
|
+
private readonly store;
|
|
28
|
+
private readonly bus;
|
|
29
|
+
private readonly config;
|
|
30
|
+
/** Per-(task,rule) denial counter for the current run session. */
|
|
31
|
+
private readonly counts;
|
|
32
|
+
/** Invoked when a task must be blocked so a worker can be interrupted. */
|
|
33
|
+
onBlock?: (taskId: string, escalation: Escalation) => void;
|
|
34
|
+
constructor(store: Store, bus: EventBus, config: OrchestratorConfig);
|
|
35
|
+
/**
|
|
36
|
+
* Records a denial. Returns the raised {@link Escalation} when this denial
|
|
37
|
+
* crossed the block threshold, otherwise null.
|
|
38
|
+
*/
|
|
39
|
+
recordDenial(d: DenialInput): Escalation | null;
|
|
40
|
+
/** Clears the denial counters for a task (e.g., after resolution). */
|
|
41
|
+
clearTask(taskId: string): void;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=escalation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation.d.ts","sourceRoot":"","sources":["../src/escalation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,+DAA+D;AAC/D,qBAAa,iBAAiB;IAO1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,0EAA0E;IAC1E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;gBAGxC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,kBAAkB;IAG7C;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI;IA8C/C,sEAAsE;IACtE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAKhC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escalation manager (§8.5). The safety layer denies a blocked tool call and
|
|
3
|
+
* notifies this manager. On the Nth same-rule denial within one task
|
|
4
|
+
* (`escalation.block_on_denial_count`, default 2), the task transitions to
|
|
5
|
+
* `blocked`, an {@link Escalation} is raised for the operator, and the run keeps
|
|
6
|
+
* going elsewhere. Resolution (deny-&-instruct / approve-once / skip) is applied
|
|
7
|
+
* by the orchestrator, which owns task-state transitions.
|
|
8
|
+
*
|
|
9
|
+
* Default posture is halt-scope-and-ask, never log-and-skip: silent skips hide
|
|
10
|
+
* broken assumptions.
|
|
11
|
+
*/
|
|
12
|
+
/** Detects blockable denials and raises escalations (§8.5). */
|
|
13
|
+
export class EscalationManager {
|
|
14
|
+
store;
|
|
15
|
+
bus;
|
|
16
|
+
config;
|
|
17
|
+
/** Per-(task,rule) denial counter for the current run session. */
|
|
18
|
+
counts = new Map();
|
|
19
|
+
/** Invoked when a task must be blocked so a worker can be interrupted. */
|
|
20
|
+
onBlock;
|
|
21
|
+
constructor(store, bus, config) {
|
|
22
|
+
this.store = store;
|
|
23
|
+
this.bus = bus;
|
|
24
|
+
this.config = config;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Records a denial. Returns the raised {@link Escalation} when this denial
|
|
28
|
+
* crossed the block threshold, otherwise null.
|
|
29
|
+
*/
|
|
30
|
+
recordDenial(d) {
|
|
31
|
+
if (!d.task_id || !d.run_id)
|
|
32
|
+
return null;
|
|
33
|
+
const key = `${d.task_id}:${d.rule_id}`;
|
|
34
|
+
const n = (this.counts.get(key) ?? 0) + 1;
|
|
35
|
+
this.counts.set(key, n);
|
|
36
|
+
if (n < this.config.escalation.block_on_denial_count)
|
|
37
|
+
return null;
|
|
38
|
+
// Avoid raising a duplicate escalation for an already-blocked task+rule.
|
|
39
|
+
const existing = this.store
|
|
40
|
+
.listOpenEscalations(d.run_id)
|
|
41
|
+
.find((e) => e.task_id === d.task_id && e.rule_id === d.rule_id);
|
|
42
|
+
if (existing)
|
|
43
|
+
return null;
|
|
44
|
+
this.store.updateTask(d.task_id, { status: "blocked" });
|
|
45
|
+
const escalation = this.store.insertEscalation({
|
|
46
|
+
run_id: d.run_id,
|
|
47
|
+
task_id: d.task_id,
|
|
48
|
+
rule_id: d.rule_id,
|
|
49
|
+
tool_name: d.tool_name,
|
|
50
|
+
input_summary: d.input_summary,
|
|
51
|
+
stated_intent: d.stated_intent ?? null,
|
|
52
|
+
});
|
|
53
|
+
this.bus.publish({
|
|
54
|
+
type: "escalation.new",
|
|
55
|
+
run_id: d.run_id,
|
|
56
|
+
payload: {
|
|
57
|
+
escalation_id: escalation.id,
|
|
58
|
+
task_id: d.task_id,
|
|
59
|
+
rule_id: d.rule_id,
|
|
60
|
+
tool_name: d.tool_name,
|
|
61
|
+
input_summary: d.input_summary,
|
|
62
|
+
stated_intent: escalation.stated_intent ?? undefined,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
this.bus.publish({
|
|
66
|
+
type: "task.state",
|
|
67
|
+
run_id: d.run_id,
|
|
68
|
+
payload: { task_id: d.task_id, scope_id: "", status: "blocked" },
|
|
69
|
+
});
|
|
70
|
+
this.onBlock?.(d.task_id, escalation);
|
|
71
|
+
return escalation;
|
|
72
|
+
}
|
|
73
|
+
/** Clears the denial counters for a task (e.g., after resolution). */
|
|
74
|
+
clearTask(taskId) {
|
|
75
|
+
for (const key of [...this.counts.keys()]) {
|
|
76
|
+
if (key.startsWith(`${taskId}:`))
|
|
77
|
+
this.counts.delete(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=escalation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation.js","sourceRoot":"","sources":["../src/escalation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event bus (§3): in-process typed pub/sub. Every event is *synchronously
|
|
3
|
+
* appended to the store before fan-out*, so the persisted log is never behind
|
|
4
|
+
* the UI. The store assigns the monotonic `seq` used as the SSE `id:` for
|
|
5
|
+
* Last-Event-ID resume.
|
|
6
|
+
*/
|
|
7
|
+
import type { BusEvent } from "@orc-brain/shared";
|
|
8
|
+
import type { Store } from "./store/index.js";
|
|
9
|
+
/** A subscriber receives every published event, in order. */
|
|
10
|
+
export type BusSubscriber = (event: BusEvent) => void;
|
|
11
|
+
/** Input to {@link EventBus.publish}: everything but the store-assigned `seq`. */
|
|
12
|
+
export type PublishInput = Omit<BusEvent, "seq" | "ts"> & {
|
|
13
|
+
ts?: string;
|
|
14
|
+
};
|
|
15
|
+
/** Typed in-process event bus backed by the persistent store. */
|
|
16
|
+
export declare class EventBus {
|
|
17
|
+
private readonly store;
|
|
18
|
+
private readonly subscribers;
|
|
19
|
+
constructor(store: Store);
|
|
20
|
+
/** Subscribes to all events; returns an unsubscribe function. */
|
|
21
|
+
subscribe(fn: BusSubscriber): () => void;
|
|
22
|
+
/**
|
|
23
|
+
* Persists then fans out an event. Persistence happens first and
|
|
24
|
+
* synchronously (better-sqlite3), guaranteeing the store is never behind a
|
|
25
|
+
* delivered event. Subscriber exceptions are isolated so one bad listener
|
|
26
|
+
* cannot break delivery to the others or the caller.
|
|
27
|
+
*/
|
|
28
|
+
publish(input: PublishInput): BusEvent;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=eventBus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventBus.d.ts","sourceRoot":"","sources":["../src/eventBus.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEtD,kFAAkF;AAClF,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,iEAAiE;AACjE,qBAAa,QAAQ;IAGP,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFlC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4B;gBAE3B,KAAK,EAAE,KAAK;IAEzC,iEAAiE;IACjE,SAAS,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,IAAI;IAKxC;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,QAAQ;CAevC"}
|
package/dist/eventBus.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event bus (§3): in-process typed pub/sub. Every event is *synchronously
|
|
3
|
+
* appended to the store before fan-out*, so the persisted log is never behind
|
|
4
|
+
* the UI. The store assigns the monotonic `seq` used as the SSE `id:` for
|
|
5
|
+
* Last-Event-ID resume.
|
|
6
|
+
*/
|
|
7
|
+
/** Typed in-process event bus backed by the persistent store. */
|
|
8
|
+
export class EventBus {
|
|
9
|
+
store;
|
|
10
|
+
subscribers = new Set();
|
|
11
|
+
constructor(store) {
|
|
12
|
+
this.store = store;
|
|
13
|
+
}
|
|
14
|
+
/** Subscribes to all events; returns an unsubscribe function. */
|
|
15
|
+
subscribe(fn) {
|
|
16
|
+
this.subscribers.add(fn);
|
|
17
|
+
return () => this.subscribers.delete(fn);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Persists then fans out an event. Persistence happens first and
|
|
21
|
+
* synchronously (better-sqlite3), guaranteeing the store is never behind a
|
|
22
|
+
* delivered event. Subscriber exceptions are isolated so one bad listener
|
|
23
|
+
* cannot break delivery to the others or the caller.
|
|
24
|
+
*/
|
|
25
|
+
publish(input) {
|
|
26
|
+
const ts = input.ts ?? new Date().toISOString();
|
|
27
|
+
const withoutSeq = { ...input, ts };
|
|
28
|
+
const seq = this.store.appendEvent(withoutSeq);
|
|
29
|
+
const event = { ...withoutSeq, seq };
|
|
30
|
+
for (const fn of this.subscribers) {
|
|
31
|
+
try {
|
|
32
|
+
fn(event);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
// Never let a subscriber failure propagate to the publisher.
|
|
36
|
+
console.error("[eventBus] subscriber threw:", err);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return event;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=eventBus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventBus.js","sourceRoot":"","sources":["../src/eventBus.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,iEAAiE;AACjE,MAAM,OAAO,QAAQ;IAGU;IAFZ,WAAW,GAAG,IAAI,GAAG,EAAiB,CAAC;IAExD,YAA6B,KAAY;QAAZ,UAAK,GAAL,KAAK,CAAO;IAAG,CAAC;IAE7C,iEAAiE;IACjE,SAAS,CAAC,EAAiB;QACzB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,KAAmB;QACzB,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAChD,MAAM,UAAU,GAAG,EAAE,GAAG,KAAK,EAAE,EAAE,EAA2B,CAAC;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,EAAc,CAAC;QACjD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,EAAE,CAAC,KAAK,CAAC,CAAC;YACZ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,6DAA6D;gBAC7D,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid goal-satisfaction evaluator (.specs/active/autonomous-loop.md §3.4, G3;
|
|
3
|
+
* spec §4 success_criteria). Decides whether a run's success criteria are met so
|
|
4
|
+
* the autonomous controller can finish (or trigger another re-plan cycle),
|
|
5
|
+
* replacing the DAG-exhaustion-only check in `Orchestrator.maybeFinish`.
|
|
6
|
+
*
|
|
7
|
+
* Two passes:
|
|
8
|
+
* 1. Deterministic — criteria written as `` `$ <cmd>` `` are shell checks. Each
|
|
9
|
+
* is routed through the SAME {@link SafetyLayer} as a worker (Golden Rule 2,
|
|
10
|
+
* R3): a denied command is NEVER executed — it is recorded as unmet and
|
|
11
|
+
* audited. An allowed command runs; exit 0 = met.
|
|
12
|
+
* 2. Judge — remaining prose criteria go to an Opus plan-mode (read-only)
|
|
13
|
+
* session that inspects the repo and returns met/unmet + rationale.
|
|
14
|
+
*
|
|
15
|
+
* Deterministic failures are authoritative: the judge can never flip a failing
|
|
16
|
+
* command check to satisfied (AC4).
|
|
17
|
+
*/
|
|
18
|
+
import type { Environment, OrchestratorConfig } from "@orc-brain/shared";
|
|
19
|
+
import { SafetyLayer } from "./safety/index.js";
|
|
20
|
+
import type { AuditSink } from "./safety/index.js";
|
|
21
|
+
import type { PlanQueryFn } from "./planner.js";
|
|
22
|
+
/** Runs a shell command in `cwd`; returns its exit code (non-zero on failure). */
|
|
23
|
+
export type CommandRunner = (command: string, cwd: string) => {
|
|
24
|
+
exitCode: number;
|
|
25
|
+
};
|
|
26
|
+
/** The evaluator's verdict for a run's criteria. */
|
|
27
|
+
export interface GoalVerdict {
|
|
28
|
+
satisfied: boolean;
|
|
29
|
+
/** Descriptions of the criteria still unmet (empty when satisfied). */
|
|
30
|
+
unmet: string[];
|
|
31
|
+
/** Human-readable explanation, joined across criteria. */
|
|
32
|
+
rationale: string;
|
|
33
|
+
}
|
|
34
|
+
/** Inputs for one evaluation pass over a goal's aggregated criteria. */
|
|
35
|
+
export interface EvaluateInput {
|
|
36
|
+
run_id: string | null;
|
|
37
|
+
goal_id: string;
|
|
38
|
+
title: string;
|
|
39
|
+
objective: string;
|
|
40
|
+
cwd: string;
|
|
41
|
+
environment: Environment;
|
|
42
|
+
/** Aggregated success-criteria descriptions (goal + verified scopes). */
|
|
43
|
+
criteria: string[];
|
|
44
|
+
}
|
|
45
|
+
/** A per-criterion judge result. */
|
|
46
|
+
interface JudgeResult {
|
|
47
|
+
met: boolean;
|
|
48
|
+
rationale: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parses an executable criterion (Open Decision 2): a description of the form
|
|
52
|
+
* `` `$ <cmd>` `` or `$ <cmd>` marks a deterministic shell check. Returns the
|
|
53
|
+
* command, or null when the criterion is prose for the judge.
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseCommandCriterion(description: string): string | null;
|
|
56
|
+
/** Builds the judge prompt for prose criteria (read-only, plan-mode session). */
|
|
57
|
+
export declare function buildJudgePrompt(title: string, objective: string, criteria: string[]): string;
|
|
58
|
+
/** The hybrid evaluator (autonomous-loop.md §3.4). */
|
|
59
|
+
export declare class GoalJudge {
|
|
60
|
+
private readonly config;
|
|
61
|
+
private readonly safety;
|
|
62
|
+
private readonly audit;
|
|
63
|
+
private readonly runCommand;
|
|
64
|
+
private readonly judgeQueryFn?;
|
|
65
|
+
constructor(config: OrchestratorConfig, safety: SafetyLayer, audit: AuditSink, opts?: {
|
|
66
|
+
runCommand?: CommandRunner;
|
|
67
|
+
judgeQueryFn?: PlanQueryFn;
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Evaluates a run's criteria (autonomous-loop.md §3.4). Deterministic command
|
|
71
|
+
* checks run first through the safety layer; remaining prose criteria go to
|
|
72
|
+
* the judge. `satisfied` is true only when EVERY criterion is met.
|
|
73
|
+
*/
|
|
74
|
+
evaluate(input: EvaluateInput): Promise<GoalVerdict>;
|
|
75
|
+
/** Records a blocked criterion command in the audit log (§8.6, AC5). */
|
|
76
|
+
private auditDenied;
|
|
77
|
+
/**
|
|
78
|
+
* Runs the read-only judge session over prose criteria and returns one result
|
|
79
|
+
* per criterion (in order). If no judge session is wired, or the session
|
|
80
|
+
* yields nothing usable, every prose criterion defaults to NOT met (strict).
|
|
81
|
+
*/
|
|
82
|
+
private judgeProse;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Extracts judge results from an SDK stream: prefers `structured_output.results`,
|
|
86
|
+
* falls back to a fenced/loose JSON object with a `results` array. Defensive
|
|
87
|
+
* (no validation library): anything unparseable yields an empty array so callers
|
|
88
|
+
* treat all criteria as not met.
|
|
89
|
+
*/
|
|
90
|
+
export declare function parseJudgeResults(structured: unknown, finalText: string): JudgeResult[];
|
|
91
|
+
export {};
|
|
92
|
+
//# sourceMappingURL=goalJudge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goalJudge.d.ts","sourceRoot":"","sources":["../src/goalJudge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAEnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAsB,MAAM,mBAAmB,CAAC;AAIvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,kFAAkF;AAClF,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,KACR;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1B,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,WAAW,CAAC;IACzB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,oCAAoC;AACpC,UAAU,WAAW;IACnB,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGxE;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,CAmBR;AAgCD,sDAAsD;AACtD,qBAAa,SAAS;IAKlB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IANxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAc;gBAGzB,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,SAAS,EACjC,IAAI,GAAE;QAAE,UAAU,CAAC,EAAE,aAAa,CAAC;QAAC,YAAY,CAAC,EAAE,WAAW,CAAA;KAAO;IAMvE;;;;OAIG;IACG,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;IA4D1D,wEAAwE;IACxE,OAAO,CAAC,WAAW;IAwBnB;;;;OAIG;YACW,UAAU;CA2CzB;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,MAAM,GAChB,WAAW,EAAE,CA2Bf"}
|