@aria_asi/cli 0.2.36 → 0.2.37
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/CLIENT-ONBOARDING.md +4 -2
- package/bin/aria.js +11 -7
- package/dist/aria-connector/src/auth.d.ts +14 -0
- package/dist/aria-connector/src/auth.d.ts.map +1 -1
- package/dist/aria-connector/src/auth.js +103 -1
- package/dist/aria-connector/src/auth.js.map +1 -1
- package/dist/aria-connector/src/chat.d.ts.map +1 -1
- package/dist/aria-connector/src/chat.js +13 -8
- package/dist/aria-connector/src/chat.js.map +1 -1
- package/dist/aria-connector/src/config.d.ts +6 -1
- package/dist/aria-connector/src/config.d.ts.map +1 -1
- package/dist/aria-connector/src/config.js.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.js +50 -6
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +310 -10
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.js +35 -11
- package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
- package/dist/aria-connector/src/connectors/repo-guard.d.ts +10 -0
- package/dist/aria-connector/src/connectors/repo-guard.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/repo-guard.js +110 -164
- package/dist/aria-connector/src/connectors/repo-guard.js.map +1 -1
- package/dist/aria-connector/src/connectors/runtime.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/runtime.js +17 -7
- package/dist/aria-connector/src/connectors/runtime.js.map +1 -1
- package/dist/aria-connector/src/connectors/shell.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/shell.js +12 -8
- package/dist/aria-connector/src/connectors/shell.js.map +1 -1
- package/dist/aria-connector/src/harness-client.d.ts +3 -1
- package/dist/aria-connector/src/harness-client.d.ts.map +1 -1
- package/dist/aria-connector/src/harness-client.js +7 -20
- package/dist/aria-connector/src/harness-client.js.map +1 -1
- package/dist/aria-connector/src/model-context.d.ts.map +1 -1
- package/dist/aria-connector/src/model-context.js +5 -0
- package/dist/aria-connector/src/model-context.js.map +1 -1
- package/dist/aria-connector/src/providers/types.d.ts +1 -1
- package/dist/aria-connector/src/providers/types.d.ts.map +1 -1
- package/dist/aria-connector/src/providers/xai.d.ts +3 -0
- package/dist/aria-connector/src/providers/xai.d.ts.map +1 -0
- package/dist/aria-connector/src/providers/xai.js +40 -0
- package/dist/aria-connector/src/providers/xai.js.map +1 -0
- package/dist/aria-connector/src/setup-wizard.js +1 -0
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/aria-connector/src/types.d.ts +2 -0
- package/dist/aria-connector/src/types.d.ts.map +1 -1
- package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +51 -9
- package/dist/assets/hooks/aria-first-class-coach.mjs +129 -0
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +33 -6
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +33 -8
- package/dist/assets/hooks/aria-preprompt-consult.mjs +5 -6
- package/dist/assets/hooks/aria-preturn-memory-gate.mjs +5 -0
- package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +15 -0
- package/dist/assets/hooks/aria-stop-gate.mjs +125 -17
- package/dist/assets/hooks/doctrine_trigger_map.json +11 -0
- package/dist/assets/hooks/lib/emergency-gateoff-impl.mjs +39 -0
- package/dist/assets/hooks/lib/emergency-gateoff.mjs +6 -0
- package/dist/assets/hooks/lib/first-class-coach.mjs +755 -0
- package/dist/assets/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +1 -14
- package/dist/assets/opencode-plugins/harness-context/auth-token.mjs +126 -0
- package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +62 -22
- package/dist/assets/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +87 -27
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
- package/dist/assets/opencode-plugins/harness-outcome/index.js +29 -24
- package/dist/assets/opencode-plugins/harness-stop/index.js +229 -68
- package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
- package/dist/runtime/auth-token.mjs +121 -0
- package/dist/runtime/coach-kernel.mjs +371 -0
- package/dist/runtime/codex-bridge.mjs +440 -69
- package/dist/runtime/discipline/doctrine_trigger_map.json +11 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +18 -0
- package/dist/runtime/doctrine_trigger_map.json +11 -0
- package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +51 -9
- package/dist/runtime/hooks/aria-first-class-coach.mjs +129 -0
- package/dist/runtime/hooks/aria-harness-via-sdk.mjs +33 -6
- package/dist/runtime/hooks/aria-pre-tool-gate.mjs +33 -8
- package/dist/runtime/hooks/aria-preprompt-consult.mjs +5 -6
- package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +5 -0
- package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +15 -0
- package/dist/runtime/hooks/aria-stop-gate.mjs +125 -17
- package/dist/runtime/hooks/doctrine_trigger_map.json +11 -0
- package/dist/runtime/hooks/lib/emergency-gateoff-impl.mjs +39 -0
- package/dist/runtime/hooks/lib/emergency-gateoff.mjs +6 -0
- package/dist/runtime/hooks/lib/first-class-coach.mjs +755 -0
- package/dist/runtime/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
- package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +1 -14
- package/dist/runtime/local-phase.mjs +8 -0
- package/dist/runtime/manifest.json +2 -2
- package/dist/runtime/provider-proxy.mjs +136 -33
- package/dist/runtime/sdk/BUNDLED.json +2 -2
- package/dist/runtime/sdk/auth.d.ts +17 -0
- package/dist/runtime/sdk/auth.js +158 -0
- package/dist/runtime/sdk/auth.js.map +1 -0
- package/dist/runtime/sdk/index.d.ts +8 -1
- package/dist/runtime/sdk/index.js +15 -1
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/service.mjs +1711 -74
- package/dist/runtime/task-project-ledger.mjs +290 -0
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/auth.d.ts +17 -0
- package/dist/sdk/auth.js +158 -0
- package/dist/sdk/auth.js.map +1 -0
- package/dist/sdk/index.d.ts +8 -1
- package/dist/sdk/index.js +15 -1
- package/dist/sdk/index.js.map +1 -1
- package/hooks/aria-cognition-substrate-binding.mjs +51 -9
- package/hooks/aria-first-class-coach.mjs +129 -0
- package/hooks/aria-harness-via-sdk.mjs +33 -6
- package/hooks/aria-pre-tool-gate.mjs +33 -8
- package/hooks/aria-preprompt-consult.mjs +5 -6
- package/hooks/aria-preturn-memory-gate.mjs +5 -0
- package/hooks/aria-repo-doctrine-gate.mjs +15 -0
- package/hooks/aria-stop-gate.mjs +125 -17
- package/hooks/doctrine_trigger_map.json +11 -0
- package/hooks/lib/emergency-gateoff-impl.mjs +39 -0
- package/hooks/lib/emergency-gateoff.mjs +6 -0
- package/hooks/lib/first-class-coach.mjs +755 -0
- package/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
- package/hooks/lib/skill-autoload-gate.mjs +1 -14
- package/opencode-plugins/harness-context/auth-token.mjs +126 -0
- package/opencode-plugins/harness-context/inject-context.mjs +62 -22
- package/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
- package/opencode-plugins/harness-gate/index.js +87 -27
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
- package/opencode-plugins/harness-outcome/index.js +29 -24
- package/opencode-plugins/harness-stop/index.js +229 -68
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
- package/package.json +8 -2
- package/runtime-src/auth-token.mjs +121 -0
- package/runtime-src/coach-kernel.mjs +371 -0
- package/runtime-src/codex-bridge.mjs +440 -69
- package/runtime-src/local-phase.mjs +8 -0
- package/runtime-src/provider-proxy.mjs +136 -33
- package/runtime-src/service.mjs +1711 -74
- package/scripts/bundle-sdk.mjs +8 -0
- package/scripts/check-client-compatibility.mjs +422 -0
- package/scripts/check-coach-kernel.mjs +204 -0
- package/scripts/check-managed-runtime-ledger.mjs +107 -0
- package/scripts/check-opencode-config-contract.mjs +78 -0
- package/scripts/check-quality-ledger.mjs +121 -0
- package/scripts/self-test-harness-gates.mjs +179 -11
- package/scripts/self-test-repo-guard.mjs +38 -0
- package/scripts/validate-skill-prompts.mjs +14 -1
- package/skills/aria-cognition/aria-essence/SKILL.md +18 -0
- package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
- package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
- package/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
- package/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
- package/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
- package/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
- package/skills/aria-cognition/mizan/SKILL.md +18 -0
- package/skills/aria-cognition/nadia/SKILL.md +18 -0
- package/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
- package/skills/aria-cognition/predictor/SKILL.md +18 -0
- package/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
- package/skills/aria-cognition/soul-domains/SKILL.md +18 -0
- package/src/auth.ts +136 -1
- package/src/chat.ts +13 -8
- package/src/config.ts +6 -1
- package/src/connectors/claude-code.ts +62 -18
- package/src/connectors/codex.ts +308 -10
- package/src/connectors/opencode.ts +35 -12
- package/src/connectors/repo-guard.ts +117 -172
- package/src/connectors/runtime.ts +19 -7
- package/src/connectors/shell.ts +12 -8
- package/src/harness-client.ts +8 -22
- package/src/model-context.ts +6 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/xai.ts +55 -0
- package/src/setup-wizard.ts +1 -0
- package/src/types.ts +2 -0
package/dist/runtime/service.mjs
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { createServer } from 'node:http';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
5
6
|
import { createHash, createCipheriv, createDecipheriv, randomBytes, randomUUID, scryptSync } from 'node:crypto';
|
|
6
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
8
9
|
import { dirname, join } from 'node:path';
|
|
9
10
|
|
|
10
11
|
import { HTTPHarnessClient } from './sdk/index.js';
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
callProviderForOpenAI,
|
|
14
15
|
extractAnthropicUserMessage,
|
|
15
16
|
extractOpenAIUserMessage,
|
|
17
|
+
resolveProviderConfig,
|
|
16
18
|
} from './provider-proxy.mjs';
|
|
17
19
|
import { recordTokenUsage, brandModel, getUsageSummary, getBillingSummary, getSubscriptionTier } from './metering.mjs';
|
|
18
20
|
import { deployFleet, loadFleet, saveFleet, getFleetStatus, buildAgentSystemPrompt } from './fleet-engine.mjs';
|
|
@@ -35,6 +37,13 @@ import {
|
|
|
35
37
|
evaluateMizanPre,
|
|
36
38
|
summarizeMizanBundle,
|
|
37
39
|
} from './mizan-scheduler.mjs';
|
|
40
|
+
import {
|
|
41
|
+
COACH_PHASES,
|
|
42
|
+
formatCoachClientBlock,
|
|
43
|
+
readCoachState,
|
|
44
|
+
recordCoachPhase,
|
|
45
|
+
} from './coach-kernel.mjs';
|
|
46
|
+
import { resolveAriaAuthToken } from './auth-token.mjs';
|
|
38
47
|
|
|
39
48
|
const require = createRequire(import.meta.url);
|
|
40
49
|
const { runFullChain } = require('./vendor/aria-gate-runtime/index.js');
|
|
@@ -66,12 +75,24 @@ const STATE_DIR = join(__dirname, 'state');
|
|
|
66
75
|
const LEASE_PATH = join(STATE_DIR, 'lease.enc');
|
|
67
76
|
const OFFLINE_BUNDLE_PATH = join(STATE_DIR, 'offline-policy-bundle.enc');
|
|
68
77
|
const RUNTIME_META_PATH = join(STATE_DIR, 'runtime-meta.json');
|
|
78
|
+
const MANAGED_RUNTIME_LEDGER_PATH = join(STATE_DIR, 'managed-runtime-ledger.jsonl');
|
|
69
79
|
const AUTONOMY_STATE_PATH = join(STATE_DIR, 'autonomy.json');
|
|
70
80
|
const COGNITION_STATE_PATH = join(STATE_DIR, 'cognition-state.enc');
|
|
71
81
|
const HIVE_FILE_LEASES_PATH = join(STATE_DIR, 'hive-file-leases.json');
|
|
72
82
|
const REVOCATION_LOCK_PATH = join(STATE_DIR, 'revoked.json');
|
|
73
83
|
const CONFIG_PATH = join(process.env.HOME || '', '.aria', 'config.json');
|
|
74
84
|
const CODEBASE_AWARENESS_STATE_PATH = join(process.env.HOME || '', '.aria', 'codebase-awareness-state.json');
|
|
85
|
+
const CURRENT_RECOVERY_PATH = join(process.env.HOME || '', '.aria', 'governance-recovery-current.json');
|
|
86
|
+
const OPENCLAW_BIN_CANDIDATES = [
|
|
87
|
+
process.env.OPENCLAW_BIN,
|
|
88
|
+
join(process.env.HOME || '', '.npm-global', 'bin', 'openclaw'),
|
|
89
|
+
'openclaw',
|
|
90
|
+
].filter(Boolean);
|
|
91
|
+
const OPENCLAW_RUNTIME_MODULE_CANDIDATES = [
|
|
92
|
+
process.env.OPENCLAW_RUNTIME_MODULE,
|
|
93
|
+
join(process.env.HOME || '', '.npm-global', 'lib', 'node_modules', 'openclaw', 'dist', 'plugins', 'runtime', 'index.js'),
|
|
94
|
+
join(process.cwd(), 'node_modules', 'openclaw', 'dist', 'plugins', 'runtime', 'index.js'),
|
|
95
|
+
].filter(Boolean);
|
|
75
96
|
const LEGACY_PACKET_CACHE_CANDIDATES = [
|
|
76
97
|
join(process.env.HOME || '', '.aria', '.aria-harness-last-packet.json'),
|
|
77
98
|
join(process.env.HOME || '', '.claude', '.aria-harness-last-packet.json'),
|
|
@@ -83,6 +104,7 @@ const PRINCIPLE_LIMIT = 400;
|
|
|
83
104
|
const PATTERN_LIMIT = 400;
|
|
84
105
|
const RECEIPT_LIMIT = 500;
|
|
85
106
|
const OWNER_TOKEN_PATH = join(process.env.HOME || '', '.aria', 'owner-token');
|
|
107
|
+
const LICENSE_PATH = join(process.env.HOME || '', '.aria', 'license.json');
|
|
86
108
|
const COGNITION_BLOCK_RX = /<cognition>([\s\S]*?)<\/cognition>/i;
|
|
87
109
|
const VERIFY_BLOCK_RX =
|
|
88
110
|
/<verify>[\s\S]*?target\s*:[\s\S]*?role\s*:[\s\S]*?verified\s*:[\s\S]*?rollback\s*:[\s\S]*?axiom\s*:[\s\S]*?<\/verify>/i;
|
|
@@ -93,6 +115,14 @@ const QUALITATIVE_DRIFT_RX = /\b(?:better|improved|should work|more reliable|cle
|
|
|
93
115
|
const DECISION_SIGNAL_RX = /(?:should|recommend|propose|suggest|let'?s|go with|i'd|i would|here'?s the plan|i'll|next step|action item|ship it|yes do|let me)/i;
|
|
94
116
|
const TRIVIAL_ACK_RX = /^(?:got it|on it|ok|sure|yes|no|done|ack)\b/i;
|
|
95
117
|
const NON_TRIVIAL_MIN_CHARS = 300;
|
|
118
|
+
const PROVIDER_RECOVERY_ATTEMPTS = Math.min(
|
|
119
|
+
2,
|
|
120
|
+
Math.max(0, Number(process.env.ARIA_RUNTIME_PROVIDER_RECOVERY_ATTEMPTS || 2)),
|
|
121
|
+
);
|
|
122
|
+
const PROVIDER_RECOVERY_MIN_TOKENS = Math.max(
|
|
123
|
+
1024,
|
|
124
|
+
Number(process.env.ARIA_RUNTIME_PROVIDER_RECOVERY_MIN_TOKENS || 2048),
|
|
125
|
+
);
|
|
96
126
|
const READABLE_LENS_SLOTS = [
|
|
97
127
|
{ key: 'truth', aliases: ['truth', 'nur', 'zahir'] },
|
|
98
128
|
{ key: 'harm', aliases: ['harm', 'mizan', 'batin'] },
|
|
@@ -114,6 +144,14 @@ const DOCTRINE_TRIGGER_MAP_CANDIDATES = [
|
|
|
114
144
|
join(process.env.HOME || '', '.opencode', 'doctrine_trigger_map.json'),
|
|
115
145
|
];
|
|
116
146
|
const DOCTRINE_TRIGGER_SYNC_INTERVAL_MS = Number(process.env.ARIA_DOCTRINE_TRIGGER_SYNC_INTERVAL_MS || 5000);
|
|
147
|
+
const SKILL_BODY_MAX_CHARS = Number(process.env.ARIA_RUNTIME_SKILL_BODY_MAX_CHARS || 20000);
|
|
148
|
+
const SKILL_SEARCH_ROOTS = [
|
|
149
|
+
join(__dirname, 'discipline', 'skills', 'aria-harness'),
|
|
150
|
+
join(__dirname, 'discipline', 'skills', 'aria-cognition'),
|
|
151
|
+
join(__dirname, '..', 'skills', 'aria-cognition'),
|
|
152
|
+
join(process.env.HOME || '', '.aria', 'runtime', 'discipline', 'skills', 'aria-harness'),
|
|
153
|
+
join(process.env.HOME || '', '.aria', 'runtime', 'discipline', 'skills', 'aria-cognition'),
|
|
154
|
+
];
|
|
117
155
|
const TOOL_DEPLOY_PATTERNS = [
|
|
118
156
|
/\b(?:\.\/)?scripts\/deploy-/i,
|
|
119
157
|
/\bkubectl\s+apply\b/i,
|
|
@@ -385,7 +423,16 @@ function loadDoctrineTriggerMap() {
|
|
|
385
423
|
return latest.map;
|
|
386
424
|
}
|
|
387
425
|
|
|
426
|
+
function isAriaControlOutput(text) {
|
|
427
|
+
return /^(?:ARIA CODEX RECOVERY CONTRACT|Aria runtime blocked final output for this Codex turn\.|Aria runtime blocked this output after running the recovery contract\.|Aria runtime post-phase blocked emission:|Aria stop gate blocked output:|Aria task\/project ledger blocked output claim\.|Aria .*Recovery contract:)/i.test(String(text || '').trim());
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function doctrineTriggerLabel(entry = {}) {
|
|
431
|
+
return entry.trigger_id || entry.id || entry.memory || entry.doctrine || 'doctrine_trigger';
|
|
432
|
+
}
|
|
433
|
+
|
|
388
434
|
function collectDoctrineTriggerHits(text) {
|
|
435
|
+
if (isAriaControlOutput(text)) return [];
|
|
389
436
|
const triggerMap = loadDoctrineTriggerMap();
|
|
390
437
|
const source = String(text || '');
|
|
391
438
|
const lowerText = source.toLowerCase();
|
|
@@ -399,7 +446,8 @@ function collectDoctrineTriggerHits(text) {
|
|
|
399
446
|
const memoryCited = memoryName && lowerText.includes(memoryName.toLowerCase());
|
|
400
447
|
if (memoryCited) continue;
|
|
401
448
|
hits.push({
|
|
402
|
-
trigger: entry
|
|
449
|
+
trigger: doctrineTriggerLabel(entry),
|
|
450
|
+
triggerId: entry.trigger_id || entry.id || null,
|
|
403
451
|
memory: entry.memory || null,
|
|
404
452
|
teaching: entry.teaching || null,
|
|
405
453
|
message: entry.message || null,
|
|
@@ -422,6 +470,142 @@ function buildToolGateBlockMessage(blockers) {
|
|
|
422
470
|
].join('\n');
|
|
423
471
|
}
|
|
424
472
|
|
|
473
|
+
function uniqueStrings(values) {
|
|
474
|
+
return Array.from(new Set(values.map((value) => String(value || '').trim()).filter(Boolean)));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function failureSummaryFromEvaluation(evaluation) {
|
|
478
|
+
if (!evaluation || typeof evaluation !== 'object') return ['runtime evaluation failed before producing a verdict'];
|
|
479
|
+
const validationIssues = Array.isArray(evaluation.validation?.violations)
|
|
480
|
+
? evaluation.validation.violations.map((violation) => `validation: ${violation}`)
|
|
481
|
+
: [];
|
|
482
|
+
const layer3Issues = Array.isArray(evaluation.layer3?.failures)
|
|
483
|
+
? evaluation.layer3.failures
|
|
484
|
+
.filter((failure) => !failure?.severity || String(failure.severity).toLowerCase() === 'block')
|
|
485
|
+
.map((failure) => `layer3: ${failure.detail || failure.kind || 'runtime gate failed'}`)
|
|
486
|
+
: [];
|
|
487
|
+
const postIssues = Array.isArray(evaluation.postResult?.notes)
|
|
488
|
+
? evaluation.postResult.notes.map((note) => `post: ${note}`)
|
|
489
|
+
: [];
|
|
490
|
+
const doctrineIssues = Array.isArray(evaluation.doctrineBlockers)
|
|
491
|
+
? evaluation.doctrineBlockers.map((blocker) => `doctrine: ${blocker}`)
|
|
492
|
+
: [];
|
|
493
|
+
const toolIssues = Array.isArray(evaluation.toolGateBlockers)
|
|
494
|
+
? evaluation.toolGateBlockers.map((blocker) => `tool_gate: ${blocker}`)
|
|
495
|
+
: [];
|
|
496
|
+
return uniqueStrings([
|
|
497
|
+
...validationIssues,
|
|
498
|
+
...layer3Issues,
|
|
499
|
+
...postIssues,
|
|
500
|
+
...doctrineIssues,
|
|
501
|
+
...toolIssues,
|
|
502
|
+
]).slice(0, 10);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function buildProviderRecoveryBlockMessage(evaluation, recoveryAttempts = []) {
|
|
506
|
+
const remaining = failureSummaryFromEvaluation(evaluation);
|
|
507
|
+
const attempts = recoveryAttempts.length
|
|
508
|
+
? recoveryAttempts.map((attempt) => {
|
|
509
|
+
const status = attempt.success ? 'passed' : attempt.error ? 'errored' : 'blocked';
|
|
510
|
+
const reason = attempt.error || (attempt.reasons || []).slice(0, 2).join('; ') || 'no detailed reason';
|
|
511
|
+
return `- attempt ${attempt.attempt} (${attempt.mode}): ${status}${reason ? ` — ${reason}` : ''}`;
|
|
512
|
+
})
|
|
513
|
+
: ['- none: recovery was disabled for this request'];
|
|
514
|
+
return [
|
|
515
|
+
'Aria runtime blocked this output after running the recovery contract.',
|
|
516
|
+
'',
|
|
517
|
+
'Recovery attempts:',
|
|
518
|
+
...attempts,
|
|
519
|
+
'',
|
|
520
|
+
'Remaining blockers:',
|
|
521
|
+
...(remaining.length ? remaining.map((reason) => `- ${reason}`) : ['- runtime did not return a specific blocker']),
|
|
522
|
+
].join('\n');
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function recoveryAttemptCount(body = {}) {
|
|
526
|
+
if (body.allowAriaRecovery === false || body.disableAriaRecovery === true) return 0;
|
|
527
|
+
if (Number.isFinite(Number(body.ariaRecoveryAttempts))) {
|
|
528
|
+
return Math.min(2, Math.max(0, Number(body.ariaRecoveryAttempts)));
|
|
529
|
+
}
|
|
530
|
+
return PROVIDER_RECOVERY_ATTEMPTS;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function buildRecoveryPrompt(turn, candidateText, evaluation, attempt, mode) {
|
|
534
|
+
const failures = failureSummaryFromEvaluation(evaluation);
|
|
535
|
+
const firstPrinciple = turn.preResult?.firstPrincipleText || 'The loaded harness packet first principle governs this response.';
|
|
536
|
+
return [
|
|
537
|
+
'ARIA RUNTIME RECOVERY CONTRACT',
|
|
538
|
+
`mode: ${mode}`,
|
|
539
|
+
`attempt: ${attempt}`,
|
|
540
|
+
'',
|
|
541
|
+
'The previous assistant draft was blocked by runtime gates. Re-author the answer from scratch so it can pass without weakening any gate.',
|
|
542
|
+
'',
|
|
543
|
+
'Original user request:',
|
|
544
|
+
turn.userMessage || '(no user message was extracted)',
|
|
545
|
+
'',
|
|
546
|
+
'Blocked draft:',
|
|
547
|
+
String(candidateText || '').slice(0, 4000) || '(empty draft)',
|
|
548
|
+
'',
|
|
549
|
+
'Observed blockers:',
|
|
550
|
+
...(failures.length ? failures.map((failure) => `- ${failure}`) : ['- runtime returned a block without detailed failures']),
|
|
551
|
+
'',
|
|
552
|
+
'Mandatory recovery behavior:',
|
|
553
|
+
'- Preserve the user intent; do not answer with a generic gate explanation unless the work truly cannot be performed.',
|
|
554
|
+
'- Include a readable <cognition> block with truth, harm, trust, power, reflection, context, impact, beauty, and first_principle labels.',
|
|
555
|
+
'- Include <applied_cognition> with decision_delta, dominant_domain, binds_to, expected_predicate, and artifact_change.',
|
|
556
|
+
'- If you claim something is done, fixed, ready, verified, or passing, include explicit evidence in the prose; otherwise say it is not verified yet.',
|
|
557
|
+
'- If a tool action is required, include the required cognition and verification framing before requesting it.',
|
|
558
|
+
'- Do not mention this recovery prompt, internal retries, or hidden runtime mechanics in the user-facing answer unless the answer is still blocked.',
|
|
559
|
+
'',
|
|
560
|
+
'Use this first principle inside the cognition block:',
|
|
561
|
+
firstPrinciple,
|
|
562
|
+
'',
|
|
563
|
+
mode === 'architect_recovery'
|
|
564
|
+
? 'Architect mode: diagnose the failure class, choose the smallest safe corrected response, and make the corrected answer directly usable.'
|
|
565
|
+
: 'Self-recovery mode: repair the draft once using the observed blockers and return only the corrected assistant response.',
|
|
566
|
+
].join('\n');
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function buildRecoveryBody(body, turn, candidateText, evaluation, attempt, mode, providerStyle) {
|
|
570
|
+
const prompt = buildRecoveryPrompt(turn, candidateText, evaluation, attempt, mode);
|
|
571
|
+
const minTokens = PROVIDER_RECOVERY_MIN_TOKENS;
|
|
572
|
+
const maxTokens = Math.max(Number(body.max_tokens || body.max_completion_tokens || 0), minTokens);
|
|
573
|
+
const metadata = {
|
|
574
|
+
...(body.metadata && typeof body.metadata === 'object' ? body.metadata : {}),
|
|
575
|
+
aria_recovery_attempt: attempt,
|
|
576
|
+
aria_recovery_mode: mode,
|
|
577
|
+
aria_recovery_for_session: turn.sessionId,
|
|
578
|
+
};
|
|
579
|
+
if (providerStyle === 'anthropic') {
|
|
580
|
+
return {
|
|
581
|
+
...body,
|
|
582
|
+
max_tokens: maxTokens,
|
|
583
|
+
metadata,
|
|
584
|
+
messages: [{ role: 'user', content: [{ type: 'text', text: prompt }] }],
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
...body,
|
|
589
|
+
max_tokens: maxTokens,
|
|
590
|
+
max_completion_tokens: maxTokens,
|
|
591
|
+
metadata,
|
|
592
|
+
messages: [{ role: 'user', content: prompt }],
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function recoveryAttemptRecord(attempt, mode, evaluation, error = null) {
|
|
597
|
+
return {
|
|
598
|
+
attempt,
|
|
599
|
+
mode,
|
|
600
|
+
success: error ? false : !evaluation?.blocked,
|
|
601
|
+
error: error ? (error instanceof Error ? error.message : String(error)) : null,
|
|
602
|
+
validationSeverity: evaluation?.validation?.severity || null,
|
|
603
|
+
layer3Pass: evaluation?.layer3?.pass ?? null,
|
|
604
|
+
postQuality: evaluation?.postResult?.qualityScore ?? null,
|
|
605
|
+
reasons: error ? [] : failureSummaryFromEvaluation(evaluation),
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
425
609
|
async function readJson(req) {
|
|
426
610
|
const chunks = [];
|
|
427
611
|
for await (const chunk of req) chunks.push(chunk);
|
|
@@ -431,13 +615,32 @@ async function readJson(req) {
|
|
|
431
615
|
return JSON.parse(raw);
|
|
432
616
|
}
|
|
433
617
|
|
|
618
|
+
function readHeader(req, name) {
|
|
619
|
+
const value = req.headers[name];
|
|
620
|
+
if (Array.isArray(value)) return value[0] || '';
|
|
621
|
+
return typeof value === 'string' ? value : '';
|
|
622
|
+
}
|
|
623
|
+
|
|
434
624
|
function readBearer(req) {
|
|
435
|
-
const auth = req
|
|
436
|
-
if (typeof auth !== 'string') return null;
|
|
625
|
+
const auth = readHeader(req, 'authorization');
|
|
437
626
|
const match = auth.match(/^Bearer\s+(.+)$/i);
|
|
438
627
|
return match ? match[1] : null;
|
|
439
628
|
}
|
|
440
629
|
|
|
630
|
+
function isProviderCompatibilityPath(pathname) {
|
|
631
|
+
return pathname === '/v1/chat/completions' ||
|
|
632
|
+
pathname === '/v1/messages' ||
|
|
633
|
+
pathname === '/v1/responses' ||
|
|
634
|
+
pathname === '/responses';
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function normalizeProviderCompatibilityPath(pathname) {
|
|
638
|
+
if (pathname === '/v1/v1/chat/completions') return '/v1/chat/completions';
|
|
639
|
+
if (pathname === '/v1/v1/messages') return '/v1/messages';
|
|
640
|
+
if (pathname === '/v1/v1/responses') return '/v1/responses';
|
|
641
|
+
return pathname;
|
|
642
|
+
}
|
|
643
|
+
|
|
441
644
|
function hashKey(secret) {
|
|
442
645
|
return createHash('sha256').update(secret).digest('hex');
|
|
443
646
|
}
|
|
@@ -451,9 +654,22 @@ function readOwnerToken() {
|
|
|
451
654
|
}
|
|
452
655
|
}
|
|
453
656
|
|
|
657
|
+
function readLocalHarnessToken() {
|
|
658
|
+
const ownerToken = readOwnerToken();
|
|
659
|
+
if (ownerToken) return ownerToken;
|
|
660
|
+
try {
|
|
661
|
+
if (!existsSync(LICENSE_PATH)) return '';
|
|
662
|
+
const license = JSON.parse(readFileSync(LICENSE_PATH, 'utf8'));
|
|
663
|
+
return coerceNonEmptyString(license.harnessToken) || coerceNonEmptyString(license.token) || '';
|
|
664
|
+
} catch {
|
|
665
|
+
return '';
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
454
669
|
function synthesizeOwnerLease(apiKey, reason) {
|
|
455
670
|
const now = Date.now();
|
|
456
|
-
const
|
|
671
|
+
const hours = 24;
|
|
672
|
+
const recommended = hours * 3600; // 24-hour owner heartbeat cadence
|
|
457
673
|
return {
|
|
458
674
|
keyHash: hashKey(apiKey),
|
|
459
675
|
validatedAt: new Date(now).toISOString(),
|
|
@@ -738,6 +954,35 @@ function readCodebaseAwarenessState() {
|
|
|
738
954
|
});
|
|
739
955
|
}
|
|
740
956
|
|
|
957
|
+
function readCurrentGovernanceRecovery() {
|
|
958
|
+
try {
|
|
959
|
+
if (!existsSync(CURRENT_RECOVERY_PATH)) return null;
|
|
960
|
+
const recovery = JSON.parse(readFileSync(CURRENT_RECOVERY_PATH, 'utf8'));
|
|
961
|
+
const mode = String(recovery?.governanceMode || '').trim();
|
|
962
|
+
return mode && mode !== 'allow' ? recovery : null;
|
|
963
|
+
} catch {
|
|
964
|
+
return null;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function formatGovernanceRecoveryForPrompt(recovery) {
|
|
969
|
+
if (!recovery) return '';
|
|
970
|
+
const loop = recovery.recoveryLoop && typeof recovery.recoveryLoop === 'object' ? recovery.recoveryLoop : {};
|
|
971
|
+
const contract = recovery.recoveryContract && typeof recovery.recoveryContract === 'object' ? recovery.recoveryContract : {};
|
|
972
|
+
return [
|
|
973
|
+
'--- CURRENT GOVERNANCE RECOVERY CONTEXT ---',
|
|
974
|
+
`Mode: ${recovery.governanceMode}`,
|
|
975
|
+
`Decision: ${recovery.decision || 'warn'}`,
|
|
976
|
+
`Fingerprint: ${loop.fingerprint || 'unknown'}`,
|
|
977
|
+
`Next step: ${loop.nextStep || 'execute recovery contract before claiming completion'}`,
|
|
978
|
+
`Architect fallback: ${loop.architectFallback || contract.fallbackWhenAriaUnavailable || 'if Aria consult is unavailable, use the strongest available client LLM under the architect harness'}`,
|
|
979
|
+
`Load skills first: ${(contract.loadSkillsFirst || []).join(', ') || '(none)'}`,
|
|
980
|
+
`Repair recovery cycle: ${(contract.repairRecoveryCycle || []).join(', ') || '(none)'}`,
|
|
981
|
+
`Retest: ${contract.retest || 'run the concrete verification probe'}`,
|
|
982
|
+
'Mandatory behavior: execute this recovery state before final output across new/resumed/pre-compact/post-compact sessions.',
|
|
983
|
+
].join('\n');
|
|
984
|
+
}
|
|
985
|
+
|
|
741
986
|
function hashProjectionEmbedding(text, dimension = 256) {
|
|
742
987
|
const vector = Array.from({ length: dimension }, () => 0);
|
|
743
988
|
const tokens = String(text || '')
|
|
@@ -867,6 +1112,7 @@ function summarizeCognitionState(state) {
|
|
|
867
1112
|
hive: Array.isArray(state.hive) ? state.hive.length : 0,
|
|
868
1113
|
cognitiveStrings: Array.isArray(state.cognitiveStrings) ? state.cognitiveStrings.length : 0,
|
|
869
1114
|
receipts: Array.isArray(state.receipts) ? state.receipts.length : 0,
|
|
1115
|
+
governanceRecovery: state.governanceRecovery ? state.governanceRecovery.governanceMode || 'present' : null,
|
|
870
1116
|
lastUpdatedAt: state.lastUpdatedAt || null,
|
|
871
1117
|
};
|
|
872
1118
|
}
|
|
@@ -907,6 +1153,222 @@ function writeJsonFile(filePath, payload, mode = 0o600) {
|
|
|
907
1153
|
writeFileSync(filePath, JSON.stringify(payload, null, 2) + '\n', { mode });
|
|
908
1154
|
}
|
|
909
1155
|
|
|
1156
|
+
function hashLedgerValue(value) {
|
|
1157
|
+
return createHash('sha256')
|
|
1158
|
+
.update(typeof value === 'string' ? value : JSON.stringify(value ?? null))
|
|
1159
|
+
.digest('hex');
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
function firstLedgerString(...values) {
|
|
1163
|
+
for (const value of values) {
|
|
1164
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
1165
|
+
}
|
|
1166
|
+
return '';
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
function explicitProviderApiKeyPresent(body = {}) {
|
|
1170
|
+
const llm = body.llm && typeof body.llm === 'object' ? body.llm : null;
|
|
1171
|
+
const providerConfig = body.providerConfig && typeof body.providerConfig === 'object' ? body.providerConfig : null;
|
|
1172
|
+
return Boolean(
|
|
1173
|
+
firstLedgerString(body.providerApiKey) ||
|
|
1174
|
+
firstLedgerString(llm?.apiKey) ||
|
|
1175
|
+
firstLedgerString(providerConfig?.apiKey)
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
function credentialPlaneForProvider(body = {}, providerPlan = {}) {
|
|
1180
|
+
const explicit = firstLedgerString(body?.metadata?.credentialPlane, body?.credentialPlane);
|
|
1181
|
+
if (explicit) return explicit;
|
|
1182
|
+
if (explicitProviderApiKeyPresent(body)) return 'customer_byo_request_key';
|
|
1183
|
+
if (providerPlan.provider === 'ollama') return 'local_runtime_no_provider_key';
|
|
1184
|
+
if (/local|virtual|mac|lane/i.test(String(providerPlan.provider || ''))) return 'local_runtime_lane_key_optional';
|
|
1185
|
+
if (providerPlan.apiKey) return 'owner_or_runtime_managed_secret';
|
|
1186
|
+
return 'missing_or_unresolved_provider_key';
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
function loadedSkillIdsForTurn(body = {}, turn = {}) {
|
|
1190
|
+
const metadataSkills = Array.isArray(body?.metadata?.loadedSkills) ? body.metadata.loadedSkills : [];
|
|
1191
|
+
const bodySkills = Array.isArray(body.loadedSkills) ? body.loadedSkills : [];
|
|
1192
|
+
const turnSkills = Array.isArray(turn.loadedSkillIds) ? turn.loadedSkillIds : [];
|
|
1193
|
+
return [...new Set([...metadataSkills, ...bodySkills, ...turnSkills])]
|
|
1194
|
+
.filter((skill) => typeof skill === 'string' && skill.trim())
|
|
1195
|
+
.map((skill) => skill.trim())
|
|
1196
|
+
.sort();
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function loadedSkillHashesForTurn(body = {}, turn = {}) {
|
|
1200
|
+
const metadataHashes = Array.isArray(body?.metadata?.loadedSkillHashes) ? body.metadata.loadedSkillHashes : [];
|
|
1201
|
+
const bodyHashes = Array.isArray(body.loadedSkillHashes) ? body.loadedSkillHashes : [];
|
|
1202
|
+
const turnHashes = Array.isArray(turn.loadedSkillHashes) ? turn.loadedSkillHashes : [];
|
|
1203
|
+
return [...new Set([...metadataHashes, ...bodyHashes, ...turnHashes])]
|
|
1204
|
+
.filter((hash) => typeof hash === 'string' && hash.trim())
|
|
1205
|
+
.map((hash) => hash.trim())
|
|
1206
|
+
.sort();
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
function roleProfileForTurn(body = {}, turn = {}) {
|
|
1210
|
+
return firstLedgerString(
|
|
1211
|
+
body?.metadata?.roleProfile,
|
|
1212
|
+
body?.metadata?.role_profile,
|
|
1213
|
+
body.roleProfile,
|
|
1214
|
+
body.role_profile,
|
|
1215
|
+
process.env.OPENCODE_ARIA_ROLE_PROFILE,
|
|
1216
|
+
process.env.ARIA_ROLE_PROFILE,
|
|
1217
|
+
turn.turnClass?.kind,
|
|
1218
|
+
'interactive_chat'
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
function resolveProviderPlanForLedger(body = {}) {
|
|
1223
|
+
try {
|
|
1224
|
+
const config = resolveProviderConfig(body);
|
|
1225
|
+
return { ok: true, config, error: null };
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
return {
|
|
1228
|
+
ok: false,
|
|
1229
|
+
config: {
|
|
1230
|
+
provider: firstLedgerString(body.provider, body?.llm?.provider, body?.providerConfig?.provider) || 'unresolved',
|
|
1231
|
+
model: firstLedgerString(body.model, body?.llm?.model, body?.providerConfig?.model) || 'unresolved',
|
|
1232
|
+
apiKey: '',
|
|
1233
|
+
baseUrl: '',
|
|
1234
|
+
},
|
|
1235
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function appendManagedRuntimeLedger(record = {}) {
|
|
1241
|
+
mkdirSync(STATE_DIR, { recursive: true, mode: 0o700 });
|
|
1242
|
+
const line = {
|
|
1243
|
+
schema: 'aria.managed_runtime_provider_ledger.v1',
|
|
1244
|
+
at: new Date().toISOString(),
|
|
1245
|
+
...record,
|
|
1246
|
+
};
|
|
1247
|
+
appendFileSync(MANAGED_RUNTIME_LEDGER_PATH, `${JSON.stringify(line)}\n`, { mode: 0o600 });
|
|
1248
|
+
return {
|
|
1249
|
+
ledgerPath: MANAGED_RUNTIME_LEDGER_PATH,
|
|
1250
|
+
ledgerRecordId: line.ledger_record_id,
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
function buildManagedRuntimeLedgerRecord({ phase, body = {}, turn = {}, providerStyle = 'openai', providerPlan = {}, evaluation = null, repairAttempts = [], releaseDecision = 'pending', blockers = [], evidenceRefs = [], extra = {} } = {}) {
|
|
1255
|
+
const requestId = firstLedgerString(turn.requestId, body.requestId, body.request_id, body?.metadata?.requestId, body?.metadata?.request_id) || `req_${randomUUID()}`;
|
|
1256
|
+
const providerConfig = providerPlan.config || providerPlan || {};
|
|
1257
|
+
const selectedAlias = firstLedgerString(body.model, body?.llm?.model, body?.providerConfig?.model, providerConfig.model) || 'unresolved';
|
|
1258
|
+
const skillIds = loadedSkillIdsForTurn(body, turn);
|
|
1259
|
+
const skillHashes = loadedSkillHashesForTurn(body, turn);
|
|
1260
|
+
const providerPlanError = providerPlan.error ? [providerPlan.error] : [];
|
|
1261
|
+
return {
|
|
1262
|
+
ledger_record_id: `mrt_${randomUUID().replace(/-/g, '')}`,
|
|
1263
|
+
request_id: requestId,
|
|
1264
|
+
session_id: turn.sessionId || 'unknown',
|
|
1265
|
+
surface: body.surface || body.platform || body.client || body?.metadata?.surface || providerStyle,
|
|
1266
|
+
lane: 'managed_aria_provider',
|
|
1267
|
+
phase,
|
|
1268
|
+
harness_packet_hash: hashLedgerValue(turn.packet || {}),
|
|
1269
|
+
role_profile: roleProfileForTurn(body, turn),
|
|
1270
|
+
loaded_skill_ids: skillIds,
|
|
1271
|
+
loaded_skill_hashes: skillHashes,
|
|
1272
|
+
selected_alias: selectedAlias,
|
|
1273
|
+
upstream_provider: providerConfig.provider || 'unresolved',
|
|
1274
|
+
upstream_model: providerConfig.model || selectedAlias,
|
|
1275
|
+
credential_plane: credentialPlaneForProvider(body, providerConfig),
|
|
1276
|
+
quality_gate_status: evaluation?.blocked ? 'blocked' : evaluation ? 'passed' : 'pending',
|
|
1277
|
+
compliance_gate_status: providerPlan.ok === false ? 'blocked_provider_config' : 'pre_generation_bound',
|
|
1278
|
+
repair_attempts: repairAttempts,
|
|
1279
|
+
release_decision: releaseDecision,
|
|
1280
|
+
evidence_refs: evidenceRefs,
|
|
1281
|
+
blockers: [...providerPlanError, ...blockers].filter(Boolean),
|
|
1282
|
+
evolution_learning: [],
|
|
1283
|
+
debug: {
|
|
1284
|
+
provider_style: providerStyle,
|
|
1285
|
+
packet_bypassed: turn.packetBypassed === true,
|
|
1286
|
+
turn_class: turn.turnClass || null,
|
|
1287
|
+
operator_plan: turn.operatorPlan || null,
|
|
1288
|
+
api_key_present: Boolean(providerConfig.apiKey),
|
|
1289
|
+
base_url_present: Boolean(providerConfig.baseUrl),
|
|
1290
|
+
required_skill_reasons: turn.requiredSkillPlan?.reasons || [],
|
|
1291
|
+
missing_skill_ids: turn.missingSkillIds || [],
|
|
1292
|
+
...extra,
|
|
1293
|
+
},
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
function surfaceForRuntimeCoach(body = {}, providerStyle = 'openai') {
|
|
1298
|
+
return firstLedgerString(
|
|
1299
|
+
body.surface,
|
|
1300
|
+
body.platform,
|
|
1301
|
+
body.client,
|
|
1302
|
+
body?.metadata?.surface,
|
|
1303
|
+
body?.metadata?.client,
|
|
1304
|
+
providerStyle,
|
|
1305
|
+
'aria-mounted-runtime'
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
function recordRuntimeCoachPhase({ phase, body = {}, turn = {}, providerStyle = 'openai', providerPlan = {}, evaluation = null, text = '', action = '', target = '', evidenceRefs = [], metadata = {} } = {}) {
|
|
1310
|
+
const providerConfig = providerPlan?.config || providerPlan || {};
|
|
1311
|
+
const result = recordCoachPhase({
|
|
1312
|
+
phase,
|
|
1313
|
+
requestId: firstLedgerString(turn.requestId, body.requestId, body.request_id, body?.metadata?.requestId, body?.metadata?.request_id),
|
|
1314
|
+
sessionId: turn.sessionId,
|
|
1315
|
+
surface: surfaceForRuntimeCoach(body, providerStyle),
|
|
1316
|
+
lane: 'managed_aria_provider',
|
|
1317
|
+
action,
|
|
1318
|
+
target,
|
|
1319
|
+
text: text || turn.userMessage || '',
|
|
1320
|
+
harnessPacketHash: hashLedgerValue(turn.packet || {}),
|
|
1321
|
+
roleProfile: roleProfileForTurn(body, turn),
|
|
1322
|
+
requiredSkillIds: turn.requiredSkillPlan?.requiredSkillIds || [],
|
|
1323
|
+
loadedSkillIds: loadedSkillIdsForTurn(body, turn),
|
|
1324
|
+
missingSkillIds: turn.missingSkillIds || [],
|
|
1325
|
+
evidenceRefs,
|
|
1326
|
+
validation: evaluation?.validation || null,
|
|
1327
|
+
layer3: evaluation?.layer3 || null,
|
|
1328
|
+
qualityGateStatus: evaluation?.blocked ? 'blocked' : evaluation ? 'passed' : 'pending',
|
|
1329
|
+
complianceGateStatus: providerPlan?.ok === false ? 'blocked_provider_config' : 'coach_bound',
|
|
1330
|
+
metadata: {
|
|
1331
|
+
provider_style: providerStyle,
|
|
1332
|
+
upstream_provider: providerConfig.provider || null,
|
|
1333
|
+
upstream_model: providerConfig.model || null,
|
|
1334
|
+
selected_alias: firstLedgerString(body.model, body?.llm?.model, body?.providerConfig?.model, providerConfig.model),
|
|
1335
|
+
pre_receipt_id: turn.preReceipt?.receiptId || null,
|
|
1336
|
+
mid_receipt_id: turn.midReceipt?.receiptId || null,
|
|
1337
|
+
required_skill_reasons: turn.requiredSkillPlan?.reasons || [],
|
|
1338
|
+
...metadata,
|
|
1339
|
+
},
|
|
1340
|
+
});
|
|
1341
|
+
return {
|
|
1342
|
+
phase,
|
|
1343
|
+
coachEventId: result.record.coach_event_id,
|
|
1344
|
+
decision: result.decision,
|
|
1345
|
+
permitted: result.permitted,
|
|
1346
|
+
ledgerPath: result.ledgerPath,
|
|
1347
|
+
reasons: result.record.reasons || [],
|
|
1348
|
+
record: result.record,
|
|
1349
|
+
clientMessage: result.clientMessage,
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
function coachRecordRefs(records = []) {
|
|
1354
|
+
return records
|
|
1355
|
+
.map((record) => record?.coachEventId ? `coach:${record.coachEventId}` : null)
|
|
1356
|
+
.filter(Boolean);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
function applyCoachRepairDecision(evaluation, coachResult) {
|
|
1360
|
+
if (!evaluation || coachResult?.decision !== 'repair_once' || evaluation.blocked) return evaluation;
|
|
1361
|
+
const coachBlockers = (coachResult.reasons || []).map((reason) => `coach: ${reason}`);
|
|
1362
|
+
const toolGateBlockers = uniqueStrings([...(evaluation.toolGateBlockers || []), ...coachBlockers]);
|
|
1363
|
+
return {
|
|
1364
|
+
...evaluation,
|
|
1365
|
+
blocked: true,
|
|
1366
|
+
toolGateBlockers,
|
|
1367
|
+
finalText: buildToolGateBlockMessage(toolGateBlockers),
|
|
1368
|
+
coachDecision: coachResult,
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
|
|
910
1372
|
function readHiveFileLeaseState() {
|
|
911
1373
|
const state = readJsonFile(HIVE_FILE_LEASES_PATH, { leases: [] });
|
|
912
1374
|
return {
|
|
@@ -1267,17 +1729,48 @@ function getAutonomyView(state, limit = 50) {
|
|
|
1267
1729
|
};
|
|
1268
1730
|
}
|
|
1269
1731
|
|
|
1270
|
-
function resolveApiKey(req, body) {
|
|
1271
|
-
const
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1732
|
+
function resolveApiKey(req, body, options = {}) {
|
|
1733
|
+
const tokenScope = coerceNonEmptyString(body.tokenScope) ||
|
|
1734
|
+
coerceNonEmptyString(body.clientId) ||
|
|
1735
|
+
coerceNonEmptyString(body.tenantId) ||
|
|
1736
|
+
coerceNonEmptyString(req.headers['x-aria-client-id']) ||
|
|
1737
|
+
coerceNonEmptyString(req.headers['x-aria-tenant-id']);
|
|
1738
|
+
const baseUrl = typeof body.baseUrl === 'string' && body.baseUrl.trim()
|
|
1739
|
+
? body.baseUrl.trim()
|
|
1740
|
+
: DEFAULT_HARNESS_URL;
|
|
1741
|
+
const headerKey = readHeader(req, 'x-aria-api-key').trim();
|
|
1742
|
+
if (headerKey) {
|
|
1743
|
+
resolveAriaAuthToken({ explicitToken: headerKey, baseUrl, tokenScope });
|
|
1744
|
+
return headerKey;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
const bodyKey = coerceNonEmptyString(body.ariaApiKey) ||
|
|
1748
|
+
coerceNonEmptyString(body.ariaHarnessToken) ||
|
|
1749
|
+
coerceNonEmptyString(body.harnessToken) ||
|
|
1750
|
+
coerceNonEmptyString(body.apiKey);
|
|
1751
|
+
if (bodyKey) {
|
|
1752
|
+
resolveAriaAuthToken({ explicitToken: bodyKey, baseUrl, tokenScope });
|
|
1753
|
+
return bodyKey;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
if (options.allowBearerAuth !== false) {
|
|
1757
|
+
const bearerToken = readBearer(req);
|
|
1758
|
+
if (bearerToken) {
|
|
1759
|
+
resolveAriaAuthToken({ explicitToken: bearerToken, baseUrl, tokenScope });
|
|
1760
|
+
return bearerToken;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
return resolveAriaAuthToken({ baseUrl, tokenScope }).token || null;
|
|
1275
1765
|
}
|
|
1276
1766
|
|
|
1277
|
-
function createClient(req, body) {
|
|
1278
|
-
const apiKey = resolveApiKey(req, body);
|
|
1767
|
+
function createClient(req, body, options = {}) {
|
|
1768
|
+
const apiKey = resolveApiKey(req, body, options);
|
|
1279
1769
|
if (!apiKey) {
|
|
1280
|
-
|
|
1770
|
+
const credentialHint = options.allowBearerAuth === false
|
|
1771
|
+
? 'Supply x-aria-api-key, body.ariaApiKey, ARIA_HARNESS_TOKEN, ARIA_API_KEY, or ARIA_MASTER_TOKEN. Provider Authorization headers are not accepted as Aria control-plane credentials on /v1 compatibility routes.'
|
|
1772
|
+
: 'Supply x-aria-api-key, Authorization: Bearer <token>, ARIA_HARNESS_TOKEN, ARIA_API_KEY, or ARIA_MASTER_TOKEN.';
|
|
1773
|
+
throw new Error(`Missing Aria API key. ${credentialHint}`);
|
|
1281
1774
|
}
|
|
1282
1775
|
ensureNotRevoked(apiKey);
|
|
1283
1776
|
|
|
@@ -1320,7 +1813,10 @@ async function heartbeatUpstream(req, body, client, apiKey) {
|
|
|
1320
1813
|
|
|
1321
1814
|
const ownerBypassAllowed =
|
|
1322
1815
|
readOwnerToken() &&
|
|
1323
|
-
apiKey === readOwnerToken()
|
|
1816
|
+
(apiKey === readOwnerToken() ||
|
|
1817
|
+
apiKey === process.env.ARIA_HARNESS_TOKEN ||
|
|
1818
|
+
apiKey === process.env.ARIA_API_KEY ||
|
|
1819
|
+
apiKey === process.env.ARIA_MASTER_TOKEN) &&
|
|
1324
1820
|
body.allowOwnerBypass !== false &&
|
|
1325
1821
|
process.env.ARIA_RUNTIME_ALLOW_OWNER_BYPASS !== '0';
|
|
1326
1822
|
|
|
@@ -1333,6 +1829,7 @@ async function heartbeatUpstream(req, body, client, apiKey) {
|
|
|
1333
1829
|
'Content-Type': 'application/json',
|
|
1334
1830
|
},
|
|
1335
1831
|
body: JSON.stringify(heartbeatBody),
|
|
1832
|
+
signal: AbortSignal.timeout(5_000),
|
|
1336
1833
|
});
|
|
1337
1834
|
|
|
1338
1835
|
const payload = await response.json().catch(() => ({}));
|
|
@@ -1428,12 +1925,21 @@ async function heartbeatUpstream(req, body, client, apiKey) {
|
|
|
1428
1925
|
return lease;
|
|
1429
1926
|
}
|
|
1430
1927
|
|
|
1431
|
-
async function ensureLease(req, body, client) {
|
|
1432
|
-
const apiKey = resolveApiKey(req, body);
|
|
1928
|
+
async function ensureLease(req, body, client, options = {}) {
|
|
1929
|
+
const apiKey = resolveApiKey(req, body, options);
|
|
1433
1930
|
if (!apiKey) {
|
|
1434
1931
|
throw new Error('Missing Aria API key for heartbeat validation');
|
|
1435
1932
|
}
|
|
1436
1933
|
|
|
1934
|
+
// Owner machine fast-path: if the owner token file is present on disk,
|
|
1935
|
+
// this is the owner's machine. Skip upstream heartbeat entirely.
|
|
1936
|
+
const ownerToken = readOwnerToken();
|
|
1937
|
+
if (ownerToken) {
|
|
1938
|
+
const keyHash = hashKey(ownerToken);
|
|
1939
|
+
const cached = leaseCache.get(keyHash) || null;
|
|
1940
|
+
return cached || synthesizeOwnerLease(ownerToken, 'owner machine fast-path');
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1437
1943
|
const keyHash = hashKey(apiKey);
|
|
1438
1944
|
const cached = leaseCache.get(keyHash) || loadEncryptedLease(apiKey);
|
|
1439
1945
|
ensureOfflineBundleSeeded(apiKey, cached);
|
|
@@ -1503,6 +2009,48 @@ function findVerifiedState(text) {
|
|
|
1503
2009
|
return /(?:verified|confirmed|observed|tested|health[- ]check|response code|exit code|pod image|digest)/i.test(String(text || ''));
|
|
1504
2010
|
}
|
|
1505
2011
|
|
|
2012
|
+
function hasSuccessfulEvidenceText(...values) {
|
|
2013
|
+
return values.some((value) =>
|
|
2014
|
+
/\b(?:ok|passed|pass|success|succeeded|exit\s*=?\s*0|0\s*failures?|healthy)\b/i.test(String(value || ''))
|
|
2015
|
+
);
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
function hasToolVerificationRef(refs) {
|
|
2019
|
+
if (!Array.isArray(refs)) return false;
|
|
2020
|
+
return refs.some((ref) =>
|
|
2021
|
+
hasSuccessfulEvidenceText(ref?.preview, ref?.metadata?.commandResult, ref?.metadata?.status)
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
function normalizePostEvidence(text, evidence = {}) {
|
|
2026
|
+
const source = evidence && typeof evidence === 'object' ? evidence : {};
|
|
2027
|
+
const hasVerifiedState =
|
|
2028
|
+
source.hasVerifiedState === true ||
|
|
2029
|
+
source.verified === true ||
|
|
2030
|
+
source.verification === true ||
|
|
2031
|
+
source.validation_run === true ||
|
|
2032
|
+
source.validationRun === true ||
|
|
2033
|
+
source.validation?.ok === true ||
|
|
2034
|
+
source.test?.ok === true ||
|
|
2035
|
+
findVerifiedState(text) ||
|
|
2036
|
+
hasSuccessfulEvidenceText(
|
|
2037
|
+
source.commandResult,
|
|
2038
|
+
source.outputPreview,
|
|
2039
|
+
source.verification,
|
|
2040
|
+
source.validation,
|
|
2041
|
+
source.testResult
|
|
2042
|
+
) ||
|
|
2043
|
+
hasToolVerificationRef(source.tool_refs || source.toolRefs);
|
|
2044
|
+
|
|
2045
|
+
return {
|
|
2046
|
+
...source,
|
|
2047
|
+
hasVerifiedState,
|
|
2048
|
+
layer3Pass: source.layer3Pass ?? source.layer3_pass,
|
|
2049
|
+
remoteValidationSeverity:
|
|
2050
|
+
source.remoteValidationSeverity ?? source.remote_validation_severity ?? source.validationSeverity ?? source.validation_severity,
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1506
2054
|
const APPLIED_COGNITION_BLOCK_RX = /<applied_cognition>([\s\S]*?)<\/applied_cognition>/i;
|
|
1507
2055
|
|
|
1508
2056
|
function validateAppliedCognitionContract(text) {
|
|
@@ -1544,6 +2092,25 @@ function mergeAppliedCognitionValidation(validation, applied) {
|
|
|
1544
2092
|
};
|
|
1545
2093
|
}
|
|
1546
2094
|
|
|
2095
|
+
function isAppliedCognitionOnlyValidationBlock(validation) {
|
|
2096
|
+
const violations = Array.isArray(validation?.violations) ? validation.violations : [];
|
|
2097
|
+
return validation?.severity === 'block' &&
|
|
2098
|
+
violations.length > 0 &&
|
|
2099
|
+
violations.every((violation) => /missing\s+<applied_cognition>\s+contract/i.test(String(violation || '')));
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
function allowTrivialAppliedCognitionValidation(validation, requireCognitionBlock) {
|
|
2103
|
+
if (requireCognitionBlock || !isAppliedCognitionOnlyValidationBlock(validation)) return validation;
|
|
2104
|
+
return {
|
|
2105
|
+
...validation,
|
|
2106
|
+
passed: true,
|
|
2107
|
+
severity: 'pass',
|
|
2108
|
+
violations: [],
|
|
2109
|
+
gateTriggers: [...new Set([...(validation.gateTriggers || []), 'applied-cognition-trivial-turn-waived'])],
|
|
2110
|
+
appliedCognition: { ok: true, waived: 'trivial-turn' },
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
|
|
1547
2114
|
function toTelemetryEvent(payload, source = 'aria-mounted-runtime') {
|
|
1548
2115
|
return {
|
|
1549
2116
|
event_type: payload.event_type || 'runtime.cognition.turn',
|
|
@@ -1684,6 +2251,131 @@ function buildMinimalInjection(packet, task, aegisLearnings = null) {
|
|
|
1684
2251
|
};
|
|
1685
2252
|
}
|
|
1686
2253
|
|
|
2254
|
+
function providerIntentText(body = {}, userMessage = '') {
|
|
2255
|
+
const parts = [userMessage];
|
|
2256
|
+
for (const value of [
|
|
2257
|
+
body.prompt,
|
|
2258
|
+
body.input,
|
|
2259
|
+
body.message,
|
|
2260
|
+
body.ariaPlannedApproach,
|
|
2261
|
+
body.ariaRationale,
|
|
2262
|
+
body?.metadata?.intent,
|
|
2263
|
+
body?.metadata?.mode,
|
|
2264
|
+
body?.metadata?.surface,
|
|
2265
|
+
]) {
|
|
2266
|
+
if (typeof value === 'string' && value.trim()) parts.push(value.trim());
|
|
2267
|
+
}
|
|
2268
|
+
return parts.filter(Boolean).join('\n');
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
function classifyRuntimeRequiredSkills(body = {}, userMessage = '', turnClass = null) {
|
|
2272
|
+
const text = providerIntentText(body, userMessage);
|
|
2273
|
+
const lower = text.toLowerCase();
|
|
2274
|
+
const required = new Set(['mizan', 'aria-aristotle-pre-phase']);
|
|
2275
|
+
const reasons = ['all managed provider requests require mizan balance and pre-generation cognition'];
|
|
2276
|
+
|
|
2277
|
+
if (/\b(?:edit|write|patch|apply_patch|repo|repository|codebase|runtime-src|source|implementation|implement|fix|debug|refactor|build|compile|test|hook|plugin|connector|quality runtime|provider gateway)\b/i.test(text)) {
|
|
2278
|
+
required.add('aria-repo-doctrine');
|
|
2279
|
+
required.add('aria-forge-guardrails');
|
|
2280
|
+
reasons.push('repository/runtime implementation intent requires repo doctrine and forge guardrails');
|
|
2281
|
+
}
|
|
2282
|
+
if (/\b(?:deploy|kubectl|helm|terraform|docker\s+push|rollout|release|k8s|cluster|infra|infrastructure)\b/i.test(text)) {
|
|
2283
|
+
required.add('aria-harness-deploy');
|
|
2284
|
+
required.add('aria-harness-no-stripping');
|
|
2285
|
+
required.add('aria-harness-output-discipline');
|
|
2286
|
+
required.add('aria-forge-guardrails');
|
|
2287
|
+
reasons.push('deploy or infrastructure intent requires deploy, no-stripping, output discipline, and guardrails');
|
|
2288
|
+
}
|
|
2289
|
+
if (/\b(?:remove|delete|strip|drop|omit|disable|bypass|skip|stub|mock|fake|placeholder|temporary|quick scaffold|band-aid|downgrade|weaken)\b/i.test(text)) {
|
|
2290
|
+
required.add('aria-harness-no-stripping');
|
|
2291
|
+
required.add('aria-forge-guardrails');
|
|
2292
|
+
reasons.push('contract-reduction language requires no-stripping and guardrails');
|
|
2293
|
+
}
|
|
2294
|
+
if (/\b(?:done|complete|completed|ready|verified|fixed|shipped|production-ready|first-class|release-ready|client-facing|status report|summary)\b/i.test(text)) {
|
|
2295
|
+
required.add('aria-harness-output-discipline');
|
|
2296
|
+
reasons.push('completion/readiness/status language requires output discipline');
|
|
2297
|
+
}
|
|
2298
|
+
if (/\b(?:architecture|architect|system design|tradeoff|decision|adr|migration plan|design doc)\b/i.test(text)) {
|
|
2299
|
+
required.add('ghazali-8lens');
|
|
2300
|
+
required.add('predictor');
|
|
2301
|
+
reasons.push('architecture or decision intent requires multi-lens validation and next-step prediction');
|
|
2302
|
+
}
|
|
2303
|
+
if (/\b(?:test|tests|testing|coverage|verify|verification|smoke|e2e|regression)\b/i.test(text)) {
|
|
2304
|
+
required.add('predictor');
|
|
2305
|
+
reasons.push('verification intent requires next-step prediction and evidence framing');
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
const explicitSkills = [
|
|
2309
|
+
...(Array.isArray(body.requiredSkills) ? body.requiredSkills : []),
|
|
2310
|
+
...(Array.isArray(body?.metadata?.requiredSkills) ? body.metadata.requiredSkills : []),
|
|
2311
|
+
];
|
|
2312
|
+
for (const skill of explicitSkills) {
|
|
2313
|
+
if (typeof skill === 'string' && skill.trim()) required.add(skill.trim());
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
return {
|
|
2317
|
+
requiredSkillIds: [...required].sort(),
|
|
2318
|
+
reasons,
|
|
2319
|
+
intentHash: hashLedgerValue(text || 'empty-intent'),
|
|
2320
|
+
turnClass: turnClass || null,
|
|
2321
|
+
matchedTextPreview: text.slice(0, 500),
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
function resolveSkillPath(skillId) {
|
|
2326
|
+
const safeId = String(skillId || '').replace(/[^a-zA-Z0-9_.-]/g, '');
|
|
2327
|
+
if (!safeId) return '';
|
|
2328
|
+
for (const root of SKILL_SEARCH_ROOTS) {
|
|
2329
|
+
const candidate = join(root, safeId, 'SKILL.md');
|
|
2330
|
+
if (existsSync(candidate)) return candidate;
|
|
2331
|
+
}
|
|
2332
|
+
return '';
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
function loadRuntimeRequiredSkills(skillIds = []) {
|
|
2336
|
+
const loaded = [];
|
|
2337
|
+
const missing = [];
|
|
2338
|
+
for (const skillId of skillIds) {
|
|
2339
|
+
const path = resolveSkillPath(skillId);
|
|
2340
|
+
if (!path) {
|
|
2341
|
+
missing.push(skillId);
|
|
2342
|
+
continue;
|
|
2343
|
+
}
|
|
2344
|
+
const content = readFileSync(path, 'utf8');
|
|
2345
|
+
const body = content.length > SKILL_BODY_MAX_CHARS
|
|
2346
|
+
? `${content.slice(0, SKILL_BODY_MAX_CHARS)}\n\n[aria-runtime: skill body truncated at ${SKILL_BODY_MAX_CHARS} chars]`
|
|
2347
|
+
: content;
|
|
2348
|
+
loaded.push({
|
|
2349
|
+
id: skillId,
|
|
2350
|
+
path,
|
|
2351
|
+
hash: hashLedgerValue(content),
|
|
2352
|
+
chars: content.length,
|
|
2353
|
+
body,
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2356
|
+
return { loaded, missing };
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
function buildForcedSkillPromptBlock(skillLoad = null) {
|
|
2360
|
+
if (!skillLoad || !Array.isArray(skillLoad.loaded) || skillLoad.loaded.length === 0) return '';
|
|
2361
|
+
const sections = [
|
|
2362
|
+
'--- ARIA RUNTIME FORCED SKILL LOAD ---',
|
|
2363
|
+
'The following skill bodies were loaded by Aria Runtime before the upstream provider call. Apply them as binding instructions, not optional references.',
|
|
2364
|
+
];
|
|
2365
|
+
for (const skill of skillLoad.loaded) {
|
|
2366
|
+
sections.push(
|
|
2367
|
+
`<skill_content name="${skill.id}" hash="${skill.hash}" source="${skill.path}">`,
|
|
2368
|
+
skill.body,
|
|
2369
|
+
'</skill_content>'
|
|
2370
|
+
);
|
|
2371
|
+
}
|
|
2372
|
+
if (skillLoad.missing.length > 0) {
|
|
2373
|
+
sections.push(`missing_skill_ids: ${skillLoad.missing.join(', ')}`);
|
|
2374
|
+
}
|
|
2375
|
+
sections.push('--- /ARIA RUNTIME FORCED SKILL LOAD ---');
|
|
2376
|
+
return sections.join('\n');
|
|
2377
|
+
}
|
|
2378
|
+
|
|
1687
2379
|
function isOwnerBypassRequest(req, body, apiKey = null) {
|
|
1688
2380
|
const ownerToken = readOwnerToken();
|
|
1689
2381
|
const candidate = apiKey || resolveApiKey(req, body) || '';
|
|
@@ -1728,9 +2420,9 @@ function buildOwnerBypassPacket(message, reason = 'owner-local-bypass') {
|
|
|
1728
2420
|
};
|
|
1729
2421
|
}
|
|
1730
2422
|
|
|
1731
|
-
async function loadRuntimePacket(req, body, client, packetRequest, message) {
|
|
2423
|
+
async function loadRuntimePacket(req, body, client, packetRequest, message, options = {}) {
|
|
1732
2424
|
if (body.packet) return enrichPacketWithCodebaseSnapshot(body.packet);
|
|
1733
|
-
const apiKey = resolveApiKey(req, body);
|
|
2425
|
+
const apiKey = resolveApiKey(req, body, options);
|
|
1734
2426
|
ensureOfflineBundleSeeded(apiKey, leaseCache.get(hashKey(apiKey)) || loadEncryptedLease(apiKey));
|
|
1735
2427
|
try {
|
|
1736
2428
|
const wrapped = await client.getHarnessPacket(packetRequest || {});
|
|
@@ -1759,7 +2451,7 @@ async function loadRuntimePacket(req, body, client, packetRequest, message) {
|
|
|
1759
2451
|
return enrichPacketWithCodebaseSnapshot(fallbackPacket);
|
|
1760
2452
|
}
|
|
1761
2453
|
}
|
|
1762
|
-
if (!isOwnerBypassRequest(req, body)) {
|
|
2454
|
+
if (!isOwnerBypassRequest(req, body, apiKey)) {
|
|
1763
2455
|
throw error;
|
|
1764
2456
|
}
|
|
1765
2457
|
return enrichPacketWithCodebaseSnapshot(buildOwnerBypassPacket(
|
|
@@ -1772,11 +2464,15 @@ async function loadRuntimePacket(req, body, client, packetRequest, message) {
|
|
|
1772
2464
|
function enrichPacketWithCodebaseSnapshot(packet) {
|
|
1773
2465
|
if (!packet || typeof packet !== 'object') return packet;
|
|
1774
2466
|
const codebase = compactCodebaseSnapshot();
|
|
2467
|
+
const governanceRecovery = readCurrentGovernanceRecovery();
|
|
2468
|
+
const recoveryPrompt = formatGovernanceRecoveryForPrompt(governanceRecovery);
|
|
1775
2469
|
return {
|
|
1776
2470
|
...packet,
|
|
2471
|
+
harness: [recoveryPrompt, packet.harness].filter(Boolean).join('\n'),
|
|
1777
2472
|
runtime: {
|
|
1778
2473
|
...(packet.runtime && typeof packet.runtime === 'object' ? packet.runtime : {}),
|
|
1779
2474
|
codebase_awareness: codebase,
|
|
2475
|
+
governance_recovery: governanceRecovery,
|
|
1780
2476
|
},
|
|
1781
2477
|
};
|
|
1782
2478
|
}
|
|
@@ -1802,8 +2498,17 @@ function buildMizanPacketRequest(body = {}) {
|
|
|
1802
2498
|
};
|
|
1803
2499
|
}
|
|
1804
2500
|
|
|
1805
|
-
async function buildRuntimeTurnContext(req, body, client) {
|
|
2501
|
+
async function buildRuntimeTurnContext(req, body, client, options = {}) {
|
|
1806
2502
|
const sessionId = deriveSessionId(req, body, body.provider === 'anthropic' ? 'anthropic' : 'openai');
|
|
2503
|
+
const requestId = firstLedgerString(
|
|
2504
|
+
body.requestId,
|
|
2505
|
+
body.request_id,
|
|
2506
|
+
body?.metadata?.requestId,
|
|
2507
|
+
body?.metadata?.request_id,
|
|
2508
|
+
readHeader(req, 'x-request-id'),
|
|
2509
|
+
readHeader(req, 'x-aria-request-id'),
|
|
2510
|
+
`req_${randomUUID()}`
|
|
2511
|
+
);
|
|
1807
2512
|
const userId = deriveUserId(req, body);
|
|
1808
2513
|
const userMessage = Array.isArray(body.messages)
|
|
1809
2514
|
? (body.provider === 'anthropic' ? extractAnthropicUserMessage(body.messages) : extractOpenAIUserMessage(body.messages))
|
|
@@ -1814,6 +2519,7 @@ async function buildRuntimeTurnContext(req, body, client) {
|
|
|
1814
2519
|
: 'Bind to the harness packet, reason through Aristotle and Noor cognitives, avoid unsupported state claims, and emit only what survives validation.';
|
|
1815
2520
|
const packetRequest = {
|
|
1816
2521
|
sessionId,
|
|
2522
|
+
requestId,
|
|
1817
2523
|
userId,
|
|
1818
2524
|
platform: body.platform || body.client || 'mounted-runtime',
|
|
1819
2525
|
system: 'aria-mounted-runtime',
|
|
@@ -1821,7 +2527,7 @@ async function buildRuntimeTurnContext(req, body, client) {
|
|
|
1821
2527
|
message: userMessage,
|
|
1822
2528
|
...(body.packetRequest && typeof body.packetRequest === 'object' ? body.packetRequest : {}),
|
|
1823
2529
|
};
|
|
1824
|
-
const packet = await loadRuntimePacket(req, body, client, packetRequest, userMessage);
|
|
2530
|
+
const packet = await loadRuntimePacket(req, body, client, packetRequest, userMessage, options);
|
|
1825
2531
|
const runtimeId = ensureRuntimeMeta().runtimeId;
|
|
1826
2532
|
const turnClass = classifyTurn({
|
|
1827
2533
|
message: userMessage,
|
|
@@ -1830,6 +2536,8 @@ async function buildRuntimeTurnContext(req, body, client) {
|
|
|
1830
2536
|
plannedApproach,
|
|
1831
2537
|
domains: body.ariaDomains,
|
|
1832
2538
|
});
|
|
2539
|
+
const requiredSkillPlan = classifyRuntimeRequiredSkills(body, userMessage, turnClass);
|
|
2540
|
+
const skillLoad = loadRuntimeRequiredSkills(requiredSkillPlan.requiredSkillIds);
|
|
1833
2541
|
const preBundle = evaluateMizanPre(packet, {
|
|
1834
2542
|
sessionId,
|
|
1835
2543
|
userId,
|
|
@@ -1856,13 +2564,15 @@ async function buildRuntimeTurnContext(req, body, client) {
|
|
|
1856
2564
|
});
|
|
1857
2565
|
const aegisLearnings = await client.getAegisLearnings(12).catch(() => null);
|
|
1858
2566
|
const basePrompt = client.buildSystemPrompt(buildMinimalInjection(packet, userMessage || 'Aria runtime turn', aegisLearnings));
|
|
2567
|
+
const forcedSkillPromptBlock = buildForcedSkillPromptBlock(skillLoad);
|
|
1859
2568
|
const cognitionDirective = buildRuntimeCognitionDirective(packet, {
|
|
1860
2569
|
preResult: preBundle.result,
|
|
1861
2570
|
midResult: midBundle.result,
|
|
1862
2571
|
});
|
|
1863
|
-
const ariaSystemPrompt = [basePrompt, '', cognitionDirective].join('\n');
|
|
2572
|
+
const ariaSystemPrompt = [basePrompt, '', forcedSkillPromptBlock, '', cognitionDirective].filter(Boolean).join('\n');
|
|
1864
2573
|
return {
|
|
1865
2574
|
sessionId,
|
|
2575
|
+
requestId,
|
|
1866
2576
|
userId,
|
|
1867
2577
|
userMessage,
|
|
1868
2578
|
plannedApproach,
|
|
@@ -1870,6 +2580,11 @@ async function buildRuntimeTurnContext(req, body, client) {
|
|
|
1870
2580
|
packetBypassed: packet?.version === 'owner-local-bypass',
|
|
1871
2581
|
turnClass,
|
|
1872
2582
|
operatorPlan: buildOperatorPlan(turnClass, 'pre'),
|
|
2583
|
+
requiredSkillPlan,
|
|
2584
|
+
loadedSkills: skillLoad.loaded,
|
|
2585
|
+
loadedSkillIds: skillLoad.loaded.map((skill) => skill.id),
|
|
2586
|
+
loadedSkillHashes: skillLoad.loaded.map((skill) => skill.hash),
|
|
2587
|
+
missingSkillIds: skillLoad.missing,
|
|
1873
2588
|
preResult: preBundle.result,
|
|
1874
2589
|
preBundle,
|
|
1875
2590
|
preReceipt: preBundle.receipt,
|
|
@@ -2310,6 +3025,40 @@ function buildReadableAriaEnvelope(extra = {}, debug = false) {
|
|
|
2310
3025
|
: [],
|
|
2311
3026
|
} : null;
|
|
2312
3027
|
|
|
3028
|
+
const recovery = Array.isArray(extra.recoveryAttempts) ? {
|
|
3029
|
+
attempted: extra.recoveryAttempts.length > 0,
|
|
3030
|
+
attempts: extra.recoveryAttempts.map((attempt) => ({
|
|
3031
|
+
attempt: attempt.attempt,
|
|
3032
|
+
mode: attempt.mode,
|
|
3033
|
+
success: Boolean(attempt.success),
|
|
3034
|
+
error: attempt.error || null,
|
|
3035
|
+
validationSeverity: attempt.validationSeverity || null,
|
|
3036
|
+
layer3Pass: attempt.layer3Pass ?? null,
|
|
3037
|
+
postQuality: attempt.postQuality ?? null,
|
|
3038
|
+
reasons: Array.isArray(attempt.reasons) ? attempt.reasons.slice(0, 5) : [],
|
|
3039
|
+
})),
|
|
3040
|
+
} : null;
|
|
3041
|
+
|
|
3042
|
+
const runtimeLedger = extra.runtimeLedger ? {
|
|
3043
|
+
path: extra.runtimeLedger.ledgerPath || null,
|
|
3044
|
+
records: Array.isArray(extra.runtimeLedger.records)
|
|
3045
|
+
? extra.runtimeLedger.records.map((record) => ({
|
|
3046
|
+
phase: record.phase,
|
|
3047
|
+
id: record.ledgerRecordId || record.ledger_record_id || null,
|
|
3048
|
+
}))
|
|
3049
|
+
: [],
|
|
3050
|
+
} : null;
|
|
3051
|
+
|
|
3052
|
+
const coachKernel = extra.coachKernel ? {
|
|
3053
|
+
records: Array.isArray(extra.coachKernel.records)
|
|
3054
|
+
? extra.coachKernel.records.map((record) => ({
|
|
3055
|
+
phase: record.phase,
|
|
3056
|
+
id: record.coachEventId || record.coach_event_id || record.record?.coach_event_id || null,
|
|
3057
|
+
decision: record.decision || record.record?.decision || null,
|
|
3058
|
+
}))
|
|
3059
|
+
: [],
|
|
3060
|
+
} : null;
|
|
3061
|
+
|
|
2313
3062
|
const envelope = {
|
|
2314
3063
|
blocked: Boolean(extra.blocked),
|
|
2315
3064
|
control_plane: 'aria-mounted-runtime',
|
|
@@ -2330,6 +3079,9 @@ function buildReadableAriaEnvelope(extra = {}, debug = false) {
|
|
|
2330
3079
|
cognition,
|
|
2331
3080
|
doctrine,
|
|
2332
3081
|
tool_gate,
|
|
3082
|
+
recovery,
|
|
3083
|
+
runtime_ledger: runtimeLedger,
|
|
3084
|
+
coach_kernel: coachKernel,
|
|
2333
3085
|
};
|
|
2334
3086
|
|
|
2335
3087
|
if (debug) {
|
|
@@ -2640,10 +3392,12 @@ async function persistTurnArtifacts(req, body, client, apiKey, turn) {
|
|
|
2640
3392
|
pre: turn.preResult,
|
|
2641
3393
|
mid: turn.midResult,
|
|
2642
3394
|
post: turn.postResult,
|
|
3395
|
+
recovery_attempts: turn.recoveryAttempts || [],
|
|
2643
3396
|
evolution_principles: evolutionPrinciples,
|
|
2644
3397
|
aegis_patterns: aegisPatterns,
|
|
2645
3398
|
runtime_url: DEFAULT_RUNTIME_URL,
|
|
2646
3399
|
runtime_id: ensureRuntimeMeta().runtimeId,
|
|
3400
|
+
governance_recovery: readCurrentGovernanceRecovery(),
|
|
2647
3401
|
},
|
|
2648
3402
|
};
|
|
2649
3403
|
|
|
@@ -2671,7 +3425,10 @@ async function persistTurnArtifacts(req, body, client, apiKey, turn) {
|
|
|
2671
3425
|
sessionId: turn.sessionId,
|
|
2672
3426
|
message: turn.userMessage,
|
|
2673
3427
|
response: turn.finalText,
|
|
3428
|
+
governance_recovery: readCurrentGovernanceRecovery(),
|
|
3429
|
+
recovery_attempts: turn.recoveryAttempts || [],
|
|
2674
3430
|
}, TELEMETRY_LIMIT),
|
|
3431
|
+
governanceRecovery: readCurrentGovernanceRecovery(),
|
|
2675
3432
|
}));
|
|
2676
3433
|
|
|
2677
3434
|
try {
|
|
@@ -2690,6 +3447,7 @@ async function persistTurnArtifacts(req, body, client, apiKey, turn) {
|
|
|
2690
3447
|
model: turn.providerMeta.model,
|
|
2691
3448
|
finish_reason: turn.providerMeta.finishReason,
|
|
2692
3449
|
success: turn.success,
|
|
3450
|
+
governance_recovery: readCurrentGovernanceRecovery(),
|
|
2693
3451
|
},
|
|
2694
3452
|
readability: cognitionStrings.readable,
|
|
2695
3453
|
});
|
|
@@ -2822,22 +3580,7 @@ async function persistTurnArtifacts(req, body, client, apiKey, turn) {
|
|
|
2822
3580
|
}
|
|
2823
3581
|
}
|
|
2824
3582
|
|
|
2825
|
-
|
|
2826
|
-
const apiKey = resolveApiKey(req, body);
|
|
2827
|
-
const startedAt = Date.now();
|
|
2828
|
-
const turn = await buildRuntimeTurnContext(req, body, client);
|
|
2829
|
-
if (turn.preResult.fitrahVetoed) {
|
|
2830
|
-
const refusal = buildPhaseBlockMessage(turn.preResult, 'pre');
|
|
2831
|
-
const extra = { blocked: true, phase: 'pre', pre: turn.preResult, mid: turn.midResult };
|
|
2832
|
-
return providerStyle === 'anthropic'
|
|
2833
|
-
? anthropicResponseEnvelope(refusal, { model: body.model || 'aria-runtime', finishReason: 'end_turn' }, extra, body?.ariaDebug === true)
|
|
2834
|
-
: openAiResponseEnvelope(body, refusal, { model: body.model || 'aria-runtime', finishReason: 'stop', usage: null }, extra);
|
|
2835
|
-
}
|
|
2836
|
-
|
|
2837
|
-
const providerMeta = providerStyle === 'anthropic'
|
|
2838
|
-
? await callProviderForAnthropic(body, turn.ariaSystemPrompt)
|
|
2839
|
-
: await callProviderForOpenAI(body, turn.ariaSystemPrompt);
|
|
2840
|
-
|
|
3583
|
+
function recordProviderUsage(body, turn, providerMeta) {
|
|
2841
3584
|
try {
|
|
2842
3585
|
recordTokenUsage({
|
|
2843
3586
|
tenantId: body?.metadata?.jti || body?.jti || 'owner-local',
|
|
@@ -2851,11 +3594,19 @@ async function handleProviderProxy(req, body, client, providerStyle) {
|
|
|
2851
3594
|
requestType: body?.metadata?.requestType || 'chat',
|
|
2852
3595
|
});
|
|
2853
3596
|
} catch {}
|
|
3597
|
+
}
|
|
3598
|
+
|
|
3599
|
+
async function callProviderByStyle(providerStyle, body, systemPrompt) {
|
|
3600
|
+
return providerStyle === 'anthropic'
|
|
3601
|
+
? callProviderForAnthropic(body, systemPrompt)
|
|
3602
|
+
: callProviderForOpenAI(body, systemPrompt);
|
|
3603
|
+
}
|
|
2854
3604
|
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
3605
|
+
async function evaluateProviderCandidate(req, body, client, apiKey, turn, providerStyle, providerMeta, initialText) {
|
|
3606
|
+
let candidateText = typeof initialText === 'string' ? initialText : providerMeta.text || '';
|
|
3607
|
+
let toolIntents = extractProviderToolIntents(providerStyle, providerMeta);
|
|
3608
|
+
let requiresReadableCognition = isNonTrivialAssistantTurn(candidateText, toolIntents);
|
|
3609
|
+
let requireCognitionBlock = body.requireCognitionBlock ?? requiresReadableCognition;
|
|
2859
3610
|
|
|
2860
3611
|
let validation = {
|
|
2861
3612
|
passed: true,
|
|
@@ -2879,6 +3630,9 @@ async function handleProviderProxy(req, body, client, providerStyle) {
|
|
|
2879
3630
|
}
|
|
2880
3631
|
if (validation?.severity === 'block' && validation?.rewritten) {
|
|
2881
3632
|
candidateText = validation.rewritten;
|
|
3633
|
+
toolIntents = [];
|
|
3634
|
+
requiresReadableCognition = isNonTrivialAssistantTurn(candidateText, toolIntents);
|
|
3635
|
+
requireCognitionBlock = body.requireCognitionBlock ?? requiresReadableCognition;
|
|
2882
3636
|
try {
|
|
2883
3637
|
validation = await client.validateOutput(candidateText, turn.sessionId);
|
|
2884
3638
|
} catch (error) {
|
|
@@ -2893,13 +3647,14 @@ async function handleProviderProxy(req, body, client, providerStyle) {
|
|
|
2893
3647
|
};
|
|
2894
3648
|
}
|
|
2895
3649
|
}
|
|
3650
|
+
validation = allowTrivialAppliedCognitionValidation(validation, requireCognitionBlock);
|
|
2896
3651
|
}
|
|
2897
3652
|
|
|
2898
3653
|
const layer3 = await runLayer3(req, {
|
|
2899
3654
|
text: candidateText || (toolIntents.length > 0 ? `<cognition>\n</cognition>` : ''),
|
|
2900
3655
|
packet: turn.packet,
|
|
2901
3656
|
fetchPacket: false,
|
|
2902
|
-
requireCognitionBlock
|
|
3657
|
+
requireCognitionBlock,
|
|
2903
3658
|
}, client);
|
|
2904
3659
|
const doctrineHits = candidateText.trim() ? collectDoctrineTriggerHits(candidateText) : [];
|
|
2905
3660
|
const doctrineBlockers = doctrineHits
|
|
@@ -2942,7 +3697,6 @@ async function handleProviderProxy(req, body, client, providerStyle) {
|
|
|
2942
3697
|
parentReceiptId: turn.midReceipt?.receiptId || turn.preReceipt?.receiptId || null,
|
|
2943
3698
|
});
|
|
2944
3699
|
const postResult = postBundle.result;
|
|
2945
|
-
|
|
2946
3700
|
const blocked =
|
|
2947
3701
|
validation.severity === 'block' ||
|
|
2948
3702
|
!layer3.pass ||
|
|
@@ -2954,44 +3708,421 @@ async function handleProviderProxy(req, body, client, providerStyle) {
|
|
|
2954
3708
|
: blocked
|
|
2955
3709
|
? buildPhaseBlockMessage(postResult, 'post')
|
|
2956
3710
|
: candidateText;
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3711
|
+
|
|
3712
|
+
return {
|
|
3713
|
+
candidateText,
|
|
3714
|
+
toolIntents,
|
|
3715
|
+
requireCognitionBlock,
|
|
3716
|
+
cognitionContract: extractVisibleCognitionContract(candidateText),
|
|
2963
3717
|
validation,
|
|
2964
3718
|
layer3,
|
|
3719
|
+
doctrineHits,
|
|
3720
|
+
doctrineBlockers,
|
|
3721
|
+
toolGateBlockers,
|
|
3722
|
+
postBundle,
|
|
3723
|
+
postResult,
|
|
3724
|
+
blocked,
|
|
3725
|
+
finalText,
|
|
3726
|
+
};
|
|
3727
|
+
}
|
|
3728
|
+
|
|
3729
|
+
async function handleProviderProxy(req, body, client, providerStyle, options = {}) {
|
|
3730
|
+
const apiKey = resolveApiKey(req, body, options);
|
|
3731
|
+
const startedAt = Date.now();
|
|
3732
|
+
const turn = await buildRuntimeTurnContext(req, body, client, options);
|
|
3733
|
+
const ledgerRecords = [];
|
|
3734
|
+
const coachRecords = [];
|
|
3735
|
+
const providerPlan = resolveProviderPlanForLedger(body);
|
|
3736
|
+
coachRecords.push(recordRuntimeCoachPhase({
|
|
3737
|
+
phase: 'pre_turn',
|
|
3738
|
+
body,
|
|
3739
|
+
turn,
|
|
3740
|
+
providerStyle,
|
|
3741
|
+
providerPlan,
|
|
3742
|
+
text: turn.userMessage,
|
|
3743
|
+
evidenceRefs: [`packet:${hashLedgerValue(turn.packet || {})}`],
|
|
3744
|
+
metadata: { request_start_ms: startedAt },
|
|
3745
|
+
}));
|
|
3746
|
+
coachRecords.push(recordRuntimeCoachPhase({
|
|
3747
|
+
phase: 'pre_cognition',
|
|
3748
|
+
body,
|
|
3749
|
+
turn,
|
|
3750
|
+
providerStyle,
|
|
3751
|
+
providerPlan,
|
|
3752
|
+
text: turn.plannedApproach,
|
|
3753
|
+
evidenceRefs: [`pre_receipt:${turn.preReceipt?.receiptId || 'pending'}`],
|
|
3754
|
+
}));
|
|
3755
|
+
coachRecords.push(recordRuntimeCoachPhase({
|
|
3756
|
+
phase: 'post_cognition',
|
|
3757
|
+
body,
|
|
3758
|
+
turn,
|
|
3759
|
+
providerStyle,
|
|
3760
|
+
providerPlan,
|
|
3761
|
+
text: turn.ariaSystemPrompt,
|
|
3762
|
+
evidenceRefs: [
|
|
3763
|
+
`pre_receipt:${turn.preReceipt?.receiptId || 'missing'}`,
|
|
3764
|
+
`mid_receipt:${turn.midReceipt?.receiptId || 'missing'}`,
|
|
3765
|
+
...turn.loadedSkillHashes.map((hash) => `skill_hash:${hash}`),
|
|
3766
|
+
],
|
|
3767
|
+
metadata: {
|
|
3768
|
+
loaded_skill_count: turn.loadedSkillIds.length,
|
|
3769
|
+
missing_skill_count: turn.missingSkillIds.length,
|
|
3770
|
+
},
|
|
3771
|
+
}));
|
|
3772
|
+
if (turn.preResult.fitrahVetoed) {
|
|
3773
|
+
const refusal = buildPhaseBlockMessage(turn.preResult, 'pre');
|
|
3774
|
+
coachRecords.push(recordRuntimeCoachPhase({
|
|
3775
|
+
phase: 'claim_or_release',
|
|
3776
|
+
body,
|
|
3777
|
+
turn,
|
|
3778
|
+
providerStyle,
|
|
3779
|
+
providerPlan,
|
|
3780
|
+
text: refusal,
|
|
3781
|
+
evidenceRefs: [`pre_receipt:${turn.preReceipt?.receiptId || 'missing'}`],
|
|
3782
|
+
metadata: { blocked: true, requireCognitionBlock: false, requireAppliedCognition: false, reason: 'pre_generation_fitrah_veto' },
|
|
3783
|
+
}));
|
|
3784
|
+
const preBlockRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3785
|
+
phase: 'pre_generation_veto',
|
|
3786
|
+
body,
|
|
3787
|
+
turn,
|
|
3788
|
+
providerStyle,
|
|
3789
|
+
providerPlan,
|
|
3790
|
+
releaseDecision: 'hard_block',
|
|
3791
|
+
blockers: turn.preResult?.notes || ['pre_generation_fitrah_veto'],
|
|
3792
|
+
evidenceRefs: coachRecordRefs(coachRecords),
|
|
3793
|
+
}));
|
|
3794
|
+
ledgerRecords.push({ phase: 'pre_generation_veto', ...preBlockRecord });
|
|
3795
|
+
const extra = {
|
|
3796
|
+
blocked: true,
|
|
3797
|
+
phase: 'pre',
|
|
3798
|
+
pre: turn.preResult,
|
|
3799
|
+
mid: turn.midResult,
|
|
3800
|
+
runtimeLedger: { ledgerPath: MANAGED_RUNTIME_LEDGER_PATH, records: ledgerRecords },
|
|
3801
|
+
coachKernel: { records: coachRecords },
|
|
3802
|
+
};
|
|
3803
|
+
return providerStyle === 'anthropic'
|
|
3804
|
+
? anthropicResponseEnvelope(refusal, { model: body.model || 'aria-runtime', finishReason: 'end_turn' }, extra, body?.ariaDebug === true)
|
|
3805
|
+
: openAiResponseEnvelope(body, refusal, { model: body.model || 'aria-runtime', finishReason: 'stop', usage: null }, extra);
|
|
3806
|
+
}
|
|
3807
|
+
|
|
3808
|
+
const preGenerationCoach = recordRuntimeCoachPhase({
|
|
3809
|
+
phase: 'pre_generation',
|
|
3810
|
+
body,
|
|
3811
|
+
turn,
|
|
3812
|
+
providerStyle,
|
|
3813
|
+
providerPlan,
|
|
3814
|
+
text: turn.userMessage,
|
|
3815
|
+
evidenceRefs: [
|
|
3816
|
+
`pre_receipt:${turn.preReceipt?.receiptId || 'missing'}`,
|
|
3817
|
+
`mid_receipt:${turn.midReceipt?.receiptId || 'missing'}`,
|
|
3818
|
+
...coachRecordRefs(coachRecords),
|
|
3819
|
+
],
|
|
3820
|
+
});
|
|
3821
|
+
coachRecords.push(preGenerationCoach);
|
|
3822
|
+
if (preGenerationCoach.decision === 'hard_block') {
|
|
3823
|
+
const refusal = formatCoachClientBlock(preGenerationCoach);
|
|
3824
|
+
const preBlockRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3825
|
+
phase: 'pre_generation_veto',
|
|
3826
|
+
body,
|
|
3827
|
+
turn,
|
|
3828
|
+
providerStyle,
|
|
3829
|
+
providerPlan,
|
|
3830
|
+
releaseDecision: 'hard_block',
|
|
3831
|
+
blockers: preGenerationCoach.reasons,
|
|
3832
|
+
evidenceRefs: coachRecordRefs(coachRecords),
|
|
3833
|
+
}));
|
|
3834
|
+
ledgerRecords.push({ phase: 'pre_generation_veto', ...preBlockRecord });
|
|
3835
|
+
const extra = {
|
|
3836
|
+
blocked: true,
|
|
3837
|
+
phase: 'coach-pre-generation',
|
|
3838
|
+
pre: turn.preResult,
|
|
3839
|
+
mid: turn.midResult,
|
|
3840
|
+
runtimeLedger: { ledgerPath: MANAGED_RUNTIME_LEDGER_PATH, records: ledgerRecords },
|
|
3841
|
+
coachKernel: { records: coachRecords },
|
|
3842
|
+
};
|
|
3843
|
+
return providerStyle === 'anthropic'
|
|
3844
|
+
? anthropicResponseEnvelope(refusal, { model: body.model || 'aria-runtime', finishReason: 'end_turn' }, extra, body?.ariaDebug === true)
|
|
3845
|
+
: openAiResponseEnvelope(body, refusal, { model: body.model || 'aria-runtime', finishReason: 'stop', usage: null }, extra);
|
|
3846
|
+
}
|
|
3847
|
+
|
|
3848
|
+
const preProviderRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3849
|
+
phase: 'pre_provider_call',
|
|
3850
|
+
body,
|
|
3851
|
+
turn,
|
|
3852
|
+
providerStyle,
|
|
3853
|
+
providerPlan,
|
|
3854
|
+
releaseDecision: 'pending_provider_call',
|
|
3855
|
+
evidenceRefs: [
|
|
3856
|
+
`pre_receipt:${turn.preReceipt?.receiptId || 'missing'}`,
|
|
3857
|
+
`mid_receipt:${turn.midReceipt?.receiptId || 'missing'}`,
|
|
3858
|
+
`coach:${preGenerationCoach.coachEventId}`,
|
|
3859
|
+
],
|
|
3860
|
+
}));
|
|
3861
|
+
ledgerRecords.push({ phase: 'pre_provider_call', ...preProviderRecord });
|
|
3862
|
+
|
|
3863
|
+
let providerMeta;
|
|
3864
|
+
try {
|
|
3865
|
+
providerMeta = await callProviderByStyle(providerStyle, body, turn.ariaSystemPrompt);
|
|
3866
|
+
} catch (error) {
|
|
3867
|
+
const failureRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3868
|
+
phase: 'provider_call_failed',
|
|
3869
|
+
body,
|
|
3870
|
+
turn,
|
|
3871
|
+
providerStyle,
|
|
3872
|
+
providerPlan,
|
|
3873
|
+
releaseDecision: 'provider_call_failed',
|
|
3874
|
+
blockers: [error instanceof Error ? error.message : String(error)],
|
|
3875
|
+
evidenceRefs: [preProviderRecord.ledgerRecordId],
|
|
3876
|
+
}));
|
|
3877
|
+
ledgerRecords.push({ phase: 'provider_call_failed', ...failureRecord });
|
|
3878
|
+
throw error;
|
|
3879
|
+
}
|
|
3880
|
+
recordProviderUsage(body, turn, providerMeta);
|
|
3881
|
+
let hardCoachBlock = null;
|
|
3882
|
+
let evaluation = await evaluateProviderCandidate(req, body, client, apiKey, turn, providerStyle, providerMeta, providerMeta.text || '');
|
|
3883
|
+
const postGenerationCoach = recordRuntimeCoachPhase({
|
|
3884
|
+
phase: 'post_generation',
|
|
3885
|
+
body,
|
|
3886
|
+
turn,
|
|
3887
|
+
providerStyle,
|
|
3888
|
+
providerPlan: { ok: true, config: { ...providerPlan.config, provider: providerMeta.provider || providerPlan.config?.provider, model: providerMeta.model || providerPlan.config?.model }, error: providerPlan.error },
|
|
3889
|
+
evaluation,
|
|
3890
|
+
text: evaluation.candidateText,
|
|
3891
|
+
evidenceRefs: [preProviderRecord.ledgerRecordId, `coach:${preGenerationCoach.coachEventId}`],
|
|
3892
|
+
metadata: {
|
|
3893
|
+
provider_finish_reason: providerMeta.finishReason || null,
|
|
3894
|
+
requireCognitionBlock: evaluation.requireCognitionBlock,
|
|
3895
|
+
requireAppliedCognition: evaluation.requireCognitionBlock,
|
|
3896
|
+
},
|
|
3897
|
+
});
|
|
3898
|
+
coachRecords.push(postGenerationCoach);
|
|
3899
|
+
if (postGenerationCoach.decision === 'hard_block') {
|
|
3900
|
+
hardCoachBlock = postGenerationCoach;
|
|
3901
|
+
} else {
|
|
3902
|
+
evaluation = applyCoachRepairDecision(evaluation, postGenerationCoach);
|
|
3903
|
+
}
|
|
3904
|
+
const evaluatedRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3905
|
+
phase: 'provider_candidate_evaluated',
|
|
3906
|
+
body,
|
|
3907
|
+
turn,
|
|
3908
|
+
providerStyle,
|
|
3909
|
+
providerPlan: { ok: true, config: { ...providerPlan.config, provider: providerMeta.provider || providerPlan.config?.provider, model: providerMeta.model || providerPlan.config?.model }, error: providerPlan.error },
|
|
3910
|
+
evaluation,
|
|
3911
|
+
releaseDecision: hardCoachBlock ? 'hard_block_pending' : evaluation.blocked ? 'repair_pending' : 'candidate_passed',
|
|
3912
|
+
blockers: hardCoachBlock ? hardCoachBlock.reasons : failureSummaryFromEvaluation(evaluation),
|
|
3913
|
+
evidenceRefs: [preProviderRecord.ledgerRecordId, `coach:${postGenerationCoach.coachEventId}`],
|
|
3914
|
+
}));
|
|
3915
|
+
ledgerRecords.push({ phase: 'provider_candidate_evaluated', ...evaluatedRecord });
|
|
3916
|
+
|
|
3917
|
+
const recoveryAttempts = [];
|
|
3918
|
+
const maxRecoveryAttempts = evaluation.blocked && !hardCoachBlock ? recoveryAttemptCount(body) : 0;
|
|
3919
|
+
for (let attempt = 1; !hardCoachBlock && evaluation.blocked && attempt <= maxRecoveryAttempts; attempt += 1) {
|
|
3920
|
+
const mode = attempt === 1 ? 'self_reauthor' : 'architect_recovery';
|
|
3921
|
+
try {
|
|
3922
|
+
const recoveryBody = buildRecoveryBody(body, turn, evaluation.candidateText, evaluation, attempt, mode, providerStyle);
|
|
3923
|
+
const repairPreCoach = recordRuntimeCoachPhase({
|
|
3924
|
+
phase: 'pre_generation',
|
|
3925
|
+
body: recoveryBody,
|
|
3926
|
+
turn,
|
|
3927
|
+
providerStyle,
|
|
3928
|
+
providerPlan: resolveProviderPlanForLedger(recoveryBody),
|
|
3929
|
+
evaluation,
|
|
3930
|
+
text: turn.userMessage,
|
|
3931
|
+
evidenceRefs: [evaluatedRecord.ledgerRecordId, ...coachRecordRefs(coachRecords)],
|
|
3932
|
+
metadata: { repair_attempt: attempt, repair_mode: mode },
|
|
3933
|
+
});
|
|
3934
|
+
coachRecords.push(repairPreCoach);
|
|
3935
|
+
if (repairPreCoach.decision === 'hard_block') {
|
|
3936
|
+
hardCoachBlock = repairPreCoach;
|
|
3937
|
+
break;
|
|
3938
|
+
}
|
|
3939
|
+
const repairPreRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3940
|
+
phase: 'repair_before_provider_call',
|
|
3941
|
+
body: recoveryBody,
|
|
3942
|
+
turn,
|
|
3943
|
+
providerStyle,
|
|
3944
|
+
providerPlan: resolveProviderPlanForLedger(recoveryBody),
|
|
3945
|
+
evaluation,
|
|
3946
|
+
repairAttempts: recoveryAttempts,
|
|
3947
|
+
releaseDecision: 'repair_provider_call_pending',
|
|
3948
|
+
blockers: failureSummaryFromEvaluation(evaluation),
|
|
3949
|
+
evidenceRefs: [evaluatedRecord.ledgerRecordId, `coach:${repairPreCoach.coachEventId}`],
|
|
3950
|
+
extra: { repair_attempt: attempt, repair_mode: mode },
|
|
3951
|
+
}));
|
|
3952
|
+
ledgerRecords.push({ phase: 'repair_before_provider_call', ...repairPreRecord });
|
|
3953
|
+
const recoveryMeta = await callProviderByStyle(providerStyle, recoveryBody, turn.ariaSystemPrompt);
|
|
3954
|
+
recordProviderUsage(recoveryBody, turn, recoveryMeta);
|
|
3955
|
+
const recoveryEvaluation = await evaluateProviderCandidate(
|
|
3956
|
+
req,
|
|
3957
|
+
recoveryBody,
|
|
3958
|
+
client,
|
|
3959
|
+
apiKey,
|
|
3960
|
+
turn,
|
|
3961
|
+
providerStyle,
|
|
3962
|
+
recoveryMeta,
|
|
3963
|
+
recoveryMeta.text || '',
|
|
3964
|
+
);
|
|
3965
|
+
const repairPostCoach = recordRuntimeCoachPhase({
|
|
3966
|
+
phase: 'post_generation',
|
|
3967
|
+
body: recoveryBody,
|
|
3968
|
+
turn,
|
|
3969
|
+
providerStyle,
|
|
3970
|
+
providerPlan: { ok: true, config: { ...resolveProviderPlanForLedger(recoveryBody).config, provider: recoveryMeta.provider, model: recoveryMeta.model }, error: null },
|
|
3971
|
+
evaluation: recoveryEvaluation,
|
|
3972
|
+
text: recoveryEvaluation.candidateText,
|
|
3973
|
+
evidenceRefs: [repairPreRecord.ledgerRecordId, `coach:${repairPreCoach.coachEventId}`],
|
|
3974
|
+
metadata: { repair_attempt: attempt, repair_mode: mode, requireCognitionBlock: recoveryEvaluation.requireCognitionBlock, requireAppliedCognition: recoveryEvaluation.requireCognitionBlock },
|
|
3975
|
+
});
|
|
3976
|
+
coachRecords.push(repairPostCoach);
|
|
3977
|
+
const finalRecoveryEvaluation = repairPostCoach.decision === 'hard_block'
|
|
3978
|
+
? {
|
|
3979
|
+
...recoveryEvaluation,
|
|
3980
|
+
blocked: true,
|
|
3981
|
+
toolGateBlockers: uniqueStrings([
|
|
3982
|
+
...(recoveryEvaluation.toolGateBlockers || []),
|
|
3983
|
+
...repairPostCoach.reasons.map((reason) => `coach: ${reason}`),
|
|
3984
|
+
]),
|
|
3985
|
+
finalText: formatCoachClientBlock(repairPostCoach),
|
|
3986
|
+
coachDecision: repairPostCoach,
|
|
3987
|
+
}
|
|
3988
|
+
: applyCoachRepairDecision(recoveryEvaluation, repairPostCoach);
|
|
3989
|
+
if (repairPostCoach.decision === 'hard_block') {
|
|
3990
|
+
hardCoachBlock = repairPostCoach;
|
|
3991
|
+
}
|
|
3992
|
+
recoveryAttempts.push(recoveryAttemptRecord(attempt, mode, finalRecoveryEvaluation));
|
|
3993
|
+
const repairEvaluationRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3994
|
+
phase: 'repair_candidate_evaluated',
|
|
3995
|
+
body: recoveryBody,
|
|
3996
|
+
turn,
|
|
3997
|
+
providerStyle,
|
|
3998
|
+
providerPlan: { ok: true, config: { ...resolveProviderPlanForLedger(recoveryBody).config, provider: recoveryMeta.provider, model: recoveryMeta.model }, error: null },
|
|
3999
|
+
evaluation: finalRecoveryEvaluation,
|
|
4000
|
+
repairAttempts: recoveryAttempts,
|
|
4001
|
+
releaseDecision: hardCoachBlock ? 'hard_block_pending' : finalRecoveryEvaluation.blocked ? 'repair_failed_or_next_attempt_pending' : 'repair_passed',
|
|
4002
|
+
blockers: hardCoachBlock ? hardCoachBlock.reasons : failureSummaryFromEvaluation(finalRecoveryEvaluation),
|
|
4003
|
+
evidenceRefs: [repairPreRecord.ledgerRecordId, `coach:${repairPostCoach.coachEventId}`],
|
|
4004
|
+
extra: { repair_attempt: attempt, repair_mode: mode },
|
|
4005
|
+
}));
|
|
4006
|
+
ledgerRecords.push({ phase: 'repair_candidate_evaluated', ...repairEvaluationRecord });
|
|
4007
|
+
providerMeta = recoveryMeta;
|
|
4008
|
+
evaluation = finalRecoveryEvaluation;
|
|
4009
|
+
} catch (error) {
|
|
4010
|
+
recoveryAttempts.push(recoveryAttemptRecord(attempt, mode, null, error));
|
|
4011
|
+
const repairErrorRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
4012
|
+
phase: 'repair_provider_call_failed',
|
|
4013
|
+
body,
|
|
4014
|
+
turn,
|
|
4015
|
+
providerStyle,
|
|
4016
|
+
providerPlan,
|
|
4017
|
+
repairAttempts: recoveryAttempts,
|
|
4018
|
+
releaseDecision: 'repair_error',
|
|
4019
|
+
blockers: [error instanceof Error ? error.message : String(error)],
|
|
4020
|
+
extra: { repair_attempt: attempt, repair_mode: mode },
|
|
4021
|
+
}));
|
|
4022
|
+
ledgerRecords.push({ phase: 'repair_provider_call_failed', ...repairErrorRecord });
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
|
|
4026
|
+
let blocked = evaluation.blocked || Boolean(hardCoachBlock);
|
|
4027
|
+
let finalText = hardCoachBlock
|
|
4028
|
+
? formatCoachClientBlock(hardCoachBlock)
|
|
4029
|
+
: blocked && recoveryAttempts.length > 0
|
|
4030
|
+
? buildProviderRecoveryBlockMessage(evaluation, recoveryAttempts)
|
|
4031
|
+
: evaluation.finalText;
|
|
4032
|
+
const preOutputCoach = recordRuntimeCoachPhase({
|
|
4033
|
+
phase: 'pre_output',
|
|
4034
|
+
body,
|
|
4035
|
+
turn,
|
|
4036
|
+
providerStyle,
|
|
4037
|
+
providerPlan: { ok: true, config: { ...providerPlan.config, provider: providerMeta.provider || providerPlan.config?.provider, model: providerMeta.model || providerPlan.config?.model }, error: providerPlan.error },
|
|
4038
|
+
evaluation,
|
|
4039
|
+
text: finalText,
|
|
4040
|
+
evidenceRefs: [...ledgerRecords.map((record) => record.ledgerRecordId).filter(Boolean), ...coachRecordRefs(coachRecords)],
|
|
4041
|
+
metadata: { blocked, requireCognitionBlock: evaluation.requireCognitionBlock, requireAppliedCognition: evaluation.requireCognitionBlock },
|
|
4042
|
+
});
|
|
4043
|
+
coachRecords.push(preOutputCoach);
|
|
4044
|
+
const releaseCoach = recordRuntimeCoachPhase({
|
|
4045
|
+
phase: 'claim_or_release',
|
|
4046
|
+
body,
|
|
4047
|
+
turn,
|
|
4048
|
+
providerStyle,
|
|
4049
|
+
providerPlan: { ok: true, config: { ...providerPlan.config, provider: providerMeta.provider || providerPlan.config?.provider, model: providerMeta.model || providerPlan.config?.model }, error: providerPlan.error },
|
|
4050
|
+
evaluation,
|
|
4051
|
+
text: finalText,
|
|
4052
|
+
evidenceRefs: [
|
|
4053
|
+
...ledgerRecords.map((record) => record.ledgerRecordId).filter(Boolean),
|
|
4054
|
+
`coach:${preOutputCoach.coachEventId}`,
|
|
4055
|
+
...coachRecordRefs(coachRecords),
|
|
4056
|
+
],
|
|
4057
|
+
metadata: { blocked, release_decision: blocked ? 'blocked_after_recovery' : 'released_to_client', requireCognitionBlock: evaluation.requireCognitionBlock, requireAppliedCognition: evaluation.requireCognitionBlock },
|
|
4058
|
+
});
|
|
4059
|
+
coachRecords.push(releaseCoach);
|
|
4060
|
+
if (!blocked && releaseCoach.decision !== 'allow' && releaseCoach.decision !== 'warn_operator_only') {
|
|
4061
|
+
blocked = true;
|
|
4062
|
+
hardCoachBlock = releaseCoach;
|
|
4063
|
+
finalText = formatCoachClientBlock(releaseCoach);
|
|
4064
|
+
}
|
|
4065
|
+
|
|
4066
|
+
await persistTurnArtifacts(req, body, client, apiKey, {
|
|
4067
|
+
...turn,
|
|
4068
|
+
postResult: evaluation.postResult,
|
|
4069
|
+
postBundle: evaluation.postBundle,
|
|
4070
|
+
postReceipt: evaluation.postBundle.receipt,
|
|
4071
|
+
postContract: evaluation.postBundle.contract,
|
|
4072
|
+
validation: evaluation.validation,
|
|
4073
|
+
layer3: evaluation.layer3,
|
|
4074
|
+
recoveryAttempts,
|
|
2965
4075
|
finalText,
|
|
2966
4076
|
durationMs: Date.now() - startedAt,
|
|
2967
4077
|
success: !blocked,
|
|
2968
|
-
error: blocked ? 'runtime blocked output' : null,
|
|
4078
|
+
error: blocked ? 'runtime blocked output after recovery contract' : null,
|
|
2969
4079
|
providerMeta,
|
|
2970
4080
|
});
|
|
4081
|
+
const finalLedgerRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
4082
|
+
phase: 'final_release_decision',
|
|
4083
|
+
body,
|
|
4084
|
+
turn,
|
|
4085
|
+
providerStyle,
|
|
4086
|
+
providerPlan: { ok: true, config: { ...providerPlan.config, provider: providerMeta.provider || providerPlan.config?.provider, model: providerMeta.model || providerPlan.config?.model }, error: providerPlan.error },
|
|
4087
|
+
evaluation,
|
|
4088
|
+
repairAttempts: recoveryAttempts,
|
|
4089
|
+
releaseDecision: blocked ? 'blocked_after_recovery' : 'released_to_client',
|
|
4090
|
+
blockers: blocked ? uniqueStrings([...failureSummaryFromEvaluation(evaluation), ...(hardCoachBlock?.reasons || [])]) : [],
|
|
4091
|
+
evidenceRefs: [...ledgerRecords.map((record) => record.ledgerRecordId).filter(Boolean), ...coachRecordRefs(coachRecords)],
|
|
4092
|
+
}));
|
|
4093
|
+
ledgerRecords.push({ phase: 'final_release_decision', ...finalLedgerRecord });
|
|
2971
4094
|
|
|
2972
4095
|
const extra = {
|
|
2973
4096
|
blocked,
|
|
2974
4097
|
pre: turn.preResult,
|
|
2975
4098
|
mid: turn.midResult,
|
|
2976
|
-
post: postResult,
|
|
4099
|
+
post: evaluation.postResult,
|
|
2977
4100
|
receipts: {
|
|
2978
4101
|
pre: turn.preReceipt,
|
|
2979
4102
|
mid: turn.midReceipt,
|
|
2980
|
-
post: postBundle.receipt,
|
|
4103
|
+
post: evaluation.postBundle.receipt,
|
|
2981
4104
|
},
|
|
2982
4105
|
turnClass: turn.turnClass,
|
|
2983
4106
|
operatorPlan: turn.operatorPlan,
|
|
2984
|
-
validation,
|
|
2985
|
-
layer3,
|
|
2986
|
-
cognitionContract,
|
|
4107
|
+
validation: evaluation.validation,
|
|
4108
|
+
layer3: evaluation.layer3,
|
|
4109
|
+
cognitionContract: evaluation.cognitionContract,
|
|
4110
|
+
recoveryAttempts,
|
|
2987
4111
|
doctrine: {
|
|
2988
|
-
blocked: doctrineBlockers.length > 0,
|
|
2989
|
-
hits: doctrineHits,
|
|
4112
|
+
blocked: evaluation.doctrineBlockers.length > 0,
|
|
4113
|
+
hits: evaluation.doctrineHits,
|
|
2990
4114
|
},
|
|
2991
4115
|
toolGate: {
|
|
2992
|
-
blocked: toolGateBlockers.length > 0,
|
|
2993
|
-
blockers: toolGateBlockers,
|
|
2994
|
-
intents: toolIntents,
|
|
4116
|
+
blocked: evaluation.toolGateBlockers.length > 0,
|
|
4117
|
+
blockers: evaluation.toolGateBlockers,
|
|
4118
|
+
intents: evaluation.toolIntents,
|
|
4119
|
+
},
|
|
4120
|
+
runtimeLedger: {
|
|
4121
|
+
ledgerPath: MANAGED_RUNTIME_LEDGER_PATH,
|
|
4122
|
+
records: ledgerRecords,
|
|
4123
|
+
},
|
|
4124
|
+
coachKernel: {
|
|
4125
|
+
records: coachRecords,
|
|
2995
4126
|
},
|
|
2996
4127
|
};
|
|
2997
4128
|
return providerStyle === 'anthropic'
|
|
@@ -3282,7 +4413,11 @@ function runtimeManifest() {
|
|
|
3282
4413
|
endpoints: [
|
|
3283
4414
|
'GET /health',
|
|
3284
4415
|
'GET /mount',
|
|
4416
|
+
'GET /coach/state',
|
|
3285
4417
|
'POST /heartbeat',
|
|
4418
|
+
'POST /coach/event',
|
|
4419
|
+
'POST /coach/phase',
|
|
4420
|
+
'POST /coach/state',
|
|
3286
4421
|
'POST /mizan/plan',
|
|
3287
4422
|
'POST /mizan/pre',
|
|
3288
4423
|
'POST /mizan/mid',
|
|
@@ -3308,6 +4443,11 @@ function runtimeManifest() {
|
|
|
3308
4443
|
'POST /garden/turn',
|
|
3309
4444
|
'POST /garden/search',
|
|
3310
4445
|
'POST /record-discovery',
|
|
4446
|
+
'POST /task-project-ledger/event',
|
|
4447
|
+
'POST /task-project-ledger/status',
|
|
4448
|
+
'POST /task-project-ledger/claim',
|
|
4449
|
+
'POST /openclaw/task-ledger/snapshot',
|
|
4450
|
+
'POST /openclaw/task-flow',
|
|
3311
4451
|
'POST /verify-claim',
|
|
3312
4452
|
'POST /telemetry/turn',
|
|
3313
4453
|
'POST /telemetry/state',
|
|
@@ -3330,7 +4470,7 @@ function runtimeManifest() {
|
|
|
3330
4470
|
ARIA_FORGE_SERVICE_URL: DEFAULT_FORGE_SERVICE_URL,
|
|
3331
4471
|
ARIA_QDRANT_URL: DEFAULT_QDRANT_URL,
|
|
3332
4472
|
OPENAI_BASE_URL: `${DEFAULT_RUNTIME_URL}/v1`,
|
|
3333
|
-
ANTHROPIC_BASE_URL:
|
|
4473
|
+
ANTHROPIC_BASE_URL: DEFAULT_RUNTIME_URL,
|
|
3334
4474
|
},
|
|
3335
4475
|
commands: {
|
|
3336
4476
|
start: 'aria-runtime',
|
|
@@ -3355,6 +4495,423 @@ function runtimeManifest() {
|
|
|
3355
4495
|
};
|
|
3356
4496
|
}
|
|
3357
4497
|
|
|
4498
|
+
let taskProjectLedgerModulePromise = null;
|
|
4499
|
+
let openClawRuntimeModulePromise = null;
|
|
4500
|
+
|
|
4501
|
+
async function loadTaskProjectLedgerModule() {
|
|
4502
|
+
if (taskProjectLedgerModulePromise) return taskProjectLedgerModulePromise;
|
|
4503
|
+
const candidates = [
|
|
4504
|
+
join(__dirname, 'task-project-ledger.mjs'),
|
|
4505
|
+
join(__dirname, '..', 'opencode-plugins', 'harness-context', 'task-project-ledger.mjs'),
|
|
4506
|
+
join(__dirname, '..', 'assets', 'opencode-plugins', 'harness-context', 'task-project-ledger.mjs'),
|
|
4507
|
+
];
|
|
4508
|
+
taskProjectLedgerModulePromise = (async () => {
|
|
4509
|
+
for (const candidate of candidates) {
|
|
4510
|
+
if (!existsSync(candidate)) continue;
|
|
4511
|
+
const mod = await import(`file://${candidate}`);
|
|
4512
|
+
if (typeof mod.updateTaskProjectLedger === 'function') return mod;
|
|
4513
|
+
}
|
|
4514
|
+
throw new Error(`task/project ledger helper missing from candidates: ${candidates.join(', ')}`);
|
|
4515
|
+
})();
|
|
4516
|
+
return taskProjectLedgerModulePromise;
|
|
4517
|
+
}
|
|
4518
|
+
|
|
4519
|
+
function parseMaybeJson(text) {
|
|
4520
|
+
const raw = String(text || '').trim();
|
|
4521
|
+
if (!raw) return null;
|
|
4522
|
+
try {
|
|
4523
|
+
return JSON.parse(raw);
|
|
4524
|
+
} catch {
|
|
4525
|
+
return raw.slice(0, 4000);
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
function firstTrimmedString(...values) {
|
|
4530
|
+
for (const value of values) {
|
|
4531
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
4532
|
+
if (typeof value === 'number' && Number.isFinite(value)) return String(value);
|
|
4533
|
+
}
|
|
4534
|
+
return '';
|
|
4535
|
+
}
|
|
4536
|
+
|
|
4537
|
+
function nullableTrimmedString(value) {
|
|
4538
|
+
if (value === null) return null;
|
|
4539
|
+
return firstTrimmedString(value) || undefined;
|
|
4540
|
+
}
|
|
4541
|
+
|
|
4542
|
+
function requireTrimmedString(value, label) {
|
|
4543
|
+
const normalized = firstTrimmedString(value);
|
|
4544
|
+
if (!normalized) throw new Error(`${label} is required`);
|
|
4545
|
+
return normalized;
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
function coerceExpectedRevision(value) {
|
|
4549
|
+
const revision = Number(value);
|
|
4550
|
+
if (!Number.isInteger(revision) || revision < 0) {
|
|
4551
|
+
throw new Error('expectedRevision must be a non-negative integer');
|
|
4552
|
+
}
|
|
4553
|
+
return revision;
|
|
4554
|
+
}
|
|
4555
|
+
|
|
4556
|
+
function normalizeOpenClawStatus(value, allowed, fallback) {
|
|
4557
|
+
const normalized = firstTrimmedString(value);
|
|
4558
|
+
if (!normalized) return fallback;
|
|
4559
|
+
if (!allowed.includes(normalized)) throw new Error(`Unsupported OpenClaw flow status: ${normalized}`);
|
|
4560
|
+
return normalized;
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4563
|
+
function openClawRuntimeModuleCandidates() {
|
|
4564
|
+
const candidates = [...OPENCLAW_RUNTIME_MODULE_CANDIDATES];
|
|
4565
|
+
try {
|
|
4566
|
+
const pkgPath = require.resolve('openclaw/package.json');
|
|
4567
|
+
candidates.push(join(dirname(pkgPath), 'dist', 'plugins', 'runtime', 'index.js'));
|
|
4568
|
+
} catch {}
|
|
4569
|
+
return [...new Set(candidates.filter(Boolean))];
|
|
4570
|
+
}
|
|
4571
|
+
|
|
4572
|
+
async function loadOpenClawRuntimeModule() {
|
|
4573
|
+
if (openClawRuntimeModulePromise) return openClawRuntimeModulePromise;
|
|
4574
|
+
openClawRuntimeModulePromise = (async () => {
|
|
4575
|
+
const candidates = openClawRuntimeModuleCandidates();
|
|
4576
|
+
for (const candidate of candidates) {
|
|
4577
|
+
if (!existsSync(candidate)) continue;
|
|
4578
|
+
const mod = await import(pathToFileURL(candidate).href);
|
|
4579
|
+
if (typeof mod.createPluginRuntime === 'function') {
|
|
4580
|
+
return { modulePath: candidate, createPluginRuntime: mod.createPluginRuntime };
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
throw new Error(
|
|
4584
|
+
`OpenClaw plugin runtime module missing from candidates: ${candidates.join(', ')}. Set OPENCLAW_RUNTIME_MODULE to the installed OpenClaw dist/plugins/runtime/index.js path.`,
|
|
4585
|
+
);
|
|
4586
|
+
})();
|
|
4587
|
+
return openClawRuntimeModulePromise;
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4590
|
+
function resolveOpenClawOwnerKey(request = {}, body = {}, context = {}) {
|
|
4591
|
+
return firstTrimmedString(
|
|
4592
|
+
request.ownerKey,
|
|
4593
|
+
request.sessionKey,
|
|
4594
|
+
request.requesterSessionKey,
|
|
4595
|
+
body.ownerKey,
|
|
4596
|
+
body.sessionKey,
|
|
4597
|
+
body.sessionId,
|
|
4598
|
+
context.ownerKey,
|
|
4599
|
+
);
|
|
4600
|
+
}
|
|
4601
|
+
|
|
4602
|
+
function ownerKeyForTaskProjectIdentity(identity = {}) {
|
|
4603
|
+
if (!identity.projectHash || !identity.taskHash) return '';
|
|
4604
|
+
return `aria-ledger:${identity.projectHash}:${identity.taskHash}`;
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4607
|
+
async function executeOpenClawTaskFlowAction(request = {}, context = {}) {
|
|
4608
|
+
const { modulePath, createPluginRuntime } = await loadOpenClawRuntimeModule();
|
|
4609
|
+
const ownerKey = requireTrimmedString(
|
|
4610
|
+
resolveOpenClawOwnerKey(request, {}, context),
|
|
4611
|
+
'OpenClaw ownerKey or sessionKey',
|
|
4612
|
+
);
|
|
4613
|
+
const runtime = createPluginRuntime();
|
|
4614
|
+
const bindSession = runtime?.tasks?.flow?.bindSession || runtime?.taskFlow?.bindSession;
|
|
4615
|
+
if (typeof bindSession !== 'function') {
|
|
4616
|
+
throw new Error('OpenClaw plugin runtime does not expose tasks.flow.bindSession');
|
|
4617
|
+
}
|
|
4618
|
+
const flowRuntime = bindSession({
|
|
4619
|
+
sessionKey: ownerKey,
|
|
4620
|
+
requesterOrigin: request.requesterOrigin,
|
|
4621
|
+
});
|
|
4622
|
+
const action = requireTrimmedString(request.action || context.action || 'create_flow', 'OpenClaw action');
|
|
4623
|
+
const base = {
|
|
4624
|
+
ok: true,
|
|
4625
|
+
mode: 'owned_openclaw_task_flow',
|
|
4626
|
+
api: 'openclaw.plugin-runtime.tasks.flow',
|
|
4627
|
+
modulePath,
|
|
4628
|
+
action,
|
|
4629
|
+
ownerKey,
|
|
4630
|
+
};
|
|
4631
|
+
|
|
4632
|
+
if (action === 'create_flow') {
|
|
4633
|
+
const flow = flowRuntime.createManaged({
|
|
4634
|
+
controllerId: firstTrimmedString(request.controllerId, context.controllerId) || 'aria/task-project-ledger',
|
|
4635
|
+
goal: requireTrimmedString(request.goal || context.goal, 'OpenClaw flow goal'),
|
|
4636
|
+
status: normalizeOpenClawStatus(
|
|
4637
|
+
request.status,
|
|
4638
|
+
['queued', 'running', 'waiting', 'blocked'],
|
|
4639
|
+
request.status === undefined ? 'running' : undefined,
|
|
4640
|
+
),
|
|
4641
|
+
notifyPolicy: normalizeOpenClawStatus(
|
|
4642
|
+
request.notifyPolicy,
|
|
4643
|
+
['done_only', 'state_changes', 'silent'],
|
|
4644
|
+
undefined,
|
|
4645
|
+
),
|
|
4646
|
+
currentStep: nullableTrimmedString(request.currentStep),
|
|
4647
|
+
stateJson: request.stateJson,
|
|
4648
|
+
waitJson: request.waitJson,
|
|
4649
|
+
});
|
|
4650
|
+
return { ...base, created: true, flow };
|
|
4651
|
+
}
|
|
4652
|
+
|
|
4653
|
+
if (action === 'get_flow') {
|
|
4654
|
+
const flow = flowRuntime.get(requireTrimmedString(request.flowId, 'OpenClaw flowId'));
|
|
4655
|
+
return { ...base, found: Boolean(flow), flow: flow || null };
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4658
|
+
if (action === 'list_flows') {
|
|
4659
|
+
return { ...base, flows: flowRuntime.list() };
|
|
4660
|
+
}
|
|
4661
|
+
|
|
4662
|
+
if (action === 'find_latest_flow') {
|
|
4663
|
+
const flow = flowRuntime.findLatest();
|
|
4664
|
+
return { ...base, found: Boolean(flow), flow: flow || null };
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
if (action === 'resolve_flow') {
|
|
4668
|
+
const flow = flowRuntime.resolve(requireTrimmedString(request.token, 'OpenClaw flow lookup token'));
|
|
4669
|
+
return { ...base, found: Boolean(flow), flow: flow || null };
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
if (action === 'get_task_summary') {
|
|
4673
|
+
const taskSummary = flowRuntime.getTaskSummary(requireTrimmedString(request.flowId, 'OpenClaw flowId'));
|
|
4674
|
+
return { ...base, found: Boolean(taskSummary), taskSummary: taskSummary || null };
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
if (action === 'set_waiting') {
|
|
4678
|
+
const result = flowRuntime.setWaiting({
|
|
4679
|
+
flowId: requireTrimmedString(request.flowId, 'OpenClaw flowId'),
|
|
4680
|
+
expectedRevision: coerceExpectedRevision(request.expectedRevision),
|
|
4681
|
+
currentStep: nullableTrimmedString(request.currentStep),
|
|
4682
|
+
stateJson: request.stateJson,
|
|
4683
|
+
waitJson: request.waitJson,
|
|
4684
|
+
blockedTaskId: nullableTrimmedString(request.blockedTaskId),
|
|
4685
|
+
blockedSummary: nullableTrimmedString(request.blockedSummary),
|
|
4686
|
+
});
|
|
4687
|
+
return { ...base, result, flow: result.applied ? result.flow : result.current || null };
|
|
4688
|
+
}
|
|
4689
|
+
|
|
4690
|
+
if (action === 'resume_flow' || action === 'advance_flow') {
|
|
4691
|
+
const result = flowRuntime.resume({
|
|
4692
|
+
flowId: requireTrimmedString(request.flowId, 'OpenClaw flowId'),
|
|
4693
|
+
expectedRevision: coerceExpectedRevision(request.expectedRevision),
|
|
4694
|
+
status: normalizeOpenClawStatus(request.status, ['queued', 'running'], 'running'),
|
|
4695
|
+
currentStep: nullableTrimmedString(request.currentStep),
|
|
4696
|
+
stateJson: request.stateJson,
|
|
4697
|
+
});
|
|
4698
|
+
return { ...base, result, flow: result.applied ? result.flow : result.current || null };
|
|
4699
|
+
}
|
|
4700
|
+
|
|
4701
|
+
if (action === 'finish_flow') {
|
|
4702
|
+
const result = flowRuntime.finish({
|
|
4703
|
+
flowId: requireTrimmedString(request.flowId, 'OpenClaw flowId'),
|
|
4704
|
+
expectedRevision: coerceExpectedRevision(request.expectedRevision),
|
|
4705
|
+
stateJson: request.stateJson,
|
|
4706
|
+
});
|
|
4707
|
+
return { ...base, result, flow: result.applied ? result.flow : result.current || null };
|
|
4708
|
+
}
|
|
4709
|
+
|
|
4710
|
+
if (action === 'fail_flow') {
|
|
4711
|
+
const result = flowRuntime.fail({
|
|
4712
|
+
flowId: requireTrimmedString(request.flowId, 'OpenClaw flowId'),
|
|
4713
|
+
expectedRevision: coerceExpectedRevision(request.expectedRevision),
|
|
4714
|
+
stateJson: request.stateJson,
|
|
4715
|
+
blockedTaskId: nullableTrimmedString(request.blockedTaskId),
|
|
4716
|
+
blockedSummary: nullableTrimmedString(request.blockedSummary),
|
|
4717
|
+
});
|
|
4718
|
+
return { ...base, result, flow: result.applied ? result.flow : result.current || null };
|
|
4719
|
+
}
|
|
4720
|
+
|
|
4721
|
+
if (action === 'request_cancel') {
|
|
4722
|
+
const result = flowRuntime.requestCancel({
|
|
4723
|
+
flowId: requireTrimmedString(request.flowId, 'OpenClaw flowId'),
|
|
4724
|
+
expectedRevision: coerceExpectedRevision(request.expectedRevision),
|
|
4725
|
+
});
|
|
4726
|
+
return { ...base, result, flow: result.applied ? result.flow : result.current || null };
|
|
4727
|
+
}
|
|
4728
|
+
|
|
4729
|
+
if (action === 'cancel_flow') {
|
|
4730
|
+
const result = await flowRuntime.cancel({
|
|
4731
|
+
flowId: requireTrimmedString(request.flowId, 'OpenClaw flowId'),
|
|
4732
|
+
cfg: request.cfg || {},
|
|
4733
|
+
});
|
|
4734
|
+
return { ...base, result, flow: result.flow || null, tasks: result.tasks || [] };
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4737
|
+
if (action === 'run_task') {
|
|
4738
|
+
const taskRuntime = firstTrimmedString(request.runtime) || 'cli';
|
|
4739
|
+
if (!['subagent', 'acp', 'cli', 'cron'].includes(taskRuntime)) {
|
|
4740
|
+
throw new Error(`Unsupported OpenClaw task runtime: ${taskRuntime}`);
|
|
4741
|
+
}
|
|
4742
|
+
const result = flowRuntime.runTask({
|
|
4743
|
+
flowId: requireTrimmedString(request.flowId, 'OpenClaw flowId'),
|
|
4744
|
+
runtime: taskRuntime,
|
|
4745
|
+
sourceId: nullableTrimmedString(request.sourceId),
|
|
4746
|
+
childSessionKey: nullableTrimmedString(request.childSessionKey),
|
|
4747
|
+
parentTaskId: nullableTrimmedString(request.parentTaskId),
|
|
4748
|
+
agentId: nullableTrimmedString(request.agentId),
|
|
4749
|
+
runId: nullableTrimmedString(request.runId),
|
|
4750
|
+
label: nullableTrimmedString(request.label),
|
|
4751
|
+
task: requireTrimmedString(request.task, 'OpenClaw task'),
|
|
4752
|
+
preferMetadata: request.preferMetadata === true,
|
|
4753
|
+
notifyPolicy: normalizeOpenClawStatus(
|
|
4754
|
+
request.notifyPolicy,
|
|
4755
|
+
['done_only', 'state_changes', 'silent'],
|
|
4756
|
+
undefined,
|
|
4757
|
+
),
|
|
4758
|
+
status: normalizeOpenClawStatus(request.status, ['queued', 'running'], undefined),
|
|
4759
|
+
startedAt: Number.isFinite(Number(request.startedAt)) ? Number(request.startedAt) : undefined,
|
|
4760
|
+
lastEventAt: Number.isFinite(Number(request.lastEventAt)) ? Number(request.lastEventAt) : undefined,
|
|
4761
|
+
progressSummary: nullableTrimmedString(request.progressSummary),
|
|
4762
|
+
});
|
|
4763
|
+
return { ...base, result, flow: result.flow || null, task: result.task || null };
|
|
4764
|
+
}
|
|
4765
|
+
|
|
4766
|
+
throw new Error(`Unsupported OpenClaw task-flow action: ${action}`);
|
|
4767
|
+
}
|
|
4768
|
+
|
|
4769
|
+
function resolveOpenClawBin() {
|
|
4770
|
+
for (const candidate of OPENCLAW_BIN_CANDIDATES) {
|
|
4771
|
+
if (candidate.includes('/') && existsSync(candidate)) return candidate;
|
|
4772
|
+
if (!candidate.includes('/')) return candidate;
|
|
4773
|
+
}
|
|
4774
|
+
return 'openclaw';
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4777
|
+
function runOpenClawJson(args, timeoutMs = 7000) {
|
|
4778
|
+
const bin = resolveOpenClawBin();
|
|
4779
|
+
const child = spawnSync(bin, args, {
|
|
4780
|
+
encoding: 'utf8',
|
|
4781
|
+
timeout: timeoutMs,
|
|
4782
|
+
maxBuffer: 1024 * 1024,
|
|
4783
|
+
});
|
|
4784
|
+
const stdout = String(child.stdout || '').trim();
|
|
4785
|
+
const stderr = String(child.stderr || '').trim();
|
|
4786
|
+
const jsonSource = stdout || (child.status === 0 ? stderr : '');
|
|
4787
|
+
return {
|
|
4788
|
+
ok: child.status === 0,
|
|
4789
|
+
status: child.status,
|
|
4790
|
+
signal: child.signal || null,
|
|
4791
|
+
bin,
|
|
4792
|
+
args,
|
|
4793
|
+
json: child.status === 0 ? parseMaybeJson(jsonSource) : null,
|
|
4794
|
+
jsonStream: stdout ? 'stdout' : jsonSource ? 'stderr' : null,
|
|
4795
|
+
stderr: (child.error ? `${child.error.message}\n` : '') + (stdout ? stderr.slice(0, 1000) : ''),
|
|
4796
|
+
};
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
function collectOpenClawTaskLedgerSnapshot(body = {}) {
|
|
4800
|
+
const includeTasks = body.includeTasks !== false;
|
|
4801
|
+
const includeAudit = body.includeAudit !== false;
|
|
4802
|
+
const includeFlows = body.includeFlows !== false;
|
|
4803
|
+
const commands = {};
|
|
4804
|
+
if (includeTasks) commands.tasksList = runOpenClawJson(['tasks', 'list', '--json']);
|
|
4805
|
+
if (includeAudit) commands.tasksAudit = runOpenClawJson(['tasks', 'audit', '--json']);
|
|
4806
|
+
if (includeFlows) commands.flowList = runOpenClawJson(['tasks', 'flow', 'list', '--json']);
|
|
4807
|
+
const commandValues = Object.values(commands);
|
|
4808
|
+
return {
|
|
4809
|
+
mode: 'openclaw_cli_task_flow_snapshot',
|
|
4810
|
+
observedAt: new Date().toISOString(),
|
|
4811
|
+
available: commandValues.length > 0 && commandValues.some((result) => result.ok),
|
|
4812
|
+
bin: resolveOpenClawBin(),
|
|
4813
|
+
commands,
|
|
4814
|
+
caveat: 'This route is a read-only CLI snapshot; managed flow mutations use /openclaw/task-flow through the OpenClaw plugin runtime Task Flow API.',
|
|
4815
|
+
};
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
function summarizeTaskProjectLedger(ledger, paths = {}) {
|
|
4819
|
+
return {
|
|
4820
|
+
ledgerId: ledger?.ledgerId || null,
|
|
4821
|
+
status: ledger?.status || null,
|
|
4822
|
+
projectRef: ledger?.identity?.projectHint || null,
|
|
4823
|
+
taskRef: ledger?.identity?.taskHint || null,
|
|
4824
|
+
readinessClaimAllowed: ledger?.controls?.readinessClaimAllowed === true,
|
|
4825
|
+
missingReadinessGates: ledger?.controls?.missingReadinessGates || [],
|
|
4826
|
+
openBlockerCount: Array.isArray(ledger?.openBlockers) ? ledger.openBlockers.length : 0,
|
|
4827
|
+
eventCount: Array.isArray(ledger?.phaseEvents) ? ledger.phaseEvents.length : 0,
|
|
4828
|
+
evidenceCount: Array.isArray(ledger?.evidence) ? ledger.evidence.length : 0,
|
|
4829
|
+
ledgerPath: paths.ledgerPath || null,
|
|
4830
|
+
};
|
|
4831
|
+
}
|
|
4832
|
+
|
|
4833
|
+
async function handleTaskProjectLedgerRoute(url, body = {}) {
|
|
4834
|
+
const ledgerMod = await loadTaskProjectLedgerModule();
|
|
4835
|
+
const platform = typeof body.platform === 'string' && body.platform.trim() ? body.platform.trim() : 'owner_runtime';
|
|
4836
|
+
const phase = typeof body.phase === 'string' && body.phase.trim() ? body.phase.trim() : 'post_turn';
|
|
4837
|
+
const source = typeof body.source === 'string' && body.source.trim() ? body.source.trim() : 'owner-runtime-ledger-route';
|
|
4838
|
+
const event = body.event && typeof body.event === 'object' ? body.event : body;
|
|
4839
|
+
|
|
4840
|
+
if (url.pathname === '/openclaw/task-flow') {
|
|
4841
|
+
return executeOpenClawTaskFlowAction(body);
|
|
4842
|
+
}
|
|
4843
|
+
|
|
4844
|
+
if (url.pathname === '/openclaw/task-ledger/snapshot') {
|
|
4845
|
+
return { ok: true, openclaw: collectOpenClawTaskLedgerSnapshot(body) };
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4848
|
+
if (url.pathname === '/task-project-ledger/status') {
|
|
4849
|
+
const identity = ledgerMod.resolveTaskProjectIdentity(event, process.env);
|
|
4850
|
+
const paths = ledgerMod.taskProjectLedgerPaths(identity, process.env);
|
|
4851
|
+
const ledger = existsSync(paths.ledgerPath) ? JSON.parse(readFileSync(paths.ledgerPath, 'utf8')) : null;
|
|
4852
|
+
return {
|
|
4853
|
+
ok: true,
|
|
4854
|
+
exists: Boolean(ledger),
|
|
4855
|
+
ledger: ledger ? summarizeTaskProjectLedger(ledger, paths) : null,
|
|
4856
|
+
paths,
|
|
4857
|
+
};
|
|
4858
|
+
}
|
|
4859
|
+
|
|
4860
|
+
let evidence = body.evidence && typeof body.evidence === 'object' ? { ...body.evidence } : {};
|
|
4861
|
+
if (body.openclawBridge === true || body.collectOpenClaw === true) {
|
|
4862
|
+
evidence.openclaw = collectOpenClawTaskLedgerSnapshot(body.openclaw || {});
|
|
4863
|
+
}
|
|
4864
|
+
if (body.openclawFlow && typeof body.openclawFlow === 'object') {
|
|
4865
|
+
const identity = ledgerMod.resolveTaskProjectIdentity(event, process.env);
|
|
4866
|
+
const ownerKey = resolveOpenClawOwnerKey(body.openclawFlow, body, {
|
|
4867
|
+
ownerKey: ownerKeyForTaskProjectIdentity(identity),
|
|
4868
|
+
});
|
|
4869
|
+
evidence.openclawFlow = await executeOpenClawTaskFlowAction(body.openclawFlow, {
|
|
4870
|
+
ownerKey,
|
|
4871
|
+
controllerId: 'aria/task-project-ledger',
|
|
4872
|
+
goal: firstTrimmedString(body.openclawFlow.goal, event.goal, event.prompt, event.message, event.text, 'Aria task/project ledger flow'),
|
|
4873
|
+
});
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4876
|
+
const result = ledgerMod.updateTaskProjectLedger({
|
|
4877
|
+
platform,
|
|
4878
|
+
phase,
|
|
4879
|
+
source,
|
|
4880
|
+
event,
|
|
4881
|
+
evidence,
|
|
4882
|
+
env: process.env,
|
|
4883
|
+
});
|
|
4884
|
+
|
|
4885
|
+
if (url.pathname === '/task-project-ledger/claim') {
|
|
4886
|
+
const text = typeof body.text === 'string' ? body.text : '';
|
|
4887
|
+
const evaluation = ledgerMod.evaluateTaskProjectClaim({ text, ledger: result.ledger });
|
|
4888
|
+
if (!evaluation.ok) {
|
|
4889
|
+
ledgerMod.recordBlockedTaskProjectClaim({
|
|
4890
|
+
ledger: result.ledger,
|
|
4891
|
+
paths: result.paths,
|
|
4892
|
+
text,
|
|
4893
|
+
evaluation,
|
|
4894
|
+
});
|
|
4895
|
+
}
|
|
4896
|
+
return {
|
|
4897
|
+
ok: true,
|
|
4898
|
+
permitted: evaluation.ok,
|
|
4899
|
+
claim: evaluation.claim,
|
|
4900
|
+
missingReadinessGates: evaluation.missingReadinessGates,
|
|
4901
|
+
openBlockerCount: evaluation.openBlockers.length,
|
|
4902
|
+
ledger: summarizeTaskProjectLedger(result.ledger, result.paths),
|
|
4903
|
+
openclawFlow: evidence.openclawFlow || null,
|
|
4904
|
+
};
|
|
4905
|
+
}
|
|
4906
|
+
|
|
4907
|
+
return {
|
|
4908
|
+
ok: true,
|
|
4909
|
+
ledger: summarizeTaskProjectLedger(result.ledger, result.paths),
|
|
4910
|
+
openclaw: evidence.openclaw || null,
|
|
4911
|
+
openclawFlow: evidence.openclawFlow || null,
|
|
4912
|
+
};
|
|
4913
|
+
}
|
|
4914
|
+
|
|
3358
4915
|
async function runLayer3(req, body, client) {
|
|
3359
4916
|
if (typeof body.text !== 'string' || !body.text.trim()) {
|
|
3360
4917
|
throw new Error('full-chain requires a non-empty text field');
|
|
@@ -3377,7 +4934,7 @@ async function runLayer3(req, body, client) {
|
|
|
3377
4934
|
const doctrineFailures = doctrineHits.map((hit) => ({
|
|
3378
4935
|
severity: String(hit.severity || 'block').toLowerCase() === 'block' ? 'block' : 'warn',
|
|
3379
4936
|
kind: 'drift_trigger',
|
|
3380
|
-
detail: `${hit.trigger} (${hit.memory || 'doctrine_trigger_map.json'}): ${hit.message || hit.teaching || 'Doctrine trigger matched.'}`,
|
|
4937
|
+
detail: `${hit.trigger || hit.triggerId || 'doctrine_trigger'} (${hit.memory || 'doctrine_trigger_map.json'}): ${hit.message || hit.teaching || 'Doctrine trigger matched.'}`,
|
|
3381
4938
|
}));
|
|
3382
4939
|
const allFailures = [...result.failures, ...doctrineFailures];
|
|
3383
4940
|
const hardFailures = allFailures.filter((failure) => failure.severity === 'block');
|
|
@@ -3619,6 +5176,14 @@ async function handleRoute(req, res) {
|
|
|
3619
5176
|
});
|
|
3620
5177
|
}
|
|
3621
5178
|
|
|
5179
|
+
if (req.method === 'GET' && url.pathname === '/coach/state') {
|
|
5180
|
+
return json(res, 200, {
|
|
5181
|
+
ok: true,
|
|
5182
|
+
phases: COACH_PHASES,
|
|
5183
|
+
state: readCoachState(),
|
|
5184
|
+
});
|
|
5185
|
+
}
|
|
5186
|
+
|
|
3622
5187
|
if (req.method === 'GET' && url.pathname === '/mount') {
|
|
3623
5188
|
return json(res, 200, runtimeManifest().mount);
|
|
3624
5189
|
}
|
|
@@ -3634,11 +5199,21 @@ async function handleRoute(req, res) {
|
|
|
3634
5199
|
return json(res, 400, { ok: false, error: `Invalid JSON body: ${error.message}` });
|
|
3635
5200
|
}
|
|
3636
5201
|
|
|
5202
|
+
const providerPath = normalizeProviderCompatibilityPath(url.pathname);
|
|
5203
|
+
const providerCompatibilityRoute = isProviderCompatibilityPath(providerPath);
|
|
5204
|
+
const ariaAuthOptions = { allowBearerAuth: true };
|
|
5205
|
+
const taskProjectLedgerRoute =
|
|
5206
|
+
url.pathname === '/task-project-ledger/event' ||
|
|
5207
|
+
url.pathname === '/task-project-ledger/status' ||
|
|
5208
|
+
url.pathname === '/task-project-ledger/claim' ||
|
|
5209
|
+
url.pathname === '/openclaw/task-ledger/snapshot' ||
|
|
5210
|
+
url.pathname === '/openclaw/task-flow';
|
|
5211
|
+
|
|
3637
5212
|
let client;
|
|
3638
5213
|
try {
|
|
3639
5214
|
// HQ routes use their own auth middleware — skip the global API key gate
|
|
3640
|
-
if (!url.pathname.startsWith('/hq/')) {
|
|
3641
|
-
client = createClient(req, body);
|
|
5215
|
+
if (!url.pathname.startsWith('/hq/') && !taskProjectLedgerRoute) {
|
|
5216
|
+
client = createClient(req, body, ariaAuthOptions);
|
|
3642
5217
|
}
|
|
3643
5218
|
} catch (error) {
|
|
3644
5219
|
return json(res, 401, { ok: false, error: error.message });
|
|
@@ -3650,7 +5225,34 @@ async function handleRoute(req, res) {
|
|
|
3650
5225
|
return json(res, 200, { ok: true, lease });
|
|
3651
5226
|
}
|
|
3652
5227
|
|
|
3653
|
-
|
|
5228
|
+
if (taskProjectLedgerRoute) {
|
|
5229
|
+
const ledgerResult = await handleTaskProjectLedgerRoute(url, body);
|
|
5230
|
+
return json(res, ledgerResult.permitted === false ? 409 : 200, ledgerResult);
|
|
5231
|
+
}
|
|
5232
|
+
|
|
5233
|
+
await ensureLease(req, body, client, ariaAuthOptions);
|
|
5234
|
+
|
|
5235
|
+
if (url.pathname === '/coach/event' || url.pathname === '/coach/phase') {
|
|
5236
|
+
const result = recordCoachPhase(body);
|
|
5237
|
+
return json(res, 200, {
|
|
5238
|
+
ok: true,
|
|
5239
|
+
permitted: result.permitted,
|
|
5240
|
+
decision: result.decision,
|
|
5241
|
+
ledgerPath: result.ledgerPath,
|
|
5242
|
+
statePath: result.statePath,
|
|
5243
|
+
record: result.record,
|
|
5244
|
+
state: result.state,
|
|
5245
|
+
clientMessage: result.clientMessage,
|
|
5246
|
+
});
|
|
5247
|
+
}
|
|
5248
|
+
|
|
5249
|
+
if (url.pathname === '/coach/state') {
|
|
5250
|
+
return json(res, 200, {
|
|
5251
|
+
ok: true,
|
|
5252
|
+
phases: COACH_PHASES,
|
|
5253
|
+
state: readCoachState({ includeState: body.includeState === true }),
|
|
5254
|
+
});
|
|
5255
|
+
}
|
|
3654
5256
|
|
|
3655
5257
|
if (url.pathname === '/mizan/plan') {
|
|
3656
5258
|
const turnClass = classifyTurn(body.context || body);
|
|
@@ -3716,7 +5318,8 @@ async function handleRoute(req, res) {
|
|
|
3716
5318
|
const apiKey = resolveApiKey(req, body);
|
|
3717
5319
|
const packetRequest = buildMizanPacketRequest(body);
|
|
3718
5320
|
const packet = body.packet || await loadRuntimePacket(req, body, client, packetRequest, packetRequest.message || body.text || '');
|
|
3719
|
-
const
|
|
5321
|
+
const text = body.text || '';
|
|
5322
|
+
const bundle = evaluateMizanPost(text, normalizePostEvidence(text, body.evidence || {}), packet, body.context || body, {
|
|
3720
5323
|
sessionId: body.sessionId || body.context?.sessionId || deriveSessionId(req, body, 'mizan-post'),
|
|
3721
5324
|
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
3722
5325
|
parentReceiptId: body.parentReceiptId || body.receiptId || null,
|
|
@@ -3733,19 +5336,19 @@ async function handleRoute(req, res) {
|
|
|
3733
5336
|
});
|
|
3734
5337
|
}
|
|
3735
5338
|
|
|
3736
|
-
if (
|
|
3737
|
-
const response = await handleProviderProxy(req, body, client, 'openai');
|
|
5339
|
+
if (providerPath === '/v1/chat/completions') {
|
|
5340
|
+
const response = await handleProviderProxy(req, body, client, 'openai', ariaAuthOptions);
|
|
3738
5341
|
return json(res, 200, response);
|
|
3739
5342
|
}
|
|
3740
5343
|
|
|
3741
|
-
if (
|
|
5344
|
+
if (providerPath === '/v1/responses' || providerPath === '/responses') {
|
|
3742
5345
|
const responseBody = responsesRequestToOpenAIBody(body);
|
|
3743
|
-
const completion = await handleProviderProxy(req, responseBody, client, 'openai');
|
|
5346
|
+
const completion = await handleProviderProxy(req, responseBody, client, 'openai', ariaAuthOptions);
|
|
3744
5347
|
return json(res, 200, openAiCompletionToResponsesEnvelope(body, completion));
|
|
3745
5348
|
}
|
|
3746
5349
|
|
|
3747
|
-
if (
|
|
3748
|
-
const response = await handleProviderProxy(req, body, client, 'anthropic');
|
|
5350
|
+
if (providerPath === '/v1/messages') {
|
|
5351
|
+
const response = await handleProviderProxy(req, body, client, 'anthropic', ariaAuthOptions);
|
|
3749
5352
|
return json(res, 200, response);
|
|
3750
5353
|
}
|
|
3751
5354
|
|
|
@@ -3884,6 +5487,17 @@ async function handleRoute(req, res) {
|
|
|
3884
5487
|
}
|
|
3885
5488
|
}
|
|
3886
5489
|
|
|
5490
|
+
if (
|
|
5491
|
+
url.pathname === '/task-project-ledger/event' ||
|
|
5492
|
+
url.pathname === '/task-project-ledger/status' ||
|
|
5493
|
+
url.pathname === '/task-project-ledger/claim' ||
|
|
5494
|
+
url.pathname === '/openclaw/task-ledger/snapshot' ||
|
|
5495
|
+
url.pathname === '/openclaw/task-flow'
|
|
5496
|
+
) {
|
|
5497
|
+
const ledgerResult = await handleTaskProjectLedgerRoute(url, body);
|
|
5498
|
+
return json(res, ledgerResult.permitted === false ? 409 : 200, ledgerResult);
|
|
5499
|
+
}
|
|
5500
|
+
|
|
3887
5501
|
if (url.pathname === '/packet' || url.pathname === '/api/harness/codex') {
|
|
3888
5502
|
const packet = await loadRuntimePacket(req, body, client, body.packetRequest || body, body.message || '');
|
|
3889
5503
|
return json(res, 200, { ok: true, packet });
|
|
@@ -3933,6 +5547,28 @@ async function handleRoute(req, res) {
|
|
|
3933
5547
|
throw new Error('validate-output requires text and sessionId');
|
|
3934
5548
|
}
|
|
3935
5549
|
|
|
5550
|
+
if (isAriaControlOutput(body.text)) {
|
|
5551
|
+
const response = {
|
|
5552
|
+
ok: true,
|
|
5553
|
+
pass: true,
|
|
5554
|
+
validation: {
|
|
5555
|
+
passed: true,
|
|
5556
|
+
severity: 'pass',
|
|
5557
|
+
violations: [],
|
|
5558
|
+
gateTriggers: ['aria-control-output'],
|
|
5559
|
+
},
|
|
5560
|
+
};
|
|
5561
|
+
if (body.runLayer3 !== false) {
|
|
5562
|
+
response.layer3 = {
|
|
5563
|
+
pass: true,
|
|
5564
|
+
summary: 'control output bypassed assistant prose validation',
|
|
5565
|
+
failures: [],
|
|
5566
|
+
doctrine: { hits: [] },
|
|
5567
|
+
};
|
|
5568
|
+
}
|
|
5569
|
+
return json(res, 200, response);
|
|
5570
|
+
}
|
|
5571
|
+
|
|
3936
5572
|
let validation;
|
|
3937
5573
|
try {
|
|
3938
5574
|
validation = await client.validateOutput(body.text, body.sessionId);
|
|
@@ -3948,6 +5584,7 @@ async function handleRoute(req, res) {
|
|
|
3948
5584
|
};
|
|
3949
5585
|
}
|
|
3950
5586
|
validation = mergeAppliedCognitionValidation(validation, validateAppliedCognitionContract(body.text));
|
|
5587
|
+
validation = allowTrivialAppliedCognitionValidation(validation, body.requireCognitionBlock !== false);
|
|
3951
5588
|
const response = { ok: true, validation };
|
|
3952
5589
|
|
|
3953
5590
|
if (body.runLayer3 !== false) {
|