@aria_asi/cli 0.2.26 → 0.2.29
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 +282 -0
- package/bin/aria.js +1140 -14
- package/dist/aria-connector/src/auth-commands.d.ts +1 -0
- package/dist/aria-connector/src/auth-commands.d.ts.map +1 -1
- package/dist/aria-connector/src/auth-commands.js +89 -41
- package/dist/aria-connector/src/auth-commands.js.map +1 -1
- package/dist/aria-connector/src/chat.d.ts +3 -0
- package/dist/aria-connector/src/chat.d.ts.map +1 -1
- package/dist/aria-connector/src/chat.js +146 -8
- package/dist/aria-connector/src/chat.js.map +1 -1
- package/dist/aria-connector/src/codebase-scanner.d.ts +2 -2
- package/dist/aria-connector/src/codebase-scanner.d.ts.map +1 -1
- package/dist/aria-connector/src/codebase-scanner.js +1 -1
- package/dist/aria-connector/src/codebase-scanner.js.map +1 -1
- package/dist/aria-connector/src/config.d.ts +12 -0
- package/dist/aria-connector/src/config.d.ts.map +1 -1
- package/dist/aria-connector/src/config.js +2 -0
- 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 +80 -24
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts +37 -0
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/codebase-awareness.js +335 -0
- package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -0
- package/dist/aria-connector/src/connectors/codex.d.ts +3 -0
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/codex.js +248 -0
- package/dist/aria-connector/src/connectors/codex.js.map +1 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.d.ts +2 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.js +47 -0
- package/dist/aria-connector/src/connectors/cognitive-skills.js.map +1 -0
- package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.js +90 -4
- package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
- package/dist/aria-connector/src/connectors/repo-git-hooks.d.ts +3 -0
- package/dist/aria-connector/src/connectors/repo-git-hooks.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/repo-git-hooks.js +87 -0
- package/dist/aria-connector/src/connectors/repo-git-hooks.js.map +1 -0
- package/dist/aria-connector/src/connectors/repo-guard.d.ts +19 -0
- package/dist/aria-connector/src/connectors/repo-guard.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/repo-guard.js +509 -0
- package/dist/aria-connector/src/connectors/repo-guard.js.map +1 -0
- package/dist/aria-connector/src/connectors/runtime.d.ts +2 -0
- package/dist/aria-connector/src/connectors/runtime.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/runtime.js +330 -0
- package/dist/aria-connector/src/connectors/runtime.js.map +1 -0
- package/dist/aria-connector/src/connectors/shell.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/shell.js +78 -13
- package/dist/aria-connector/src/connectors/shell.js.map +1 -1
- package/dist/aria-connector/src/connectors/syncd.d.ts +27 -0
- package/dist/aria-connector/src/connectors/syncd.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/syncd.js +405 -0
- package/dist/aria-connector/src/connectors/syncd.js.map +1 -0
- package/dist/aria-connector/src/decisions.d.ts +207 -0
- package/dist/aria-connector/src/decisions.d.ts.map +1 -0
- package/dist/aria-connector/src/decisions.js +291 -0
- package/dist/aria-connector/src/decisions.js.map +1 -0
- package/dist/aria-connector/src/garden-control-plane.d.ts.map +1 -1
- package/dist/aria-connector/src/garden-control-plane.js +74 -17
- package/dist/aria-connector/src/garden-control-plane.js.map +1 -1
- package/dist/aria-connector/src/github-connect.d.ts +18 -0
- package/dist/aria-connector/src/github-connect.d.ts.map +1 -0
- package/dist/aria-connector/src/github-connect.js +117 -0
- package/dist/aria-connector/src/github-connect.js.map +1 -0
- package/dist/aria-connector/src/harness-client.d.ts +15 -0
- package/dist/aria-connector/src/harness-client.d.ts.map +1 -1
- package/dist/aria-connector/src/harness-client.js +106 -3
- package/dist/aria-connector/src/harness-client.js.map +1 -1
- package/dist/aria-connector/src/hive-client.d.ts +30 -0
- package/dist/aria-connector/src/hive-client.d.ts.map +1 -1
- package/dist/aria-connector/src/hive-client.js +124 -5
- package/dist/aria-connector/src/hive-client.js.map +1 -1
- package/dist/aria-connector/src/index.d.ts +13 -2
- package/dist/aria-connector/src/index.d.ts.map +1 -1
- package/dist/aria-connector/src/index.js +10 -1
- package/dist/aria-connector/src/index.js.map +1 -1
- package/dist/aria-connector/src/lib/aristotle-noor-wire.d.ts +102 -0
- package/dist/aria-connector/src/lib/aristotle-noor-wire.d.ts.map +1 -0
- package/dist/aria-connector/src/lib/aristotle-noor-wire.js +231 -0
- package/dist/aria-connector/src/lib/aristotle-noor-wire.js.map +1 -0
- package/dist/aria-connector/src/providers/types.d.ts +5 -0
- package/dist/aria-connector/src/providers/types.d.ts.map +1 -1
- package/dist/aria-connector/src/runtime-proof.d.ts +45 -0
- package/dist/aria-connector/src/runtime-proof.d.ts.map +1 -0
- package/dist/aria-connector/src/runtime-proof.js +340 -0
- package/dist/aria-connector/src/runtime-proof.js.map +1 -0
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +34 -2
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/assets/hooks/aria-agent-handoff.mjs +224 -0
- package/dist/assets/hooks/aria-agent-ledger-merge.mjs +164 -0
- package/dist/assets/hooks/aria-architect-fallback.mjs +267 -0
- package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +676 -0
- package/dist/assets/hooks/aria-discovery-record.mjs +101 -0
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +412 -0
- package/dist/assets/hooks/aria-import-resolution-gate.mjs +330 -0
- package/dist/assets/hooks/aria-outcome-record.mjs +84 -0
- package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +294 -0
- package/dist/assets/hooks/aria-pre-text-gate.mjs +112 -0
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +2133 -0
- package/dist/assets/hooks/aria-preprompt-consult.mjs +438 -0
- package/dist/assets/hooks/aria-preturn-memory-gate.mjs +570 -0
- package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +397 -0
- package/dist/assets/hooks/aria-stop-gate.mjs +1551 -0
- package/dist/assets/hooks/aria-trigger-autolearn.mjs +229 -0
- package/dist/assets/hooks/aria-userprompt-abandon-detect.mjs +192 -0
- package/dist/assets/hooks/doctrine_trigger_map.json +479 -0
- package/dist/assets/hooks/lib/canonical-lenses.mjs +64 -0
- package/dist/assets/hooks/lib/gate-audit.mjs +43 -0
- package/dist/assets/hooks/test-aria-preturn-memory-gate.mjs +245 -0
- package/dist/assets/hooks/test-tier-lens-labeling.mjs +399 -0
- package/dist/assets/opencode-plugins/harness-context/index.js +60 -0
- package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +179 -0
- package/dist/assets/opencode-plugins/harness-context/package.json +9 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +248 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +129 -0
- package/dist/assets/opencode-plugins/harness-role/index.js +77 -0
- package/dist/assets/opencode-plugins/harness-role/package.json +9 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +241 -0
- package/dist/runtime/discipline/CLAUDE.md +339 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +63 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
- package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
- package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
- package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
- package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
- package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +72 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +38 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
- package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +25 -0
- package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
- package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +25 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +81 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +98 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +99 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +127 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +117 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +112 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +102 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +121 -0
- package/dist/runtime/doctor.mjs +23 -0
- package/dist/runtime/local-phase.mjs +632 -0
- package/dist/runtime/manifest.json +15 -0
- package/dist/runtime/mizan-scheduler.mjs +331 -0
- package/dist/runtime/package.json +6 -0
- package/dist/runtime/provider-proxy.mjs +594 -0
- package/dist/runtime/sdk/BUNDLED.json +5 -0
- package/dist/runtime/sdk/index.d.ts +477 -0
- package/dist/runtime/sdk/index.js +1469 -0
- package/dist/runtime/sdk/index.js.map +1 -0
- package/dist/runtime/sdk/package.json +8 -0
- package/dist/runtime/sdk/runWithCognition.d.ts +77 -0
- package/dist/runtime/sdk/runWithCognition.js +157 -0
- package/dist/runtime/sdk/runWithCognition.js.map +1 -0
- package/dist/runtime/service.mjs +2708 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.d.ts +53 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.d.ts.map +1 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.js +277 -0
- package/dist/runtime/vendor/aria-gate-runtime/index.js.map +1 -0
- package/dist/runtime/vendor/aria-gate-runtime/package.json +6 -0
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/index.d.ts +283 -0
- package/dist/sdk/index.js +622 -85
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/runWithCognition.d.ts +77 -0
- package/dist/sdk/runWithCognition.js +157 -0
- package/dist/sdk/runWithCognition.js.map +1 -0
- package/hooks/aria-agent-handoff.mjs +11 -1
- package/hooks/aria-architect-fallback.mjs +109 -40
- package/hooks/aria-cognition-substrate-binding.mjs +676 -0
- package/hooks/aria-harness-via-sdk.mjs +34 -21
- package/hooks/aria-import-resolution-gate.mjs +330 -0
- package/hooks/aria-outcome-record.mjs +5 -1
- package/hooks/aria-pre-emit-dryrun.mjs +294 -0
- package/hooks/aria-pre-tool-gate.mjs +828 -41
- package/hooks/aria-preprompt-consult.mjs +113 -13
- package/hooks/aria-preturn-memory-gate.mjs +298 -6
- package/hooks/aria-repo-doctrine-gate.mjs +397 -0
- package/hooks/aria-stop-gate.mjs +739 -76
- package/hooks/aria-userprompt-abandon-detect.mjs +5 -1
- package/hooks/doctrine_trigger_map.json +209 -15
- package/hooks/lib/canonical-lenses.mjs +64 -0
- package/hooks/lib/gate-audit.mjs +43 -0
- package/opencode-plugins/harness-context/index.js +1 -1
- package/opencode-plugins/harness-context/inject-context.mjs +82 -23
- package/opencode-plugins/harness-gate/index.js +248 -0
- package/opencode-plugins/harness-outcome/index.js +129 -0
- package/opencode-plugins/harness-stop/index.js +241 -0
- package/package.json +8 -2
- package/runtime-src/doctor.mjs +23 -0
- package/runtime-src/local-phase.mjs +632 -0
- package/runtime-src/mizan-scheduler.mjs +331 -0
- package/runtime-src/provider-proxy.mjs +594 -0
- package/runtime-src/service.mjs +2708 -0
- package/scripts/bundle-sdk.mjs +317 -0
- package/scripts/install-client.sh +176 -0
- package/scripts/publish-all.sh +344 -0
- package/scripts/publish-docker.sh +27 -0
- package/scripts/validate-hook-contracts.mjs +54 -0
- package/scripts/validate-skill-prompts.mjs +95 -0
- package/skills/aria-cognition/aria-essence/SKILL.md +63 -0
- package/skills/aria-cognition/aria-essence/references/domain-matrix.md +80 -0
- package/skills/aria-cognition/aria-essence/references/evolution-loop.md +30 -0
- package/skills/aria-cognition/aria-essence/references/readable-cognition.md +27 -0
- package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +35 -0
- package/skills/aria-cognition/aria-forge-guardrails/references/checklist.md +31 -0
- package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +39 -0
- package/skills/aria-cognition/forge-quality-rules/SKILL.md +43 -0
- package/skills/aria-cognition/ghazali-8lens/SKILL.md +38 -0
- package/skills/aria-cognition/istiqra-induction/SKILL.md +26 -0
- package/skills/aria-cognition/ladunni-22/SKILL.md +35 -0
- package/skills/aria-cognition/mizan/SKILL.md +72 -0
- package/skills/aria-cognition/nadia/SKILL.md +38 -0
- package/skills/aria-cognition/nadia-psi/SKILL.md +38 -0
- package/skills/aria-cognition/predictor/SKILL.md +25 -0
- package/skills/aria-cognition/qiyas-analogy/SKILL.md +26 -0
- package/skills/aria-cognition/soul-domains/SKILL.md +25 -0
- package/src/auth-commands.ts +111 -45
- package/src/chat.ts +174 -13
- package/src/codebase-scanner.ts +4 -0
- package/src/config.ts +15 -0
- package/src/connectors/claude-code.ts +79 -25
- package/src/connectors/codebase-awareness.ts +408 -0
- package/src/connectors/codex.ts +274 -0
- package/src/connectors/cognitive-skills.ts +51 -0
- package/src/connectors/opencode.ts +93 -4
- package/src/connectors/repo-git-hooks.ts +86 -0
- package/src/connectors/repo-guard.ts +589 -0
- package/src/connectors/runtime.ts +374 -0
- package/src/connectors/shell.ts +83 -14
- package/src/connectors/syncd.ts +488 -0
- package/src/decisions.ts +469 -0
- package/src/garden-control-plane.ts +101 -26
- package/src/github-connect.ts +143 -0
- package/src/harness-client.ts +128 -3
- package/src/hive-client.ts +165 -5
- package/src/index.ts +41 -2
- package/src/lib/aristotle-noor-wire.ts +310 -0
- package/src/providers/types.ts +6 -0
- package/src/runtime-proof.ts +392 -0
- package/src/setup-wizard.ts +37 -2
|
@@ -0,0 +1,2708 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { createHash, createCipheriv, createDecipheriv, randomBytes, randomUUID, scryptSync } from 'node:crypto';
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
|
|
10
|
+
import { HTTPHarnessClient } from './sdk/index.js';
|
|
11
|
+
import {
|
|
12
|
+
callProviderForAnthropic,
|
|
13
|
+
callProviderForOpenAI,
|
|
14
|
+
extractAnthropicUserMessage,
|
|
15
|
+
extractOpenAIUserMessage,
|
|
16
|
+
} from './provider-proxy.mjs';
|
|
17
|
+
import {
|
|
18
|
+
ARISTOTLE_28_MODULES,
|
|
19
|
+
NOOR_COGNITIVE_SUITE,
|
|
20
|
+
buildPhaseBlockMessage,
|
|
21
|
+
buildRuntimeCognitionDirective,
|
|
22
|
+
extractAegisPatterns,
|
|
23
|
+
extractEvolutionPrinciples,
|
|
24
|
+
} from './local-phase.mjs';
|
|
25
|
+
import {
|
|
26
|
+
buildOperatorPlan,
|
|
27
|
+
classifyTurn,
|
|
28
|
+
evaluateMizanMid,
|
|
29
|
+
evaluateMizanPost,
|
|
30
|
+
evaluateMizanPre,
|
|
31
|
+
summarizeMizanBundle,
|
|
32
|
+
} from './mizan-scheduler.mjs';
|
|
33
|
+
|
|
34
|
+
const require = createRequire(import.meta.url);
|
|
35
|
+
const { runFullChain } = require('./vendor/aria-gate-runtime/index.js');
|
|
36
|
+
|
|
37
|
+
const DEFAULT_HOST = process.env.ARIA_RUNTIME_HOST || '127.0.0.1';
|
|
38
|
+
const DEFAULT_PORT = Number(process.env.ARIA_RUNTIME_PORT || 4319);
|
|
39
|
+
const DEFAULT_HARNESS_URL =
|
|
40
|
+
process.env.ARIA_HARNESS_BASE_URL ||
|
|
41
|
+
process.env.ARIA_HARNESS_URL ||
|
|
42
|
+
'https://harness.ariasos.com';
|
|
43
|
+
const DEFAULT_RUNTIME_URL = process.env.ARIA_RUNTIME_URL || `http://${DEFAULT_HOST}:${DEFAULT_PORT}`;
|
|
44
|
+
const DEFAULT_QDRANT_URL = process.env.ARIA_QDRANT_URL || 'http://127.0.0.1:6333';
|
|
45
|
+
const DEFAULT_QDRANT_COLLECTION = process.env.ARIA_QDRANT_COLLECTION || 'aria_garden_memory';
|
|
46
|
+
const DEFAULT_FORGE_SERVICE_URL =
|
|
47
|
+
process.env.ARIA_FORGE_SERVICE_URL ||
|
|
48
|
+
process.env.FORGE_SERVICE_URL ||
|
|
49
|
+
`${DEFAULT_HARNESS_URL.replace(/\/$/, '')}/api/forge/psi`;
|
|
50
|
+
const DEFAULT_HEARTBEAT_GRACE_SECONDS = Number(process.env.ARIA_RUNTIME_HEARTBEAT_GRACE_SECONDS || 900);
|
|
51
|
+
const DEFAULT_JOB_CLAIM_SECONDS = Number(process.env.ARIA_RUNTIME_JOB_CLAIM_SECONDS || 120);
|
|
52
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
53
|
+
const STATE_DIR = join(__dirname, 'state');
|
|
54
|
+
const LEASE_PATH = join(STATE_DIR, 'lease.enc');
|
|
55
|
+
const RUNTIME_META_PATH = join(STATE_DIR, 'runtime-meta.json');
|
|
56
|
+
const AUTONOMY_STATE_PATH = join(STATE_DIR, 'autonomy.json');
|
|
57
|
+
const COGNITION_STATE_PATH = join(STATE_DIR, 'cognition-state.enc');
|
|
58
|
+
const REVOCATION_LOCK_PATH = join(STATE_DIR, 'revoked.json');
|
|
59
|
+
const CONFIG_PATH = join(process.env.HOME || '', '.aria', 'config.json');
|
|
60
|
+
const CODEBASE_AWARENESS_STATE_PATH = join(process.env.HOME || '', '.aria', 'codebase-awareness-state.json');
|
|
61
|
+
const leaseCache = new Map();
|
|
62
|
+
const TELEMETRY_LIMIT = 250;
|
|
63
|
+
const DECISION_LIMIT = 250;
|
|
64
|
+
const PRINCIPLE_LIMIT = 400;
|
|
65
|
+
const PATTERN_LIMIT = 400;
|
|
66
|
+
const RECEIPT_LIMIT = 500;
|
|
67
|
+
const OWNER_TOKEN_PATH = join(process.env.HOME || '', '.aria', 'owner-token');
|
|
68
|
+
|
|
69
|
+
function json(res, status, payload) {
|
|
70
|
+
res.writeHead(status, { 'content-type': 'application/json; charset=utf-8' });
|
|
71
|
+
res.end(JSON.stringify(payload, null, 2));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function readJson(req) {
|
|
75
|
+
const chunks = [];
|
|
76
|
+
for await (const chunk of req) chunks.push(chunk);
|
|
77
|
+
if (chunks.length === 0) return {};
|
|
78
|
+
const raw = Buffer.concat(chunks).toString('utf8').trim();
|
|
79
|
+
if (!raw) return {};
|
|
80
|
+
return JSON.parse(raw);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function readBearer(req) {
|
|
84
|
+
const auth = req.headers.authorization;
|
|
85
|
+
if (typeof auth !== 'string') return null;
|
|
86
|
+
const match = auth.match(/^Bearer\s+(.+)$/i);
|
|
87
|
+
return match ? match[1] : null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function hashKey(secret) {
|
|
91
|
+
return createHash('sha256').update(secret).digest('hex');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readOwnerToken() {
|
|
95
|
+
try {
|
|
96
|
+
if (!existsSync(OWNER_TOKEN_PATH)) return '';
|
|
97
|
+
return readFileSync(OWNER_TOKEN_PATH, 'utf8').trim();
|
|
98
|
+
} catch {
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function synthesizeOwnerLease(apiKey, reason) {
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
const recommended = 300;
|
|
106
|
+
return {
|
|
107
|
+
keyHash: hashKey(apiKey),
|
|
108
|
+
validatedAt: new Date(now).toISOString(),
|
|
109
|
+
recommendedHeartbeatSeconds: recommended,
|
|
110
|
+
graceSeconds: DEFAULT_HEARTBEAT_GRACE_SECONDS,
|
|
111
|
+
nextRequiredAt: now + recommended * 1000,
|
|
112
|
+
hardStopAt: now + (recommended + DEFAULT_HEARTBEAT_GRACE_SECONDS) * 1000,
|
|
113
|
+
ownerBypass: true,
|
|
114
|
+
claims: {
|
|
115
|
+
tenant_id: 'owner-local',
|
|
116
|
+
tier: 'owner',
|
|
117
|
+
expires_at: null,
|
|
118
|
+
feature_flags: ['owner-bypass'],
|
|
119
|
+
scope: ['all'],
|
|
120
|
+
quota: null,
|
|
121
|
+
doctrine_bundle_hash: null,
|
|
122
|
+
reason,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function deriveEncryptionKey(secret) {
|
|
128
|
+
return scryptSync(secret, 'aria-mounted-runtime', 32);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function encryptJson(payload, secret) {
|
|
132
|
+
const iv = randomBytes(12);
|
|
133
|
+
const key = deriveEncryptionKey(secret);
|
|
134
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
135
|
+
const plaintext = Buffer.from(JSON.stringify(payload), 'utf8');
|
|
136
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
137
|
+
const tag = cipher.getAuthTag();
|
|
138
|
+
return JSON.stringify({
|
|
139
|
+
v: 1,
|
|
140
|
+
iv: iv.toString('base64'),
|
|
141
|
+
tag: tag.toString('base64'),
|
|
142
|
+
data: ciphertext.toString('base64'),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function decryptJson(raw, secret) {
|
|
147
|
+
const payload = JSON.parse(raw);
|
|
148
|
+
const key = deriveEncryptionKey(secret);
|
|
149
|
+
const decipher = createDecipheriv(
|
|
150
|
+
'aes-256-gcm',
|
|
151
|
+
key,
|
|
152
|
+
Buffer.from(payload.iv, 'base64'),
|
|
153
|
+
);
|
|
154
|
+
decipher.setAuthTag(Buffer.from(payload.tag, 'base64'));
|
|
155
|
+
const plaintext = Buffer.concat([
|
|
156
|
+
decipher.update(Buffer.from(payload.data, 'base64')),
|
|
157
|
+
decipher.final(),
|
|
158
|
+
]).toString('utf8');
|
|
159
|
+
return JSON.parse(plaintext);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function loadEncryptedLease(secret) {
|
|
163
|
+
try {
|
|
164
|
+
if (!existsSync(LEASE_PATH)) return null;
|
|
165
|
+
return decryptJson(readFileSync(LEASE_PATH, 'utf8'), secret);
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function saveEncryptedLease(lease, secret) {
|
|
172
|
+
mkdirSync(STATE_DIR, { recursive: true, mode: 0o700 });
|
|
173
|
+
writeFileSync(LEASE_PATH, encryptJson(lease, secret), { mode: 0o600 });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function defaultCognitionState() {
|
|
177
|
+
return {
|
|
178
|
+
telemetry: [],
|
|
179
|
+
decisions: [],
|
|
180
|
+
evolutionPrinciples: [],
|
|
181
|
+
aegisPatterns: [],
|
|
182
|
+
heartbeats: [],
|
|
183
|
+
hive: [],
|
|
184
|
+
cognitiveStrings: [],
|
|
185
|
+
receipts: [],
|
|
186
|
+
lastUpdatedAt: null,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function loadEncryptedCognitionState(secret) {
|
|
191
|
+
try {
|
|
192
|
+
if (!existsSync(COGNITION_STATE_PATH)) return defaultCognitionState();
|
|
193
|
+
const state = decryptJson(readFileSync(COGNITION_STATE_PATH, 'utf8'), secret);
|
|
194
|
+
return {
|
|
195
|
+
...defaultCognitionState(),
|
|
196
|
+
...(state && typeof state === 'object' ? state : {}),
|
|
197
|
+
};
|
|
198
|
+
} catch {
|
|
199
|
+
return defaultCognitionState();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function saveEncryptedCognitionState(state, secret) {
|
|
204
|
+
mkdirSync(STATE_DIR, { recursive: true, mode: 0o700 });
|
|
205
|
+
writeFileSync(COGNITION_STATE_PATH, encryptJson({
|
|
206
|
+
...state,
|
|
207
|
+
lastUpdatedAt: new Date().toISOString(),
|
|
208
|
+
}, secret), { mode: 0o600 });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function readRevocationLock() {
|
|
212
|
+
return readJsonFile(REVOCATION_LOCK_PATH, null);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function writeRevocationLock(payload) {
|
|
216
|
+
writeJsonFile(REVOCATION_LOCK_PATH, {
|
|
217
|
+
lockedAt: new Date().toISOString(),
|
|
218
|
+
...payload,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function clearRevocationLock() {
|
|
223
|
+
try {
|
|
224
|
+
if (existsSync(REVOCATION_LOCK_PATH)) rmSync(REVOCATION_LOCK_PATH, { force: true });
|
|
225
|
+
} catch {}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function ensureNotRevoked(apiKey) {
|
|
229
|
+
const revoked = readRevocationLock();
|
|
230
|
+
if (!revoked) return;
|
|
231
|
+
if (!revoked.keyHash || revoked.keyHash === hashKey(apiKey)) {
|
|
232
|
+
throw new Error(revoked.reason || 'License revoked. Local runtime state is locked.');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function readLocalAriaConfig() {
|
|
237
|
+
return readJsonFile(CONFIG_PATH, {});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function readCodebaseAwarenessState() {
|
|
241
|
+
return readJsonFile(CODEBASE_AWARENESS_STATE_PATH, {
|
|
242
|
+
status: 'idle',
|
|
243
|
+
watchedRepos: [],
|
|
244
|
+
repoSnapshots: [],
|
|
245
|
+
lastError: null,
|
|
246
|
+
updatedAt: null,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function hashProjectionEmbedding(text, dimension = 256) {
|
|
251
|
+
const vector = Array.from({ length: dimension }, () => 0);
|
|
252
|
+
const tokens = String(text || '')
|
|
253
|
+
.toLowerCase()
|
|
254
|
+
.split(/[^a-z0-9_./:-]+/i)
|
|
255
|
+
.filter(Boolean);
|
|
256
|
+
for (const token of tokens) {
|
|
257
|
+
const digest = createHash('sha256').update(token).digest();
|
|
258
|
+
const idx = digest.readUInt16BE(0) % dimension;
|
|
259
|
+
const sign = (digest[2] & 1) === 0 ? 1 : -1;
|
|
260
|
+
vector[idx] += sign;
|
|
261
|
+
}
|
|
262
|
+
const magnitude = Math.sqrt(vector.reduce((sum, value) => sum + value * value, 0));
|
|
263
|
+
if (!magnitude) return vector;
|
|
264
|
+
return vector.map((value) => value / magnitude);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function qdrantRequest(method, pathname, body = null) {
|
|
268
|
+
const response = await fetch(`${DEFAULT_QDRANT_URL.replace(/\/+$/, '')}${pathname}`, {
|
|
269
|
+
method,
|
|
270
|
+
headers: { 'Content-Type': 'application/json' },
|
|
271
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
272
|
+
});
|
|
273
|
+
if (!response.ok) {
|
|
274
|
+
const errorBody = await response.text().catch(() => response.statusText);
|
|
275
|
+
throw new Error(`Qdrant error ${response.status}: ${errorBody}`);
|
|
276
|
+
}
|
|
277
|
+
return response.json().catch(() => ({}));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let qdrantCollectionReady = false;
|
|
281
|
+
|
|
282
|
+
async function ensureQdrantCollection() {
|
|
283
|
+
if (qdrantCollectionReady) return;
|
|
284
|
+
try {
|
|
285
|
+
await qdrantRequest('GET', `/collections/${encodeURIComponent(DEFAULT_QDRANT_COLLECTION)}`);
|
|
286
|
+
qdrantCollectionReady = true;
|
|
287
|
+
return;
|
|
288
|
+
} catch {}
|
|
289
|
+
|
|
290
|
+
await qdrantRequest('PUT', `/collections/${encodeURIComponent(DEFAULT_QDRANT_COLLECTION)}`, {
|
|
291
|
+
vectors: {
|
|
292
|
+
size: 256,
|
|
293
|
+
distance: 'Cosine',
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
qdrantCollectionReady = true;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async function persistGardenPulseToQdrant(apiKey, payload) {
|
|
300
|
+
await ensureQdrantCollection();
|
|
301
|
+
const pointId = payload.id || randomUUID();
|
|
302
|
+
const content = [
|
|
303
|
+
payload.message || '',
|
|
304
|
+
payload.response || '',
|
|
305
|
+
Array.isArray(payload.tags) ? payload.tags.join(' ') : '',
|
|
306
|
+
payload.plannedApproach || '',
|
|
307
|
+
].filter(Boolean).join('\n');
|
|
308
|
+
const vector = hashProjectionEmbedding(content, 256);
|
|
309
|
+
await qdrantRequest('PUT', `/collections/${encodeURIComponent(DEFAULT_QDRANT_COLLECTION)}/points?wait=true`, {
|
|
310
|
+
points: [
|
|
311
|
+
{
|
|
312
|
+
id: pointId,
|
|
313
|
+
vector,
|
|
314
|
+
payload: {
|
|
315
|
+
keyHash: hashKey(apiKey),
|
|
316
|
+
sessionId: payload.sessionId || null,
|
|
317
|
+
message: payload.message || '',
|
|
318
|
+
response: payload.response || '',
|
|
319
|
+
plannedApproach: payload.plannedApproach || null,
|
|
320
|
+
tags: Array.isArray(payload.tags) ? payload.tags : [],
|
|
321
|
+
telemetry: payload.telemetry || null,
|
|
322
|
+
readability: payload.readability || null,
|
|
323
|
+
createdAt: new Date().toISOString(),
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
],
|
|
327
|
+
});
|
|
328
|
+
return { pointId, collection: DEFAULT_QDRANT_COLLECTION };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function searchGardenQdrant(apiKey, query, limit = 8) {
|
|
332
|
+
await ensureQdrantCollection();
|
|
333
|
+
const vector = hashProjectionEmbedding(query, 256);
|
|
334
|
+
const response = await qdrantRequest('POST', `/collections/${encodeURIComponent(DEFAULT_QDRANT_COLLECTION)}/points/search`, {
|
|
335
|
+
vector,
|
|
336
|
+
limit: Math.max(1, Math.min(Number(limit) || 8, 20)),
|
|
337
|
+
with_payload: true,
|
|
338
|
+
filter: {
|
|
339
|
+
must: [
|
|
340
|
+
{
|
|
341
|
+
key: 'keyHash',
|
|
342
|
+
match: { value: hashKey(apiKey) },
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
return Array.isArray(response?.result) ? response.result : [];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function appendBounded(list, item, limit) {
|
|
351
|
+
return [item, ...(Array.isArray(list) ? list : [])].slice(0, limit);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function mergeUniqueByJson(list, incoming, limit) {
|
|
355
|
+
const seen = new Set();
|
|
356
|
+
const merged = [];
|
|
357
|
+
for (const item of [...(Array.isArray(incoming) ? incoming : []), ...(Array.isArray(list) ? list : [])]) {
|
|
358
|
+
if (!item) continue;
|
|
359
|
+
const key = JSON.stringify(item);
|
|
360
|
+
if (seen.has(key)) continue;
|
|
361
|
+
seen.add(key);
|
|
362
|
+
merged.push(item);
|
|
363
|
+
if (merged.length >= limit) break;
|
|
364
|
+
}
|
|
365
|
+
return merged;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function summarizeCognitionState(state) {
|
|
369
|
+
return {
|
|
370
|
+
telemetryTurns: Array.isArray(state.telemetry) ? state.telemetry.length : 0,
|
|
371
|
+
decisions: Array.isArray(state.decisions) ? state.decisions.length : 0,
|
|
372
|
+
evolutionPrinciples: Array.isArray(state.evolutionPrinciples) ? state.evolutionPrinciples.length : 0,
|
|
373
|
+
aegisPatterns: Array.isArray(state.aegisPatterns) ? state.aegisPatterns.length : 0,
|
|
374
|
+
heartbeats: Array.isArray(state.heartbeats) ? state.heartbeats.length : 0,
|
|
375
|
+
hive: Array.isArray(state.hive) ? state.hive.length : 0,
|
|
376
|
+
cognitiveStrings: Array.isArray(state.cognitiveStrings) ? state.cognitiveStrings.length : 0,
|
|
377
|
+
receipts: Array.isArray(state.receipts) ? state.receipts.length : 0,
|
|
378
|
+
lastUpdatedAt: state.lastUpdatedAt || null,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function mutateCognitionState(secret, mutator) {
|
|
383
|
+
const current = loadEncryptedCognitionState(secret);
|
|
384
|
+
const next = mutator({ ...current }) || current;
|
|
385
|
+
saveEncryptedCognitionState(next, secret);
|
|
386
|
+
return next;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function persistMizanBundle(secret, bundle, source = 'runtime') {
|
|
390
|
+
if (!bundle?.receipt) return null;
|
|
391
|
+
mutateCognitionState(secret, (state) => ({
|
|
392
|
+
...state,
|
|
393
|
+
receipts: appendBounded(state.receipts, {
|
|
394
|
+
at: new Date().toISOString(),
|
|
395
|
+
source,
|
|
396
|
+
summary: summarizeMizanBundle(bundle),
|
|
397
|
+
receipt: bundle.receipt,
|
|
398
|
+
contract: bundle.contract,
|
|
399
|
+
}, RECEIPT_LIMIT),
|
|
400
|
+
}));
|
|
401
|
+
return bundle.receipt;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function readJsonFile(filePath, fallback) {
|
|
405
|
+
try {
|
|
406
|
+
if (!existsSync(filePath)) return fallback;
|
|
407
|
+
return JSON.parse(readFileSync(filePath, 'utf8'));
|
|
408
|
+
} catch {
|
|
409
|
+
return fallback;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function writeJsonFile(filePath, payload, mode = 0o600) {
|
|
414
|
+
mkdirSync(STATE_DIR, { recursive: true, mode: 0o700 });
|
|
415
|
+
writeFileSync(filePath, JSON.stringify(payload, null, 2) + '\n', { mode });
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function ensureRuntimeMeta() {
|
|
419
|
+
const existing = readJsonFile(RUNTIME_META_PATH, null);
|
|
420
|
+
if (existing?.runtimeId) return existing;
|
|
421
|
+
|
|
422
|
+
const created = {
|
|
423
|
+
runtimeId: randomUUID(),
|
|
424
|
+
createdAt: new Date().toISOString(),
|
|
425
|
+
hostnameHint: process.env.HOSTNAME || null,
|
|
426
|
+
};
|
|
427
|
+
writeJsonFile(RUNTIME_META_PATH, created);
|
|
428
|
+
return created;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function loadAutonomyState() {
|
|
432
|
+
const state = readJsonFile(AUTONOMY_STATE_PATH, {
|
|
433
|
+
jobs: [],
|
|
434
|
+
workers: [],
|
|
435
|
+
});
|
|
436
|
+
return {
|
|
437
|
+
jobs: Array.isArray(state.jobs) ? state.jobs : [],
|
|
438
|
+
workers: Array.isArray(state.workers) ? state.workers : [],
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function saveAutonomyState(state) {
|
|
443
|
+
writeJsonFile(AUTONOMY_STATE_PATH, state);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function sweepAutonomyState(state) {
|
|
447
|
+
const now = Date.now();
|
|
448
|
+
|
|
449
|
+
for (const job of state.jobs) {
|
|
450
|
+
if (job.status === 'claimed' && job.claimExpiresAt && Date.parse(job.claimExpiresAt) <= now) {
|
|
451
|
+
job.status = 'queued';
|
|
452
|
+
job.workerId = null;
|
|
453
|
+
job.claimedAt = null;
|
|
454
|
+
job.claimExpiresAt = null;
|
|
455
|
+
job.updatedAt = new Date().toISOString();
|
|
456
|
+
job.progress = [...(job.progress || []), {
|
|
457
|
+
at: new Date().toISOString(),
|
|
458
|
+
status: 'lease-expired',
|
|
459
|
+
message: 'Claim lease expired; job returned to queue.',
|
|
460
|
+
}];
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
for (const worker of state.workers) {
|
|
465
|
+
if (worker.lastHeartbeat && Date.parse(worker.lastHeartbeat) < now - 3 * DEFAULT_JOB_CLAIM_SECONDS * 1000) {
|
|
466
|
+
worker.status = 'offline';
|
|
467
|
+
worker.currentJobId = null;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return state;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function queueStats(state) {
|
|
475
|
+
return {
|
|
476
|
+
queued: state.jobs.filter((job) => job.status === 'queued').length,
|
|
477
|
+
claimed: state.jobs.filter((job) => job.status === 'claimed').length,
|
|
478
|
+
completed: state.jobs.filter((job) => job.status === 'completed').length,
|
|
479
|
+
failed: state.jobs.filter((job) => job.status === 'failed').length,
|
|
480
|
+
workers: state.workers.length,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function asJsonPayload(value) {
|
|
485
|
+
if (value == null) return null;
|
|
486
|
+
if (typeof value === 'string') {
|
|
487
|
+
try {
|
|
488
|
+
return JSON.parse(value);
|
|
489
|
+
} catch {
|
|
490
|
+
return { raw: value };
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return value;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function getAutonomyView(state, limit = 50) {
|
|
497
|
+
const jobs = [...state.jobs]
|
|
498
|
+
.sort((a, b) => Date.parse(b.updatedAt || b.createdAt) - Date.parse(a.updatedAt || a.createdAt))
|
|
499
|
+
.slice(0, limit);
|
|
500
|
+
const workers = [...state.workers]
|
|
501
|
+
.sort((a, b) => Date.parse(b.lastHeartbeat || b.registeredAt) - Date.parse(a.lastHeartbeat || a.registeredAt));
|
|
502
|
+
return {
|
|
503
|
+
stats: queueStats(state),
|
|
504
|
+
jobs,
|
|
505
|
+
workers,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function resolveApiKey(req, body) {
|
|
510
|
+
const headerKey = req.headers['x-aria-api-key'];
|
|
511
|
+
if (typeof headerKey === 'string' && headerKey.trim()) return headerKey.trim();
|
|
512
|
+
if (typeof body.apiKey === 'string' && body.apiKey.trim()) return body.apiKey.trim();
|
|
513
|
+
return readBearer(req) || process.env.ARIA_API_KEY || process.env.ARIA_MASTER_TOKEN || null;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function createClient(req, body) {
|
|
517
|
+
const apiKey = resolveApiKey(req, body);
|
|
518
|
+
if (!apiKey) {
|
|
519
|
+
throw new Error('Missing Aria API key. Supply x-aria-api-key, Authorization: Bearer <token>, ARIA_API_KEY, or ARIA_MASTER_TOKEN.');
|
|
520
|
+
}
|
|
521
|
+
ensureNotRevoked(apiKey);
|
|
522
|
+
|
|
523
|
+
return new HTTPHarnessClient({
|
|
524
|
+
baseUrl: typeof body.baseUrl === 'string' && body.baseUrl.trim() ? body.baseUrl.trim() : DEFAULT_HARNESS_URL,
|
|
525
|
+
apiKey,
|
|
526
|
+
harnessPacketUrl:
|
|
527
|
+
typeof body.harnessPacketUrl === 'string' && body.harnessPacketUrl.trim()
|
|
528
|
+
? body.harnessPacketUrl.trim()
|
|
529
|
+
: undefined,
|
|
530
|
+
workspaceRoot:
|
|
531
|
+
typeof body.workspaceRoot === 'string' && body.workspaceRoot.trim()
|
|
532
|
+
? body.workspaceRoot.trim()
|
|
533
|
+
: process.cwd(),
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
async function heartbeatUpstream(req, body, client, apiKey) {
|
|
538
|
+
const runtimeMeta = ensureRuntimeMeta();
|
|
539
|
+
const state = sweepAutonomyState(loadAutonomyState());
|
|
540
|
+
const heartbeatBody = {
|
|
541
|
+
token: apiKey,
|
|
542
|
+
surface:
|
|
543
|
+
body.surface ||
|
|
544
|
+
req.headers['x-aria-client-surface'] ||
|
|
545
|
+
'aria-mounted-runtime',
|
|
546
|
+
hive: body.hive || null,
|
|
547
|
+
cognitive_strings: body.cognitiveStrings || body.cognitive_strings || null,
|
|
548
|
+
evolution: body.evolution || null,
|
|
549
|
+
aegis_patterns: body.aegisPatterns || body.aegis_patterns || null,
|
|
550
|
+
telemetry: body.telemetry || null,
|
|
551
|
+
metadata: {
|
|
552
|
+
runtime_id: runtimeMeta.runtimeId,
|
|
553
|
+
runtime: 'aria-mounted-runtime',
|
|
554
|
+
runtime_url: DEFAULT_RUNTIME_URL,
|
|
555
|
+
workspace_root: body.workspaceRoot || process.cwd(),
|
|
556
|
+
autonomy: queueStats(state),
|
|
557
|
+
},
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
const ownerBypassAllowed =
|
|
561
|
+
readOwnerToken() &&
|
|
562
|
+
apiKey === readOwnerToken() &&
|
|
563
|
+
body.allowOwnerBypass !== false &&
|
|
564
|
+
process.env.ARIA_RUNTIME_ALLOW_OWNER_BYPASS !== '0';
|
|
565
|
+
|
|
566
|
+
let lease;
|
|
567
|
+
try {
|
|
568
|
+
const response = await fetch(`${client.baseUrl || DEFAULT_HARNESS_URL}/api/license/heartbeat`, {
|
|
569
|
+
method: 'POST',
|
|
570
|
+
headers: {
|
|
571
|
+
Authorization: `Bearer ${apiKey}`,
|
|
572
|
+
'Content-Type': 'application/json',
|
|
573
|
+
},
|
|
574
|
+
body: JSON.stringify(heartbeatBody),
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
const payload = await response.json().catch(() => ({}));
|
|
578
|
+
if (response.status === 410) {
|
|
579
|
+
writeRevocationLock({
|
|
580
|
+
keyHash: hashKey(apiKey),
|
|
581
|
+
reason: payload.reason || 'License revoked',
|
|
582
|
+
responseStatus: response.status,
|
|
583
|
+
});
|
|
584
|
+
const error = new Error(payload.reason || 'License revoked');
|
|
585
|
+
error.code = 'LICENSE_REVOKED';
|
|
586
|
+
throw error;
|
|
587
|
+
}
|
|
588
|
+
if (!response.ok || payload.valid === false) {
|
|
589
|
+
const error = new Error(payload.reason || `License heartbeat failed (${response.status})`);
|
|
590
|
+
error.code = 'LICENSE_INVALID';
|
|
591
|
+
throw error;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const recommended = Number(payload.recommended_heartbeat_seconds || 300);
|
|
595
|
+
lease = {
|
|
596
|
+
keyHash: hashKey(apiKey),
|
|
597
|
+
validatedAt: new Date().toISOString(),
|
|
598
|
+
recommendedHeartbeatSeconds: recommended,
|
|
599
|
+
graceSeconds: DEFAULT_HEARTBEAT_GRACE_SECONDS,
|
|
600
|
+
nextRequiredAt: Date.now() + recommended * 1000,
|
|
601
|
+
hardStopAt: Date.now() + (recommended + DEFAULT_HEARTBEAT_GRACE_SECONDS) * 1000,
|
|
602
|
+
claims: {
|
|
603
|
+
tenant_id: payload.tenant_id || null,
|
|
604
|
+
tier: payload.tier || null,
|
|
605
|
+
expires_at: payload.expires_at || null,
|
|
606
|
+
feature_flags: payload.feature_flags || [],
|
|
607
|
+
scope: payload.scope || [],
|
|
608
|
+
quota: payload.quota || null,
|
|
609
|
+
doctrine_bundle_hash: payload.doctrine_bundle_hash || null,
|
|
610
|
+
},
|
|
611
|
+
};
|
|
612
|
+
clearRevocationLock();
|
|
613
|
+
} catch (error) {
|
|
614
|
+
if (!ownerBypassAllowed) {
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
lease = synthesizeOwnerLease(
|
|
618
|
+
apiKey,
|
|
619
|
+
error instanceof Error ? error.message : 'owner bypass',
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
leaseCache.set(lease.keyHash, lease);
|
|
624
|
+
saveEncryptedLease(lease, apiKey);
|
|
625
|
+
mutateCognitionState(apiKey, (state) => {
|
|
626
|
+
const base = {
|
|
627
|
+
...state,
|
|
628
|
+
heartbeats: appendBounded(state.heartbeats, {
|
|
629
|
+
at: new Date().toISOString(),
|
|
630
|
+
lease,
|
|
631
|
+
hive: body.hive || null,
|
|
632
|
+
cognitive_strings: body.cognitiveStrings || body.cognitive_strings || null,
|
|
633
|
+
evolution: body.evolution || null,
|
|
634
|
+
aegis_patterns: body.aegisPatterns || body.aegis_patterns || null,
|
|
635
|
+
telemetry: body.telemetry || null,
|
|
636
|
+
}, TELEMETRY_LIMIT),
|
|
637
|
+
};
|
|
638
|
+
if (body.skipLocalStateWrite === true) {
|
|
639
|
+
return base;
|
|
640
|
+
}
|
|
641
|
+
return {
|
|
642
|
+
...base,
|
|
643
|
+
hive: body.hive ? appendBounded(state.hive, { at: new Date().toISOString(), payload: body.hive }, TELEMETRY_LIMIT) : state.hive,
|
|
644
|
+
cognitiveStrings: body.cognitiveStrings || body.cognitive_strings
|
|
645
|
+
? appendBounded(state.cognitiveStrings, {
|
|
646
|
+
at: new Date().toISOString(),
|
|
647
|
+
payload: body.cognitiveStrings || body.cognitive_strings,
|
|
648
|
+
}, TELEMETRY_LIMIT)
|
|
649
|
+
: state.cognitiveStrings,
|
|
650
|
+
evolutionPrinciples: body.evolution
|
|
651
|
+
? mergeUniqueByJson(state.evolutionPrinciples, Array.isArray(body.evolution) ? body.evolution : [body.evolution], PRINCIPLE_LIMIT)
|
|
652
|
+
: state.evolutionPrinciples,
|
|
653
|
+
aegisPatterns: body.aegisPatterns || body.aegis_patterns
|
|
654
|
+
? mergeUniqueByJson(state.aegisPatterns, Array.isArray(body.aegisPatterns || body.aegis_patterns) ? (body.aegisPatterns || body.aegis_patterns) : [body.aegisPatterns || body.aegis_patterns], PATTERN_LIMIT)
|
|
655
|
+
: state.aegisPatterns,
|
|
656
|
+
};
|
|
657
|
+
});
|
|
658
|
+
return lease;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
async function ensureLease(req, body, client) {
|
|
662
|
+
const apiKey = resolveApiKey(req, body);
|
|
663
|
+
if (!apiKey) {
|
|
664
|
+
throw new Error('Missing Aria API key for heartbeat validation');
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const keyHash = hashKey(apiKey);
|
|
668
|
+
const cached = leaseCache.get(keyHash) || loadEncryptedLease(apiKey);
|
|
669
|
+
if (cached && cached.hardStopAt > Date.now()) {
|
|
670
|
+
leaseCache.set(keyHash, cached);
|
|
671
|
+
if (cached.nextRequiredAt > Date.now()) {
|
|
672
|
+
return cached;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
return heartbeatUpstream(req, body, client, apiKey);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function deriveSessionId(req, body, prefix = 'runtime') {
|
|
680
|
+
const candidate =
|
|
681
|
+
body.sessionId ||
|
|
682
|
+
body.session_id ||
|
|
683
|
+
body?.metadata?.sessionId ||
|
|
684
|
+
body?.metadata?.session_id ||
|
|
685
|
+
req.headers['x-aria-session-id'] ||
|
|
686
|
+
req.headers['x-session-id'];
|
|
687
|
+
if (typeof candidate === 'string' && candidate.trim()) return candidate.trim();
|
|
688
|
+
return `${prefix}-${Date.now().toString(36)}-${randomUUID().slice(0, 8)}`;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function deriveUserId(req, body) {
|
|
692
|
+
const candidate =
|
|
693
|
+
body.userId ||
|
|
694
|
+
body.user_id ||
|
|
695
|
+
body?.metadata?.userId ||
|
|
696
|
+
body?.metadata?.user_id ||
|
|
697
|
+
req.headers['x-aria-user-id'];
|
|
698
|
+
return typeof candidate === 'string' && candidate.trim() ? candidate.trim() : null;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function findVerifiedState(text) {
|
|
702
|
+
return /(?:verified|confirmed|observed|tested|health[- ]check|response code|exit code|pod image|digest)/i.test(String(text || ''));
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function toTelemetryEvent(payload, source = 'aria-mounted-runtime') {
|
|
706
|
+
return {
|
|
707
|
+
event_type: payload.event_type || 'runtime.cognition.turn',
|
|
708
|
+
source,
|
|
709
|
+
session_id: payload.session_id || null,
|
|
710
|
+
duration_ms: payload.duration_ms || null,
|
|
711
|
+
success: payload.success !== false,
|
|
712
|
+
error: payload.error || null,
|
|
713
|
+
data: payload.data || {},
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
async function pushTelemetryUpstream(client, apiKey, payload) {
|
|
718
|
+
const url = `${client.baseUrl || DEFAULT_HARNESS_URL}/api/telemetry`;
|
|
719
|
+
const response = await fetch(url, {
|
|
720
|
+
method: 'POST',
|
|
721
|
+
headers: {
|
|
722
|
+
Authorization: `Bearer ${apiKey}`,
|
|
723
|
+
'Content-Type': 'application/json',
|
|
724
|
+
},
|
|
725
|
+
body: JSON.stringify([toTelemetryEvent(payload)]),
|
|
726
|
+
});
|
|
727
|
+
if (!response.ok) {
|
|
728
|
+
const body = await response.text().catch(() => response.statusText);
|
|
729
|
+
throw new Error(`telemetry upstream ${response.status}: ${body}`);
|
|
730
|
+
}
|
|
731
|
+
return response.json().catch(() => ({ logged: true }));
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
async function pushDecisionUpstream(client, apiKey, payload) {
|
|
735
|
+
const url = `${client.baseUrl || DEFAULT_HARNESS_URL}/api/decisions/log`;
|
|
736
|
+
const response = await fetch(url, {
|
|
737
|
+
method: 'POST',
|
|
738
|
+
headers: {
|
|
739
|
+
Authorization: `Bearer ${apiKey}`,
|
|
740
|
+
'Content-Type': 'application/json',
|
|
741
|
+
},
|
|
742
|
+
body: JSON.stringify(payload),
|
|
743
|
+
});
|
|
744
|
+
if (!response.ok) {
|
|
745
|
+
const body = await response.text().catch(() => response.statusText);
|
|
746
|
+
throw new Error(`decision upstream ${response.status}: ${body}`);
|
|
747
|
+
}
|
|
748
|
+
return response.json().catch(() => ({ logged: true }));
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
function buildMinimalInjection(packet, task, aegisLearnings = null) {
|
|
752
|
+
return {
|
|
753
|
+
harness: packet,
|
|
754
|
+
docs: [],
|
|
755
|
+
files: {},
|
|
756
|
+
task,
|
|
757
|
+
loadedAt: new Date().toISOString(),
|
|
758
|
+
...(aegisLearnings ? { aegisLearnings } : {}),
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function isOwnerBypassRequest(req, body, apiKey = null) {
|
|
763
|
+
const ownerToken = readOwnerToken();
|
|
764
|
+
const candidate = apiKey || resolveApiKey(req, body) || '';
|
|
765
|
+
return Boolean(
|
|
766
|
+
ownerToken &&
|
|
767
|
+
candidate &&
|
|
768
|
+
candidate === ownerToken &&
|
|
769
|
+
body.allowOwnerBypass !== false &&
|
|
770
|
+
process.env.ARIA_RUNTIME_ALLOW_OWNER_BYPASS !== '0',
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function buildOwnerBypassPacket(message, reason = 'owner-local-bypass') {
|
|
775
|
+
const firstPrinciple = 'Truth over deception. No harm. Sacred trust. Power obligates service. Reflection before action.';
|
|
776
|
+
return {
|
|
777
|
+
packet: {
|
|
778
|
+
harness: [
|
|
779
|
+
`first_principle = ${firstPrinciple}`,
|
|
780
|
+
'axioms = truth_over_deception, no_harm, sacred_trust, power_obligates_service, reflection_before_action',
|
|
781
|
+
`owner_bypass_reason = ${reason}`,
|
|
782
|
+
'runtime_mode = owner-local-bypass',
|
|
783
|
+
].join('\n'),
|
|
784
|
+
axioms: {
|
|
785
|
+
truth_over_deception: true,
|
|
786
|
+
no_harm: true,
|
|
787
|
+
sacred_trust: true,
|
|
788
|
+
power_obligates_service: true,
|
|
789
|
+
reflection_before_action: true,
|
|
790
|
+
},
|
|
791
|
+
frames: {
|
|
792
|
+
first_principle: firstPrinciple,
|
|
793
|
+
runtime_mode: 'owner-local-bypass',
|
|
794
|
+
message: message || '',
|
|
795
|
+
},
|
|
796
|
+
doctrine: {
|
|
797
|
+
owner_local_bypass: 'Using local runtime doctrine because remote packet auth is unavailable.',
|
|
798
|
+
},
|
|
799
|
+
memory: {},
|
|
800
|
+
},
|
|
801
|
+
timestamp: new Date().toISOString(),
|
|
802
|
+
version: 'owner-local-bypass',
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
async function loadRuntimePacket(req, body, client, packetRequest, message) {
|
|
807
|
+
if (body.packet) return body.packet;
|
|
808
|
+
try {
|
|
809
|
+
return await client.getHarnessPacket(packetRequest || {});
|
|
810
|
+
} catch (error) {
|
|
811
|
+
if (!isOwnerBypassRequest(req, body)) {
|
|
812
|
+
throw error;
|
|
813
|
+
}
|
|
814
|
+
return buildOwnerBypassPacket(
|
|
815
|
+
message || packetRequest?.message || '',
|
|
816
|
+
error instanceof Error ? error.message : 'owner-local-bypass',
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
async function buildRuntimeTurnContext(req, body, client) {
|
|
822
|
+
const sessionId = deriveSessionId(req, body, body.provider === 'anthropic' ? 'anthropic' : 'openai');
|
|
823
|
+
const userId = deriveUserId(req, body);
|
|
824
|
+
const userMessage = Array.isArray(body.messages)
|
|
825
|
+
? (body.provider === 'anthropic' ? extractAnthropicUserMessage(body.messages) : extractOpenAIUserMessage(body.messages))
|
|
826
|
+
: '';
|
|
827
|
+
const plannedApproach =
|
|
828
|
+
typeof body.ariaPlannedApproach === 'string' && body.ariaPlannedApproach.trim()
|
|
829
|
+
? body.ariaPlannedApproach.trim()
|
|
830
|
+
: 'Bind to the harness packet, reason through Aristotle and Noor cognitives, avoid unsupported state claims, and emit only what survives validation.';
|
|
831
|
+
const packetRequest = {
|
|
832
|
+
sessionId,
|
|
833
|
+
userId,
|
|
834
|
+
platform: body.platform || body.client || 'mounted-runtime',
|
|
835
|
+
system: 'aria-mounted-runtime',
|
|
836
|
+
stage: 'runtime-proxy',
|
|
837
|
+
message: userMessage,
|
|
838
|
+
...(body.packetRequest && typeof body.packetRequest === 'object' ? body.packetRequest : {}),
|
|
839
|
+
};
|
|
840
|
+
const packet = await loadRuntimePacket(req, body, client, packetRequest, userMessage);
|
|
841
|
+
const runtimeId = ensureRuntimeMeta().runtimeId;
|
|
842
|
+
const turnClass = classifyTurn({
|
|
843
|
+
message: userMessage,
|
|
844
|
+
intendedAction: userMessage,
|
|
845
|
+
rationale: body.ariaRationale || 'Produce a truthful, substrate-bound answer that survives validation and compounds into the hive.',
|
|
846
|
+
plannedApproach,
|
|
847
|
+
domains: body.ariaDomains,
|
|
848
|
+
});
|
|
849
|
+
const preBundle = evaluateMizanPre(packet, {
|
|
850
|
+
sessionId,
|
|
851
|
+
userId,
|
|
852
|
+
message: userMessage,
|
|
853
|
+
intendedAction: userMessage,
|
|
854
|
+
rationale: body.ariaRationale || 'Produce a truthful, substrate-bound answer that survives validation and compounds into the hive.',
|
|
855
|
+
plannedApproach,
|
|
856
|
+
domains: body.ariaDomains,
|
|
857
|
+
}, {
|
|
858
|
+
sessionId,
|
|
859
|
+
runtimeId,
|
|
860
|
+
});
|
|
861
|
+
const midBundle = evaluateMizanMid(userMessage, plannedApproach, packet, {
|
|
862
|
+
sessionId,
|
|
863
|
+
userId,
|
|
864
|
+
message: userMessage,
|
|
865
|
+
plannedApproach,
|
|
866
|
+
rationale: body.ariaRationale || 'Produce a truthful, substrate-bound answer that survives validation and compounds into the hive.',
|
|
867
|
+
domains: body.ariaDomains,
|
|
868
|
+
}, {
|
|
869
|
+
sessionId,
|
|
870
|
+
runtimeId,
|
|
871
|
+
parentReceiptId: preBundle.receipt.receiptId,
|
|
872
|
+
});
|
|
873
|
+
const aegisLearnings = await client.getAegisLearnings(12).catch(() => null);
|
|
874
|
+
const basePrompt = client.buildSystemPrompt(buildMinimalInjection(packet, userMessage || 'Aria runtime turn', aegisLearnings));
|
|
875
|
+
const cognitionDirective = buildRuntimeCognitionDirective(packet, {
|
|
876
|
+
preResult: preBundle.result,
|
|
877
|
+
midResult: midBundle.result,
|
|
878
|
+
});
|
|
879
|
+
const ariaSystemPrompt = [basePrompt, '', cognitionDirective].join('\n');
|
|
880
|
+
return {
|
|
881
|
+
sessionId,
|
|
882
|
+
userId,
|
|
883
|
+
userMessage,
|
|
884
|
+
plannedApproach,
|
|
885
|
+
packet,
|
|
886
|
+
packetBypassed: packet?.version === 'owner-local-bypass',
|
|
887
|
+
turnClass,
|
|
888
|
+
operatorPlan: buildOperatorPlan(turnClass, 'pre'),
|
|
889
|
+
preResult: preBundle.result,
|
|
890
|
+
preBundle,
|
|
891
|
+
preReceipt: preBundle.receipt,
|
|
892
|
+
preContract: preBundle.contract,
|
|
893
|
+
midResult: midBundle.result,
|
|
894
|
+
midBundle,
|
|
895
|
+
midReceipt: midBundle.receipt,
|
|
896
|
+
midContract: midBundle.contract,
|
|
897
|
+
aegisLearnings,
|
|
898
|
+
ariaSystemPrompt,
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
async function buildDirectTurnContext(req, body, client, options = {}) {
|
|
903
|
+
const sessionId =
|
|
904
|
+
typeof body.sessionId === 'string' && body.sessionId.trim()
|
|
905
|
+
? body.sessionId.trim()
|
|
906
|
+
: deriveSessionId(req, body, options.prefix || 'runtime');
|
|
907
|
+
const userId =
|
|
908
|
+
typeof body.userId === 'string' && body.userId.trim()
|
|
909
|
+
? body.userId.trim()
|
|
910
|
+
: deriveUserId(req, body);
|
|
911
|
+
const userMessage = typeof body.message === 'string' ? body.message : '';
|
|
912
|
+
const plannedApproach =
|
|
913
|
+
typeof body.ariaPlannedApproach === 'string' && body.ariaPlannedApproach.trim()
|
|
914
|
+
? body.ariaPlannedApproach.trim()
|
|
915
|
+
: options.defaultPlannedApproach ||
|
|
916
|
+
'Bind this turn to the packet, run readable Aristotle and Noor cognition, and compound the result into the hive.';
|
|
917
|
+
const packetRequest = {
|
|
918
|
+
sessionId,
|
|
919
|
+
userId,
|
|
920
|
+
platform: body.platform || body.client || options.platform || 'mounted-runtime',
|
|
921
|
+
system: 'aria-mounted-runtime',
|
|
922
|
+
stage: options.stage || 'runtime-direct',
|
|
923
|
+
message: userMessage,
|
|
924
|
+
...(body.packetRequest && typeof body.packetRequest === 'object' ? body.packetRequest : {}),
|
|
925
|
+
};
|
|
926
|
+
const packet = await loadRuntimePacket(req, body, client, packetRequest, userMessage);
|
|
927
|
+
const runtimeId = ensureRuntimeMeta().runtimeId;
|
|
928
|
+
const rationale =
|
|
929
|
+
body.ariaRationale ||
|
|
930
|
+
options.defaultRationale ||
|
|
931
|
+
'Capture this turn truthfully, preserve cognitive continuity, and write it into the shared Aria substrate.';
|
|
932
|
+
const turnClass = classifyTurn({
|
|
933
|
+
message: userMessage,
|
|
934
|
+
intendedAction: userMessage,
|
|
935
|
+
plannedApproach,
|
|
936
|
+
rationale,
|
|
937
|
+
domains: body.ariaDomains,
|
|
938
|
+
});
|
|
939
|
+
const preBundle = evaluateMizanPre(packet, {
|
|
940
|
+
sessionId,
|
|
941
|
+
userId,
|
|
942
|
+
message: userMessage,
|
|
943
|
+
intendedAction: userMessage,
|
|
944
|
+
rationale,
|
|
945
|
+
plannedApproach,
|
|
946
|
+
domains: body.ariaDomains,
|
|
947
|
+
}, {
|
|
948
|
+
sessionId,
|
|
949
|
+
runtimeId,
|
|
950
|
+
});
|
|
951
|
+
const midBundle = evaluateMizanMid(userMessage, plannedApproach, packet, {
|
|
952
|
+
sessionId,
|
|
953
|
+
userId,
|
|
954
|
+
message: userMessage,
|
|
955
|
+
plannedApproach,
|
|
956
|
+
rationale,
|
|
957
|
+
domains: body.ariaDomains,
|
|
958
|
+
}, {
|
|
959
|
+
sessionId,
|
|
960
|
+
runtimeId,
|
|
961
|
+
parentReceiptId: preBundle.receipt.receiptId,
|
|
962
|
+
});
|
|
963
|
+
return {
|
|
964
|
+
sessionId,
|
|
965
|
+
userId,
|
|
966
|
+
userMessage,
|
|
967
|
+
plannedApproach,
|
|
968
|
+
packet,
|
|
969
|
+
packetBypassed: packet?.version === 'owner-local-bypass',
|
|
970
|
+
turnClass,
|
|
971
|
+
operatorPlan: buildOperatorPlan(turnClass, 'pre'),
|
|
972
|
+
preResult: preBundle.result,
|
|
973
|
+
preBundle,
|
|
974
|
+
preReceipt: preBundle.receipt,
|
|
975
|
+
preContract: preBundle.contract,
|
|
976
|
+
midResult: midBundle.result,
|
|
977
|
+
midBundle,
|
|
978
|
+
midReceipt: midBundle.receipt,
|
|
979
|
+
midContract: midBundle.contract,
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function openAiResponseEnvelope(body, text, providerMeta, extra = {}) {
|
|
984
|
+
const debug = body?.ariaDebug === true;
|
|
985
|
+
return {
|
|
986
|
+
id: `chatcmpl_${randomUUID().replace(/-/g, '')}`,
|
|
987
|
+
object: 'chat.completion',
|
|
988
|
+
created: Math.floor(Date.now() / 1000),
|
|
989
|
+
model: providerMeta.model,
|
|
990
|
+
choices: [
|
|
991
|
+
{
|
|
992
|
+
index: 0,
|
|
993
|
+
finish_reason: providerMeta.finishReason || 'stop',
|
|
994
|
+
message: {
|
|
995
|
+
role: 'assistant',
|
|
996
|
+
content: text,
|
|
997
|
+
},
|
|
998
|
+
},
|
|
999
|
+
],
|
|
1000
|
+
usage: providerMeta.usage
|
|
1001
|
+
? {
|
|
1002
|
+
prompt_tokens: providerMeta.usage.promptTokens || 0,
|
|
1003
|
+
completion_tokens: providerMeta.usage.completionTokens || 0,
|
|
1004
|
+
total_tokens: (providerMeta.usage.promptTokens || 0) + (providerMeta.usage.completionTokens || 0),
|
|
1005
|
+
}
|
|
1006
|
+
: undefined,
|
|
1007
|
+
aria: buildReadableAriaEnvelope(extra, debug),
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
function anthropicResponseEnvelope(text, providerMeta, extra = {}, debug = false) {
|
|
1012
|
+
return {
|
|
1013
|
+
id: `msg_${randomUUID().replace(/-/g, '')}`,
|
|
1014
|
+
type: 'message',
|
|
1015
|
+
role: 'assistant',
|
|
1016
|
+
model: providerMeta.model,
|
|
1017
|
+
stop_reason: providerMeta.finishReason || 'end_turn',
|
|
1018
|
+
content: [{ type: 'text', text }],
|
|
1019
|
+
usage: providerMeta.usage
|
|
1020
|
+
? {
|
|
1021
|
+
input_tokens: providerMeta.usage.promptTokens || 0,
|
|
1022
|
+
output_tokens: providerMeta.usage.completionTokens || 0,
|
|
1023
|
+
}
|
|
1024
|
+
: undefined,
|
|
1025
|
+
aria: buildReadableAriaEnvelope(extra, debug),
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
function toReadableSignal(name) {
|
|
1030
|
+
const map = {
|
|
1031
|
+
fitrah_gate: 'truth boundary',
|
|
1032
|
+
truth_lens: 'truth check',
|
|
1033
|
+
harm_lens: 'harm check',
|
|
1034
|
+
trust_lens: 'trust boundary',
|
|
1035
|
+
power_lens: 'impact check',
|
|
1036
|
+
reflection_lens: 'reflection pass',
|
|
1037
|
+
tafakkur: 'deep analysis',
|
|
1038
|
+
tadabbur: 'consequence mapping',
|
|
1039
|
+
qiyas: 'analogy transfer',
|
|
1040
|
+
istiqra: 'pattern induction',
|
|
1041
|
+
self_reflection: 'self-check',
|
|
1042
|
+
predictor: 'next-step forecast',
|
|
1043
|
+
meta_cognition: 'meta-cognition',
|
|
1044
|
+
mizan: 'quality balance',
|
|
1045
|
+
nur: 'direct read',
|
|
1046
|
+
firasah: 'discernment',
|
|
1047
|
+
ghazali_8_lens: 'quality scrutiny',
|
|
1048
|
+
quality_gate: 'quality gate',
|
|
1049
|
+
evolution_distill: 'evolution distill',
|
|
1050
|
+
aegis_pattern_match: 'risk pattern match',
|
|
1051
|
+
noor_recognition: 'recognition pull',
|
|
1052
|
+
forge_primitive_planner: 'tool planning',
|
|
1053
|
+
};
|
|
1054
|
+
return map[name] || String(name || '').replace(/_/g, ' ');
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function summarizePhaseResult(phase, result) {
|
|
1058
|
+
if (!result) return null;
|
|
1059
|
+
const notes = Array.isArray(result.notes) ? result.notes.filter(Boolean) : [];
|
|
1060
|
+
const fired = Array.isArray(result.fired) ? result.fired.filter(Boolean) : [];
|
|
1061
|
+
return {
|
|
1062
|
+
phase,
|
|
1063
|
+
blocked: Boolean(result.fitrahVetoed || result.reAuthorSignal),
|
|
1064
|
+
alignment: result.fitrahAlignment == null ? null : Math.round(Number(result.fitrahAlignment) * 100),
|
|
1065
|
+
quality: result.qualityScore == null ? null : Number(result.qualityScore),
|
|
1066
|
+
signals: fired.slice(0, 6).map(toReadableSignal),
|
|
1067
|
+
summary: notes.slice(0, 3).join(' | ') || null,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
function buildReadableAriaEnvelope(extra = {}, debug = false) {
|
|
1072
|
+
const phases = [
|
|
1073
|
+
summarizePhaseResult('pre', extra.pre),
|
|
1074
|
+
summarizePhaseResult('mid', extra.mid),
|
|
1075
|
+
summarizePhaseResult('post', extra.post),
|
|
1076
|
+
].filter(Boolean);
|
|
1077
|
+
const receipts = extra.receipts ? {
|
|
1078
|
+
pre: extra.receipts.pre ? {
|
|
1079
|
+
id: extra.receipts.pre.receiptId,
|
|
1080
|
+
blocked: Boolean(extra.receipts.pre.blocked),
|
|
1081
|
+
turnClass: extra.receipts.pre.turnClass,
|
|
1082
|
+
quality: extra.receipts.pre.qualityScore,
|
|
1083
|
+
} : null,
|
|
1084
|
+
mid: extra.receipts.mid ? {
|
|
1085
|
+
id: extra.receipts.mid.receiptId,
|
|
1086
|
+
blocked: Boolean(extra.receipts.mid.blocked),
|
|
1087
|
+
turnClass: extra.receipts.mid.turnClass,
|
|
1088
|
+
quality: extra.receipts.mid.qualityScore,
|
|
1089
|
+
} : null,
|
|
1090
|
+
post: extra.receipts.post ? {
|
|
1091
|
+
id: extra.receipts.post.receiptId,
|
|
1092
|
+
blocked: Boolean(extra.receipts.post.blocked),
|
|
1093
|
+
turnClass: extra.receipts.post.turnClass,
|
|
1094
|
+
quality: extra.receipts.post.qualityScore,
|
|
1095
|
+
} : null,
|
|
1096
|
+
} : null;
|
|
1097
|
+
|
|
1098
|
+
const validation = extra.validation ? {
|
|
1099
|
+
severity: extra.validation.severity,
|
|
1100
|
+
issues: Array.isArray(extra.validation.violations) ? extra.validation.violations.slice(0, 3) : [],
|
|
1101
|
+
rewritten: Boolean(extra.validation.rewritten),
|
|
1102
|
+
} : null;
|
|
1103
|
+
|
|
1104
|
+
const layer3 = extra.layer3 ? {
|
|
1105
|
+
pass: extra.layer3.pass !== false,
|
|
1106
|
+
blockers: Array.isArray(extra.layer3.failures)
|
|
1107
|
+
? extra.layer3.failures
|
|
1108
|
+
.filter((failure) => failure?.severity === 'block')
|
|
1109
|
+
.slice(0, 3)
|
|
1110
|
+
.map((failure) => failure.detail || failure.kind || 'runtime block')
|
|
1111
|
+
: [],
|
|
1112
|
+
} : null;
|
|
1113
|
+
|
|
1114
|
+
const envelope = {
|
|
1115
|
+
blocked: Boolean(extra.blocked),
|
|
1116
|
+
control_plane: 'aria-mounted-runtime',
|
|
1117
|
+
principle: extra.pre?.firstPrincipleText || null,
|
|
1118
|
+
phases,
|
|
1119
|
+
turn_class: extra.turnClass ? {
|
|
1120
|
+
kind: extra.turnClass.kind,
|
|
1121
|
+
intensity: extra.turnClass.intensity,
|
|
1122
|
+
domains: extra.turnClass.domains,
|
|
1123
|
+
} : null,
|
|
1124
|
+
operator_plan: extra.operatorPlan ? {
|
|
1125
|
+
packs: extra.operatorPlan.requiredPacks,
|
|
1126
|
+
operators: extra.operatorPlan.priorityOperators,
|
|
1127
|
+
} : null,
|
|
1128
|
+
receipts,
|
|
1129
|
+
validation,
|
|
1130
|
+
layer3,
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
if (debug) {
|
|
1134
|
+
envelope.raw = extra;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
return envelope;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
function coerceNonEmptyString(value) {
|
|
1141
|
+
return typeof value === 'string' && value.trim() ? value.trim() : '';
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
function extractJsonObject(text) {
|
|
1145
|
+
const raw = String(text || '').trim();
|
|
1146
|
+
if (!raw) {
|
|
1147
|
+
throw new Error('planner returned empty output');
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
return JSON.parse(raw);
|
|
1151
|
+
} catch {}
|
|
1152
|
+
|
|
1153
|
+
const fenced = raw.match(/```(?:json)?\s*([\s\S]+?)```/i);
|
|
1154
|
+
if (fenced?.[1]) {
|
|
1155
|
+
try {
|
|
1156
|
+
return JSON.parse(fenced[1].trim());
|
|
1157
|
+
} catch {}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
const first = raw.indexOf('{');
|
|
1161
|
+
const last = raw.lastIndexOf('}');
|
|
1162
|
+
if (first >= 0 && last > first) {
|
|
1163
|
+
return JSON.parse(raw.slice(first, last + 1));
|
|
1164
|
+
}
|
|
1165
|
+
throw new Error('planner output did not contain valid JSON');
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function compactCodebaseSnapshot() {
|
|
1169
|
+
const config = readLocalAriaConfig();
|
|
1170
|
+
const awareness = readCodebaseAwarenessState();
|
|
1171
|
+
const repositories = Array.isArray(config.repositories) ? config.repositories : [];
|
|
1172
|
+
const schemaImages = config.schemaImages && typeof config.schemaImages === 'object'
|
|
1173
|
+
? config.schemaImages
|
|
1174
|
+
: {};
|
|
1175
|
+
const repoSnapshots = Array.isArray(awareness.repoSnapshots) ? awareness.repoSnapshots : [];
|
|
1176
|
+
return {
|
|
1177
|
+
repositories: repositories.slice(0, 6).map((repo) => ({
|
|
1178
|
+
name: repo?.name || null,
|
|
1179
|
+
path: repo?.path || null,
|
|
1180
|
+
language: repo?.language || null,
|
|
1181
|
+
packageManager: repo?.packageManager || null,
|
|
1182
|
+
entry: repo?.entry || null,
|
|
1183
|
+
})),
|
|
1184
|
+
schemaImages,
|
|
1185
|
+
awareness: {
|
|
1186
|
+
status: awareness.status || 'idle',
|
|
1187
|
+
updatedAt: awareness.updatedAt || null,
|
|
1188
|
+
repoSnapshots: repoSnapshots.slice(0, 4).map((repo) => ({
|
|
1189
|
+
repoName: repo?.repoName || repo?.name || null,
|
|
1190
|
+
filesIndexed: repo?.filesIndexed || repo?.fileCount || null,
|
|
1191
|
+
symbolsIndexed: repo?.symbolsIndexed || null,
|
|
1192
|
+
routesIndexed: repo?.routesIndexed || null,
|
|
1193
|
+
summary: repo?.summary || null,
|
|
1194
|
+
})),
|
|
1195
|
+
},
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function buildForgePlannerPrompt(turn, body) {
|
|
1200
|
+
const requestedDomain = coerceNonEmptyString(body.domain) || 'general';
|
|
1201
|
+
const codebase = compactCodebaseSnapshot();
|
|
1202
|
+
const requestShape = {
|
|
1203
|
+
user_goal: turn.userMessage,
|
|
1204
|
+
requested_domain: requestedDomain,
|
|
1205
|
+
requested_paths: Array.isArray(body.paths) ? body.paths.slice(0, 24) : [],
|
|
1206
|
+
constraints: Array.isArray(body.constraints) ? body.constraints.slice(0, 24) : [],
|
|
1207
|
+
desired_outputs: Array.isArray(body.outputs) ? body.outputs.slice(0, 24) : [],
|
|
1208
|
+
materialize: body.materialize !== false,
|
|
1209
|
+
audit: body.audit !== false,
|
|
1210
|
+
codebase,
|
|
1211
|
+
};
|
|
1212
|
+
return [
|
|
1213
|
+
'You are the Aria Forge planning head. Produce a strict JSON manifest for Forge PSI.',
|
|
1214
|
+
'Do not write code. Do not explain yourself. Return JSON only.',
|
|
1215
|
+
'The manifest must be readable and operational, not abstract.',
|
|
1216
|
+
'Use plain labels. Do not expose internal cognition IP names in user-facing summary fields.',
|
|
1217
|
+
'Required JSON keys:',
|
|
1218
|
+
'- normalizedIntent: string',
|
|
1219
|
+
'- domain: string',
|
|
1220
|
+
'- manifestSummary: string',
|
|
1221
|
+
'- requestedArtifacts: string[]',
|
|
1222
|
+
'- constraints: string[]',
|
|
1223
|
+
'- paths: string[]',
|
|
1224
|
+
'- implementationPlan: string[]',
|
|
1225
|
+
'- runtimeMode: string',
|
|
1226
|
+
'- materialize: boolean',
|
|
1227
|
+
'- audit: boolean',
|
|
1228
|
+
'- enforceAudit: boolean',
|
|
1229
|
+
'- providerIntent: { lane: string, why: string }',
|
|
1230
|
+
'',
|
|
1231
|
+
'Input:',
|
|
1232
|
+
JSON.stringify(requestShape, null, 2),
|
|
1233
|
+
].join('\n');
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
function resolveForgeServiceUrl(baseUrl, pathname) {
|
|
1237
|
+
const normalizedBase = baseUrl.replace(/\/+$/, '');
|
|
1238
|
+
if (normalizedBase.endsWith('/api/forge/psi') && pathname === '/synthesize') {
|
|
1239
|
+
return normalizedBase;
|
|
1240
|
+
}
|
|
1241
|
+
return `${normalizedBase}${pathname}`;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
async function callForgeService(pathname, payload, options = {}) {
|
|
1245
|
+
const baseUrl = DEFAULT_FORGE_SERVICE_URL.replace(/\/+$/, '');
|
|
1246
|
+
const targetUrl = resolveForgeServiceUrl(baseUrl, pathname);
|
|
1247
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
1248
|
+
const authToken = coerceNonEmptyString(options.authToken);
|
|
1249
|
+
if (authToken) {
|
|
1250
|
+
headers.Authorization = `Bearer ${authToken}`;
|
|
1251
|
+
headers['X-API-Key'] = authToken;
|
|
1252
|
+
}
|
|
1253
|
+
let response;
|
|
1254
|
+
try {
|
|
1255
|
+
response = await fetch(targetUrl, {
|
|
1256
|
+
method: 'POST',
|
|
1257
|
+
headers,
|
|
1258
|
+
body: JSON.stringify(payload),
|
|
1259
|
+
});
|
|
1260
|
+
} catch (error) {
|
|
1261
|
+
throw new Error(`Forge PSI fetch failed for ${targetUrl}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
const responseText = await response.text();
|
|
1265
|
+
let parsed;
|
|
1266
|
+
try {
|
|
1267
|
+
parsed = responseText ? JSON.parse(responseText) : {};
|
|
1268
|
+
} catch {
|
|
1269
|
+
parsed = { raw: responseText };
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
if (!response.ok) {
|
|
1273
|
+
const detail =
|
|
1274
|
+
parsed && typeof parsed === 'object'
|
|
1275
|
+
? parsed.error || parsed.message || responseText || response.statusText
|
|
1276
|
+
: responseText || response.statusText;
|
|
1277
|
+
throw new Error(`Forge PSI error ${response.status} from ${targetUrl}: ${detail}`);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
return parsed;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
function summarizeForgeOutcome(manifest, forgeResult) {
|
|
1284
|
+
const summary = [
|
|
1285
|
+
`Forge plan: ${manifest.manifestSummary || manifest.normalizedIntent || 'runtime forge synthesis'}`,
|
|
1286
|
+
];
|
|
1287
|
+
if (Array.isArray(forgeResult?.writtenFiles) && forgeResult.writtenFiles.length > 0) {
|
|
1288
|
+
summary.push(`Files materialized: ${forgeResult.writtenFiles.slice(0, 8).join(', ')}`);
|
|
1289
|
+
}
|
|
1290
|
+
if (forgeResult?.forgeAudit?.verdict) {
|
|
1291
|
+
summary.push(`Audit verdict: ${forgeResult.forgeAudit.verdict}`);
|
|
1292
|
+
}
|
|
1293
|
+
if (forgeResult?.metadata?.runtime) {
|
|
1294
|
+
summary.push(`Forge runtime: ${forgeResult.metadata.runtime}`);
|
|
1295
|
+
}
|
|
1296
|
+
return summary.join('\n');
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
function buildForgeExecutionIntent(normalizedIntent, manifest) {
|
|
1300
|
+
const sections = [coerceNonEmptyString(normalizedIntent)];
|
|
1301
|
+
if (Array.isArray(manifest.requestedArtifacts) && manifest.requestedArtifacts.length > 0) {
|
|
1302
|
+
sections.push(`Required artifact paths:\n- ${manifest.requestedArtifacts.join('\n- ')}`);
|
|
1303
|
+
}
|
|
1304
|
+
if (Array.isArray(manifest.constraints) && manifest.constraints.length > 0) {
|
|
1305
|
+
sections.push(`Constraints:\n- ${manifest.constraints.join('\n- ')}`);
|
|
1306
|
+
}
|
|
1307
|
+
if (Array.isArray(manifest.implementationPlan) && manifest.implementationPlan.length > 0) {
|
|
1308
|
+
sections.push(`Execution plan:\n- ${manifest.implementationPlan.join('\n- ')}`);
|
|
1309
|
+
}
|
|
1310
|
+
return sections.filter(Boolean).join('\n\n');
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
function extractForgeArtifactPaths(forgeResult) {
|
|
1314
|
+
const explicit = Array.isArray(forgeResult?.writtenFiles) ? forgeResult.writtenFiles.filter(Boolean) : [];
|
|
1315
|
+
if (explicit.length > 0) return explicit;
|
|
1316
|
+
const code = coerceNonEmptyString(forgeResult?.code);
|
|
1317
|
+
if (!code) return [];
|
|
1318
|
+
try {
|
|
1319
|
+
const parsed = extractJsonObject(code);
|
|
1320
|
+
if (Array.isArray(parsed?.files)) {
|
|
1321
|
+
return parsed.files.map((file) => coerceNonEmptyString(file?.path)).filter(Boolean);
|
|
1322
|
+
}
|
|
1323
|
+
} catch {}
|
|
1324
|
+
return [];
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
function computeForgeContractIssues(manifest, forgeResult) {
|
|
1328
|
+
const issues = [];
|
|
1329
|
+
const requestedArtifacts = Array.isArray(manifest.requestedArtifacts) ? manifest.requestedArtifacts.filter(Boolean) : [];
|
|
1330
|
+
const actualArtifacts = extractForgeArtifactPaths(forgeResult);
|
|
1331
|
+
if (requestedArtifacts.length > 0) {
|
|
1332
|
+
const matched = requestedArtifacts.filter((requested) =>
|
|
1333
|
+
actualArtifacts.some((actual) => actual === requested || actual.endsWith(`/${requested}`) || requested.endsWith(`/${actual}`)),
|
|
1334
|
+
);
|
|
1335
|
+
if (matched.length === 0) {
|
|
1336
|
+
issues.push(`forge output missed requested artifact paths (${requestedArtifacts.join(', ')})`);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
const qaVerdict = forgeResult?.metadata?.qaGate?.verdict || null;
|
|
1340
|
+
if (qaVerdict === 'fail') {
|
|
1341
|
+
issues.push('forge qa gate failed');
|
|
1342
|
+
}
|
|
1343
|
+
return {
|
|
1344
|
+
requestedArtifacts,
|
|
1345
|
+
actualArtifacts,
|
|
1346
|
+
issues,
|
|
1347
|
+
matched: issues.length === 0,
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
async function persistTurnArtifacts(req, body, client, apiKey, turn) {
|
|
1352
|
+
const evolutionPrinciples = extractEvolutionPrinciples(turn.packet, [turn.preResult, turn.midResult, turn.postResult]);
|
|
1353
|
+
const aegisPatterns = [
|
|
1354
|
+
...extractAegisPatterns(turn.midResult || {}),
|
|
1355
|
+
...extractAegisPatterns(turn.postResult || {}),
|
|
1356
|
+
];
|
|
1357
|
+
const cognitionStrings = {
|
|
1358
|
+
pre: turn.preResult?.notes || [],
|
|
1359
|
+
mid: turn.midResult?.notes || [],
|
|
1360
|
+
post: turn.postResult?.notes || [],
|
|
1361
|
+
receipts: {
|
|
1362
|
+
pre: turn.preReceipt || null,
|
|
1363
|
+
mid: turn.midReceipt || null,
|
|
1364
|
+
post: turn.postReceipt || null,
|
|
1365
|
+
},
|
|
1366
|
+
contracts: {
|
|
1367
|
+
pre: turn.preContract || null,
|
|
1368
|
+
mid: turn.midContract || null,
|
|
1369
|
+
post: turn.postContract || null,
|
|
1370
|
+
},
|
|
1371
|
+
turn_class: turn.turnClass || null,
|
|
1372
|
+
operator_plan: turn.operatorPlan || null,
|
|
1373
|
+
fired: [
|
|
1374
|
+
...(turn.preResult?.fired || []),
|
|
1375
|
+
...(turn.midResult?.fired || []),
|
|
1376
|
+
...(turn.postResult?.fired || []),
|
|
1377
|
+
],
|
|
1378
|
+
first_principle: turn.preResult?.firstPrincipleText || null,
|
|
1379
|
+
aristotle_28: ARISTOTLE_28_MODULES,
|
|
1380
|
+
noor_cognitives: NOOR_COGNITIVE_SUITE,
|
|
1381
|
+
readable: {
|
|
1382
|
+
pre: summarizePhaseResult('pre', turn.preResult),
|
|
1383
|
+
mid: summarizePhaseResult('mid', turn.midResult),
|
|
1384
|
+
post: summarizePhaseResult('post', turn.postResult),
|
|
1385
|
+
},
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
const telemetryPayload = {
|
|
1389
|
+
event_type: 'runtime.cognition.turn',
|
|
1390
|
+
session_id: turn.sessionId,
|
|
1391
|
+
duration_ms: turn.durationMs,
|
|
1392
|
+
success: turn.success,
|
|
1393
|
+
error: turn.error || null,
|
|
1394
|
+
data: {
|
|
1395
|
+
provider: turn.providerMeta.provider,
|
|
1396
|
+
model: turn.providerMeta.model,
|
|
1397
|
+
finish_reason: turn.providerMeta.finishReason,
|
|
1398
|
+
message: turn.userMessage,
|
|
1399
|
+
planned_approach: turn.plannedApproach,
|
|
1400
|
+
validation: turn.validation,
|
|
1401
|
+
layer3: turn.layer3,
|
|
1402
|
+
pre: turn.preResult,
|
|
1403
|
+
mid: turn.midResult,
|
|
1404
|
+
post: turn.postResult,
|
|
1405
|
+
evolution_principles: evolutionPrinciples,
|
|
1406
|
+
aegis_patterns: aegisPatterns,
|
|
1407
|
+
runtime_url: DEFAULT_RUNTIME_URL,
|
|
1408
|
+
runtime_id: ensureRuntimeMeta().runtimeId,
|
|
1409
|
+
},
|
|
1410
|
+
};
|
|
1411
|
+
|
|
1412
|
+
mutateCognitionState(apiKey, (state) => ({
|
|
1413
|
+
...state,
|
|
1414
|
+
telemetry: appendBounded(state.telemetry, telemetryPayload, TELEMETRY_LIMIT),
|
|
1415
|
+
evolutionPrinciples: mergeUniqueByJson(state.evolutionPrinciples, evolutionPrinciples, PRINCIPLE_LIMIT),
|
|
1416
|
+
aegisPatterns: mergeUniqueByJson(state.aegisPatterns, aegisPatterns, PATTERN_LIMIT),
|
|
1417
|
+
receipts: appendBounded(state.receipts, {
|
|
1418
|
+
at: new Date().toISOString(),
|
|
1419
|
+
source: 'persistTurnArtifacts',
|
|
1420
|
+
sessionId: turn.sessionId,
|
|
1421
|
+
turnClass: turn.turnClass || null,
|
|
1422
|
+
pre: turn.preReceipt || null,
|
|
1423
|
+
mid: turn.midReceipt || null,
|
|
1424
|
+
post: turn.postReceipt || null,
|
|
1425
|
+
}, RECEIPT_LIMIT),
|
|
1426
|
+
cognitiveStrings: appendBounded(state.cognitiveStrings, {
|
|
1427
|
+
at: new Date().toISOString(),
|
|
1428
|
+
sessionId: turn.sessionId,
|
|
1429
|
+
payload: cognitionStrings,
|
|
1430
|
+
}, TELEMETRY_LIMIT),
|
|
1431
|
+
hive: appendBounded(state.hive, {
|
|
1432
|
+
at: new Date().toISOString(),
|
|
1433
|
+
sessionId: turn.sessionId,
|
|
1434
|
+
message: turn.userMessage,
|
|
1435
|
+
response: turn.finalText,
|
|
1436
|
+
}, TELEMETRY_LIMIT),
|
|
1437
|
+
}));
|
|
1438
|
+
|
|
1439
|
+
try {
|
|
1440
|
+
await persistGardenPulseToQdrant(apiKey, {
|
|
1441
|
+
sessionId: turn.sessionId,
|
|
1442
|
+
message: turn.userMessage,
|
|
1443
|
+
response: turn.finalText,
|
|
1444
|
+
plannedApproach: turn.plannedApproach,
|
|
1445
|
+
tags: [
|
|
1446
|
+
'runtime-turn',
|
|
1447
|
+
turn.providerMeta.provider || 'provider',
|
|
1448
|
+
turn.success ? 'pass' : 'blocked',
|
|
1449
|
+
],
|
|
1450
|
+
telemetry: {
|
|
1451
|
+
provider: turn.providerMeta.provider,
|
|
1452
|
+
model: turn.providerMeta.model,
|
|
1453
|
+
finish_reason: turn.providerMeta.finishReason,
|
|
1454
|
+
success: turn.success,
|
|
1455
|
+
},
|
|
1456
|
+
readability: cognitionStrings.readable,
|
|
1457
|
+
});
|
|
1458
|
+
} catch {}
|
|
1459
|
+
|
|
1460
|
+
const heartbeatBody = {
|
|
1461
|
+
apiKey,
|
|
1462
|
+
surface: 'aria-mounted-runtime',
|
|
1463
|
+
skipLocalStateWrite: true,
|
|
1464
|
+
hive: {
|
|
1465
|
+
session_id: turn.sessionId,
|
|
1466
|
+
message: turn.userMessage,
|
|
1467
|
+
response: turn.finalText,
|
|
1468
|
+
},
|
|
1469
|
+
cognitive_strings: cognitionStrings,
|
|
1470
|
+
evolution: evolutionPrinciples,
|
|
1471
|
+
aegis_patterns: aegisPatterns,
|
|
1472
|
+
telemetry: telemetryPayload.data,
|
|
1473
|
+
metadata: {
|
|
1474
|
+
runtime_id: ensureRuntimeMeta().runtimeId,
|
|
1475
|
+
runtime: 'aria-mounted-runtime',
|
|
1476
|
+
runtime_url: DEFAULT_RUNTIME_URL,
|
|
1477
|
+
workspace_root: process.cwd(),
|
|
1478
|
+
provider: turn.providerMeta.provider,
|
|
1479
|
+
model: turn.providerMeta.model,
|
|
1480
|
+
},
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
try {
|
|
1484
|
+
await heartbeatUpstream(req, heartbeatBody, client, apiKey);
|
|
1485
|
+
} catch {}
|
|
1486
|
+
|
|
1487
|
+
try {
|
|
1488
|
+
await pushTelemetryUpstream(client, apiKey, telemetryPayload);
|
|
1489
|
+
} catch {}
|
|
1490
|
+
|
|
1491
|
+
if (findVerifiedState(turn.finalText) || /recommend|should|propose|choose/i.test(turn.finalText)) {
|
|
1492
|
+
const decisionPayload = {
|
|
1493
|
+
decision_type: body?.metadata?.decision_type || 'runtime-turn',
|
|
1494
|
+
category: body?.metadata?.decision_category || 'cognition-control-plane',
|
|
1495
|
+
context: turn.userMessage.slice(0, 2000) || 'mounted runtime turn',
|
|
1496
|
+
decision: turn.finalText.slice(0, 2000),
|
|
1497
|
+
reasoning: [
|
|
1498
|
+
...(turn.preResult?.notes || []),
|
|
1499
|
+
...(turn.midResult?.notes || []),
|
|
1500
|
+
...(turn.postResult?.notes || []),
|
|
1501
|
+
].join(' | ').slice(0, 4000) || 'Aria runtime cognition turn',
|
|
1502
|
+
outcome: 'pending',
|
|
1503
|
+
expected_outcome: {
|
|
1504
|
+
predicate: 'response survives runtime validation and compounds into central telemetry',
|
|
1505
|
+
measurable_type: 'boolean',
|
|
1506
|
+
threshold: true,
|
|
1507
|
+
},
|
|
1508
|
+
source: 'aria-mounted-runtime',
|
|
1509
|
+
model_used: turn.providerMeta.model,
|
|
1510
|
+
code_links: body?.metadata?.code_links || null,
|
|
1511
|
+
};
|
|
1512
|
+
try {
|
|
1513
|
+
const decisionResult = await pushDecisionUpstream(client, apiKey, decisionPayload);
|
|
1514
|
+
mutateCognitionState(apiKey, (state) => ({
|
|
1515
|
+
...state,
|
|
1516
|
+
decisions: appendBounded(state.decisions, {
|
|
1517
|
+
at: new Date().toISOString(),
|
|
1518
|
+
sessionId: turn.sessionId,
|
|
1519
|
+
decision: decisionPayload,
|
|
1520
|
+
result: decisionResult,
|
|
1521
|
+
}, DECISION_LIMIT),
|
|
1522
|
+
}));
|
|
1523
|
+
} catch {}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
if (body.ariaGarden !== false && turn.userMessage && turn.finalText) {
|
|
1527
|
+
try {
|
|
1528
|
+
await client.gardenTurn(turn.sessionId, turn.userMessage, turn.finalText, turn.userId || undefined);
|
|
1529
|
+
} catch {}
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
async function handleProviderProxy(req, body, client, providerStyle) {
|
|
1534
|
+
const apiKey = resolveApiKey(req, body);
|
|
1535
|
+
const startedAt = Date.now();
|
|
1536
|
+
const turn = await buildRuntimeTurnContext(req, body, client);
|
|
1537
|
+
if (turn.preResult.fitrahVetoed) {
|
|
1538
|
+
const refusal = buildPhaseBlockMessage(turn.preResult, 'pre');
|
|
1539
|
+
const extra = { blocked: true, phase: 'pre', pre: turn.preResult, mid: turn.midResult };
|
|
1540
|
+
return providerStyle === 'anthropic'
|
|
1541
|
+
? anthropicResponseEnvelope(refusal, { model: body.model || 'aria-runtime', finishReason: 'end_turn' }, extra, body?.ariaDebug === true)
|
|
1542
|
+
: openAiResponseEnvelope(body, refusal, { model: body.model || 'aria-runtime', finishReason: 'stop', usage: null }, extra);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
const providerMeta = providerStyle === 'anthropic'
|
|
1546
|
+
? await callProviderForAnthropic(body, turn.ariaSystemPrompt)
|
|
1547
|
+
: await callProviderForOpenAI(body, turn.ariaSystemPrompt);
|
|
1548
|
+
|
|
1549
|
+
let candidateText = providerMeta.text || '';
|
|
1550
|
+
let validation;
|
|
1551
|
+
try {
|
|
1552
|
+
validation = await client.validateOutput(candidateText, turn.sessionId);
|
|
1553
|
+
} catch (error) {
|
|
1554
|
+
if (!turn.packetBypassed) throw error;
|
|
1555
|
+
validation = {
|
|
1556
|
+
passed: true,
|
|
1557
|
+
severity: 'warn',
|
|
1558
|
+
violations: [
|
|
1559
|
+
`remote validate unavailable: ${error instanceof Error ? error.message : String(error)}`,
|
|
1560
|
+
],
|
|
1561
|
+
gateTriggers: ['owner-local-bypass'],
|
|
1562
|
+
};
|
|
1563
|
+
}
|
|
1564
|
+
if (validation?.severity === 'block' && validation?.rewritten) {
|
|
1565
|
+
candidateText = validation.rewritten;
|
|
1566
|
+
try {
|
|
1567
|
+
validation = await client.validateOutput(candidateText, turn.sessionId);
|
|
1568
|
+
} catch (error) {
|
|
1569
|
+
if (!turn.packetBypassed) throw error;
|
|
1570
|
+
validation = {
|
|
1571
|
+
passed: true,
|
|
1572
|
+
severity: 'warn',
|
|
1573
|
+
violations: [
|
|
1574
|
+
`remote validate unavailable after rewrite: ${error instanceof Error ? error.message : String(error)}`,
|
|
1575
|
+
],
|
|
1576
|
+
gateTriggers: ['owner-local-bypass'],
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
const layer3 = await runLayer3(req, {
|
|
1582
|
+
text: candidateText,
|
|
1583
|
+
packet: turn.packet,
|
|
1584
|
+
fetchPacket: false,
|
|
1585
|
+
requireCognitionBlock: body.requireCognitionBlock ?? false,
|
|
1586
|
+
}, client);
|
|
1587
|
+
const postBundle = evaluateMizanPost(candidateText, {
|
|
1588
|
+
hasVerifiedState: findVerifiedState(candidateText),
|
|
1589
|
+
layer3Pass: layer3.pass,
|
|
1590
|
+
remoteValidationSeverity: validation.severity,
|
|
1591
|
+
}, turn.packet, {
|
|
1592
|
+
sessionId: turn.sessionId,
|
|
1593
|
+
userId: turn.userId,
|
|
1594
|
+
message: turn.userMessage,
|
|
1595
|
+
plannedApproach: turn.plannedApproach,
|
|
1596
|
+
domains: body.ariaDomains,
|
|
1597
|
+
}, {
|
|
1598
|
+
sessionId: turn.sessionId,
|
|
1599
|
+
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
1600
|
+
parentReceiptId: turn.midReceipt?.receiptId || turn.preReceipt?.receiptId || null,
|
|
1601
|
+
});
|
|
1602
|
+
const postResult = postBundle.result;
|
|
1603
|
+
|
|
1604
|
+
const blocked = validation.severity === 'block' || !layer3.pass || postResult.reAuthorSignal;
|
|
1605
|
+
const finalText = blocked ? buildPhaseBlockMessage(postResult, 'post') : candidateText;
|
|
1606
|
+
await persistTurnArtifacts(req, body, client, apiKey, {
|
|
1607
|
+
...turn,
|
|
1608
|
+
postResult,
|
|
1609
|
+
postBundle,
|
|
1610
|
+
postReceipt: postBundle.receipt,
|
|
1611
|
+
postContract: postBundle.contract,
|
|
1612
|
+
validation,
|
|
1613
|
+
layer3,
|
|
1614
|
+
finalText,
|
|
1615
|
+
durationMs: Date.now() - startedAt,
|
|
1616
|
+
success: !blocked,
|
|
1617
|
+
error: blocked ? 'runtime blocked output' : null,
|
|
1618
|
+
providerMeta,
|
|
1619
|
+
});
|
|
1620
|
+
|
|
1621
|
+
const extra = {
|
|
1622
|
+
blocked,
|
|
1623
|
+
pre: turn.preResult,
|
|
1624
|
+
mid: turn.midResult,
|
|
1625
|
+
post: postResult,
|
|
1626
|
+
receipts: {
|
|
1627
|
+
pre: turn.preReceipt,
|
|
1628
|
+
mid: turn.midReceipt,
|
|
1629
|
+
post: postBundle.receipt,
|
|
1630
|
+
},
|
|
1631
|
+
turnClass: turn.turnClass,
|
|
1632
|
+
operatorPlan: turn.operatorPlan,
|
|
1633
|
+
validation,
|
|
1634
|
+
layer3,
|
|
1635
|
+
};
|
|
1636
|
+
return providerStyle === 'anthropic'
|
|
1637
|
+
? anthropicResponseEnvelope(finalText, providerMeta, extra, body?.ariaDebug === true)
|
|
1638
|
+
: openAiResponseEnvelope(body, finalText, providerMeta, extra);
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
async function handleForgeSynthesis(req, body, client) {
|
|
1642
|
+
const apiKey = resolveApiKey(req, body);
|
|
1643
|
+
const startedAt = Date.now();
|
|
1644
|
+
const intent =
|
|
1645
|
+
coerceNonEmptyString(body.intent) ||
|
|
1646
|
+
coerceNonEmptyString(body.input) ||
|
|
1647
|
+
coerceNonEmptyString(body.prompt) ||
|
|
1648
|
+
coerceNonEmptyString(body.message) ||
|
|
1649
|
+
coerceNonEmptyString(body.description);
|
|
1650
|
+
if (!intent) {
|
|
1651
|
+
throw new Error('forge/synthesize requires intent, input, prompt, message, or description');
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
const boundBody = {
|
|
1655
|
+
...body,
|
|
1656
|
+
message: intent,
|
|
1657
|
+
ariaPlannedApproach:
|
|
1658
|
+
coerceNonEmptyString(body.ariaPlannedApproach) ||
|
|
1659
|
+
'Use an LLM to normalize the implementation intent into a readable forge manifest, then hand that manifest to Forge PSI for real synthesis and materialization.',
|
|
1660
|
+
ariaRationale:
|
|
1661
|
+
coerceNonEmptyString(body.ariaRationale) ||
|
|
1662
|
+
'Aria should act as the control plane: planning and cognition in runtime, synthesis and file materialization in Forge PSI, with telemetry compounded into hive and garden.',
|
|
1663
|
+
};
|
|
1664
|
+
const turn = await buildDirectTurnContext(req, boundBody, client, {
|
|
1665
|
+
prefix: 'forge',
|
|
1666
|
+
stage: 'forge-synthesize',
|
|
1667
|
+
platform: 'aria-forge-runtime',
|
|
1668
|
+
defaultPlannedApproach:
|
|
1669
|
+
'Normalize the request into a forge manifest, route it through real Forge PSI synthesis, and persist readable cognition and outcome telemetry.',
|
|
1670
|
+
defaultRationale:
|
|
1671
|
+
'Forge PSI should be headed by Aria runtime cognition rather than direct raw prompting.',
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1674
|
+
if (turn.preResult.fitrahVetoed) {
|
|
1675
|
+
const refusal = buildPhaseBlockMessage(turn.preResult, 'pre');
|
|
1676
|
+
return {
|
|
1677
|
+
ok: false,
|
|
1678
|
+
blocked: true,
|
|
1679
|
+
phase: 'pre',
|
|
1680
|
+
manifest: null,
|
|
1681
|
+
forge: null,
|
|
1682
|
+
aria: buildReadableAriaEnvelope({
|
|
1683
|
+
blocked: true,
|
|
1684
|
+
pre: turn.preResult,
|
|
1685
|
+
mid: turn.midResult,
|
|
1686
|
+
}, body?.ariaDebug === true),
|
|
1687
|
+
response: refusal,
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
const plannerPrompt = buildForgePlannerPrompt(turn, body);
|
|
1692
|
+
const plannerBody = {
|
|
1693
|
+
...body,
|
|
1694
|
+
allowProviderFallback: body.allowProviderFallback !== false,
|
|
1695
|
+
messages: [{ role: 'user', content: plannerPrompt }],
|
|
1696
|
+
metadata: {
|
|
1697
|
+
...(body.metadata && typeof body.metadata === 'object' ? body.metadata : {}),
|
|
1698
|
+
intent: 'forge-manifest-planner',
|
|
1699
|
+
mode: 'architecture',
|
|
1700
|
+
roleProfile: 'forge-planner',
|
|
1701
|
+
},
|
|
1702
|
+
modelIntent: 'architecture forge planner manifest',
|
|
1703
|
+
};
|
|
1704
|
+
const plannerMeta = await callProviderForOpenAI(plannerBody, [
|
|
1705
|
+
'You are Aria runtime acting as the Forge planning head.',
|
|
1706
|
+
'Return strict JSON only.',
|
|
1707
|
+
'Do not emit code fences unless the content is still valid JSON.',
|
|
1708
|
+
].join('\n'));
|
|
1709
|
+
const manifest = extractJsonObject(plannerMeta.text || '');
|
|
1710
|
+
const normalizedIntent = coerceNonEmptyString(manifest.normalizedIntent) || intent;
|
|
1711
|
+
const domain = coerceNonEmptyString(manifest.domain) || coerceNonEmptyString(body.domain) || 'general';
|
|
1712
|
+
const requestedArtifacts = Array.isArray(manifest.requestedArtifacts) ? manifest.requestedArtifacts.filter(Boolean) : [];
|
|
1713
|
+
const constraints = Array.isArray(manifest.constraints) ? manifest.constraints.filter(Boolean) : [];
|
|
1714
|
+
const paths = Array.isArray(manifest.paths) ? manifest.paths.filter(Boolean) : [];
|
|
1715
|
+
const implementationPlan = Array.isArray(manifest.implementationPlan) ? manifest.implementationPlan.filter(Boolean) : [];
|
|
1716
|
+
const forgeAuthToken =
|
|
1717
|
+
coerceNonEmptyString(body.forgeAuthToken) ||
|
|
1718
|
+
coerceNonEmptyString(process.env.FORGE_API_TOKEN) ||
|
|
1719
|
+
coerceNonEmptyString(process.env.ARIA_API_KEY) ||
|
|
1720
|
+
coerceNonEmptyString(process.env.ARIA_MASTER_TOKEN) ||
|
|
1721
|
+
coerceNonEmptyString(body.apiKey);
|
|
1722
|
+
|
|
1723
|
+
const forgeManifest = {
|
|
1724
|
+
normalizedIntent,
|
|
1725
|
+
requestedArtifacts,
|
|
1726
|
+
constraints,
|
|
1727
|
+
implementationPlan,
|
|
1728
|
+
};
|
|
1729
|
+
const forgePayload = {
|
|
1730
|
+
input: buildForgeExecutionIntent(normalizedIntent, forgeManifest),
|
|
1731
|
+
type: 'intention',
|
|
1732
|
+
domain,
|
|
1733
|
+
materialize: manifest.materialize !== false && body.materialize !== false,
|
|
1734
|
+
audit: manifest.audit !== false && body.audit !== false,
|
|
1735
|
+
enforceAudit: manifest.enforceAudit !== false && body.enforceAudit !== false,
|
|
1736
|
+
author: 'aria-mounted-runtime',
|
|
1737
|
+
context: {
|
|
1738
|
+
...(body.context && typeof body.context === 'object' ? body.context : {}),
|
|
1739
|
+
runtimeManifest: {
|
|
1740
|
+
manifestSummary: coerceNonEmptyString(manifest.manifestSummary),
|
|
1741
|
+
requestedArtifacts,
|
|
1742
|
+
constraints,
|
|
1743
|
+
paths,
|
|
1744
|
+
implementationPlan,
|
|
1745
|
+
providerIntent: manifest.providerIntent || null,
|
|
1746
|
+
},
|
|
1747
|
+
runtimeReadableCognition: {
|
|
1748
|
+
pre: summarizePhaseResult('pre', turn.preResult),
|
|
1749
|
+
mid: summarizePhaseResult('mid', turn.midResult),
|
|
1750
|
+
},
|
|
1751
|
+
codebase: compactCodebaseSnapshot(),
|
|
1752
|
+
},
|
|
1753
|
+
};
|
|
1754
|
+
|
|
1755
|
+
const forgeResult = await callForgeService('/synthesize', forgePayload, {
|
|
1756
|
+
authToken: forgeAuthToken,
|
|
1757
|
+
});
|
|
1758
|
+
const contractCheck = computeForgeContractIssues(forgeManifest, forgeResult);
|
|
1759
|
+
const summaryText = summarizeForgeOutcome({
|
|
1760
|
+
normalizedIntent,
|
|
1761
|
+
manifestSummary: coerceNonEmptyString(manifest.manifestSummary),
|
|
1762
|
+
}, forgeResult);
|
|
1763
|
+
const validation = {
|
|
1764
|
+
passed: contractCheck.issues.length === 0,
|
|
1765
|
+
severity: contractCheck.issues.length === 0 ? 'pass' : 'block',
|
|
1766
|
+
violations: contractCheck.issues,
|
|
1767
|
+
gateTriggers: ['forge-runtime', ...(contractCheck.issues.length > 0 ? ['forge-contract'] : [])],
|
|
1768
|
+
};
|
|
1769
|
+
const layer3 = await runLayer3(req, {
|
|
1770
|
+
text: typeof forgeResult?.code === 'string' && forgeResult.code.trim() ? forgeResult.code : summaryText,
|
|
1771
|
+
packet: turn.packet,
|
|
1772
|
+
fetchPacket: false,
|
|
1773
|
+
requireCognitionBlock: body.requireCognitionBlock ?? false,
|
|
1774
|
+
}, client).catch((error) => layer3FailureResult(error, turn.packet));
|
|
1775
|
+
const postBundle = evaluateMizanPost(summaryText, {
|
|
1776
|
+
hasVerifiedState: true,
|
|
1777
|
+
layer3Pass: layer3.pass,
|
|
1778
|
+
remoteValidationSeverity: validation.severity,
|
|
1779
|
+
}, turn.packet, {
|
|
1780
|
+
sessionId: turn.sessionId,
|
|
1781
|
+
userId: turn.userId,
|
|
1782
|
+
message: turn.userMessage,
|
|
1783
|
+
plannedApproach: turn.plannedApproach,
|
|
1784
|
+
domains: body.ariaDomains,
|
|
1785
|
+
}, {
|
|
1786
|
+
sessionId: turn.sessionId,
|
|
1787
|
+
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
1788
|
+
parentReceiptId: turn.midReceipt?.receiptId || turn.preReceipt?.receiptId || null,
|
|
1789
|
+
});
|
|
1790
|
+
const postResult = postBundle.result;
|
|
1791
|
+
const blocked = validation.severity === 'block' || !layer3.pass || postResult.reAuthorSignal || postResult.fitrahVetoed;
|
|
1792
|
+
const finalText = blocked ? buildPhaseBlockMessage(postResult, 'post') : summaryText;
|
|
1793
|
+
|
|
1794
|
+
await persistTurnArtifacts(req, {
|
|
1795
|
+
...boundBody,
|
|
1796
|
+
metadata: {
|
|
1797
|
+
...(body.metadata && typeof body.metadata === 'object' ? body.metadata : {}),
|
|
1798
|
+
decision_type: body?.metadata?.decision_type || 'forge-synthesis',
|
|
1799
|
+
decision_category: body?.metadata?.decision_category || 'forge-control-plane',
|
|
1800
|
+
code_links: Array.isArray(forgeResult?.writtenFiles) ? forgeResult.writtenFiles : null,
|
|
1801
|
+
},
|
|
1802
|
+
}, client, apiKey, {
|
|
1803
|
+
...turn,
|
|
1804
|
+
postResult,
|
|
1805
|
+
postBundle,
|
|
1806
|
+
postReceipt: postBundle.receipt,
|
|
1807
|
+
postContract: postBundle.contract,
|
|
1808
|
+
validation,
|
|
1809
|
+
layer3,
|
|
1810
|
+
finalText,
|
|
1811
|
+
durationMs: Date.now() - startedAt,
|
|
1812
|
+
success: !blocked,
|
|
1813
|
+
error: blocked ? 'forge synthesis flagged by runtime cognition' : null,
|
|
1814
|
+
providerMeta: {
|
|
1815
|
+
provider: plannerMeta.provider,
|
|
1816
|
+
model: plannerMeta.model,
|
|
1817
|
+
finishReason: blocked ? 'flagged' : (plannerMeta.finishReason || 'forge-synthesized'),
|
|
1818
|
+
usage: plannerMeta.usage || null,
|
|
1819
|
+
},
|
|
1820
|
+
});
|
|
1821
|
+
|
|
1822
|
+
return {
|
|
1823
|
+
ok: !blocked,
|
|
1824
|
+
blocked,
|
|
1825
|
+
manifest: {
|
|
1826
|
+
normalizedIntent,
|
|
1827
|
+
domain,
|
|
1828
|
+
manifestSummary: coerceNonEmptyString(manifest.manifestSummary),
|
|
1829
|
+
requestedArtifacts,
|
|
1830
|
+
constraints,
|
|
1831
|
+
paths,
|
|
1832
|
+
implementationPlan,
|
|
1833
|
+
providerIntent: manifest.providerIntent || null,
|
|
1834
|
+
runtimeMode: coerceNonEmptyString(manifest.runtimeMode) || 'llm-headed-forge-psi',
|
|
1835
|
+
contract: contractCheck,
|
|
1836
|
+
},
|
|
1837
|
+
forge: forgeResult,
|
|
1838
|
+
response: finalText,
|
|
1839
|
+
aria: buildReadableAriaEnvelope({
|
|
1840
|
+
blocked,
|
|
1841
|
+
pre: turn.preResult,
|
|
1842
|
+
mid: turn.midResult,
|
|
1843
|
+
post: postResult,
|
|
1844
|
+
receipts: {
|
|
1845
|
+
pre: turn.preReceipt,
|
|
1846
|
+
mid: turn.midReceipt,
|
|
1847
|
+
post: postBundle.receipt,
|
|
1848
|
+
},
|
|
1849
|
+
turnClass: turn.turnClass,
|
|
1850
|
+
operatorPlan: turn.operatorPlan,
|
|
1851
|
+
validation,
|
|
1852
|
+
layer3,
|
|
1853
|
+
}, body?.ariaDebug === true),
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
function layer3FailureResult(error, packet) {
|
|
1858
|
+
return {
|
|
1859
|
+
pass: false,
|
|
1860
|
+
summary: 'runtime layer3 failed',
|
|
1861
|
+
failures: [
|
|
1862
|
+
{
|
|
1863
|
+
severity: 'block',
|
|
1864
|
+
kind: 'runtime-layer3',
|
|
1865
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
1866
|
+
},
|
|
1867
|
+
],
|
|
1868
|
+
packetTimestamp: packet?.timestamp || null,
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
function packetToSubstrateSet(packet) {
|
|
1873
|
+
const p = packet?.packet && typeof packet.packet === 'object' ? packet.packet : packet;
|
|
1874
|
+
const axioms = Object.keys(p?.axioms || {});
|
|
1875
|
+
const frames = Object.keys(p?.frames || {});
|
|
1876
|
+
const memoryRecord = p?.memory || {};
|
|
1877
|
+
const memories = Object.keys(memoryRecord).map((name) =>
|
|
1878
|
+
name.toLowerCase().endsWith('.md') ? name : `${name}.md`,
|
|
1879
|
+
);
|
|
1880
|
+
const doctrineRecord = p?.doctrine || {};
|
|
1881
|
+
const doctrinesAcceptable = Object.keys(doctrineRecord);
|
|
1882
|
+
const packets = Array.from(
|
|
1883
|
+
new Set([
|
|
1884
|
+
'role',
|
|
1885
|
+
'first_principle',
|
|
1886
|
+
'turn_mode',
|
|
1887
|
+
'role_rule',
|
|
1888
|
+
'role_profile',
|
|
1889
|
+
'cognition_belt',
|
|
1890
|
+
'aria_research_pull',
|
|
1891
|
+
...frames,
|
|
1892
|
+
]),
|
|
1893
|
+
);
|
|
1894
|
+
|
|
1895
|
+
const firstPrincipleText =
|
|
1896
|
+
typeof p?.frames?.first_principle === 'string' ? p.frames.first_principle : '';
|
|
1897
|
+
|
|
1898
|
+
return {
|
|
1899
|
+
axioms,
|
|
1900
|
+
frames,
|
|
1901
|
+
memories,
|
|
1902
|
+
doctrinesAcceptable,
|
|
1903
|
+
packets,
|
|
1904
|
+
languagesLoaded: ['nadia', 'noor'],
|
|
1905
|
+
languagesActive: { nadia: false, noor: false },
|
|
1906
|
+
firstPrincipleText,
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
function runtimeManifest() {
|
|
1911
|
+
const runtimeMeta = ensureRuntimeMeta();
|
|
1912
|
+
const state = sweepAutonomyState(loadAutonomyState());
|
|
1913
|
+
return {
|
|
1914
|
+
ok: true,
|
|
1915
|
+
runtime: 'aria-mounted-runtime',
|
|
1916
|
+
runtimeId: runtimeMeta.runtimeId,
|
|
1917
|
+
url: DEFAULT_RUNTIME_URL,
|
|
1918
|
+
runtimeRoot: __dirname,
|
|
1919
|
+
endpoints: [
|
|
1920
|
+
'GET /health',
|
|
1921
|
+
'GET /mount',
|
|
1922
|
+
'POST /heartbeat',
|
|
1923
|
+
'POST /mizan/plan',
|
|
1924
|
+
'POST /mizan/pre',
|
|
1925
|
+
'POST /mizan/mid',
|
|
1926
|
+
'POST /mizan/post',
|
|
1927
|
+
'POST /phase/pre',
|
|
1928
|
+
'POST /phase/mid',
|
|
1929
|
+
'POST /phase/post',
|
|
1930
|
+
'POST /autonomy/jobs/enqueue',
|
|
1931
|
+
'POST /autonomy/jobs/list',
|
|
1932
|
+
'POST /autonomy/jobs/claim',
|
|
1933
|
+
'POST /autonomy/jobs/heartbeat',
|
|
1934
|
+
'POST /autonomy/jobs/complete',
|
|
1935
|
+
'POST /autonomy/jobs/fail',
|
|
1936
|
+
'POST /autonomy/workers/register',
|
|
1937
|
+
'POST /autonomy/workers/list',
|
|
1938
|
+
'POST /packet',
|
|
1939
|
+
'POST /consult',
|
|
1940
|
+
'POST /inject',
|
|
1941
|
+
'POST /build-system-prompt',
|
|
1942
|
+
'POST /check-action',
|
|
1943
|
+
'POST /validate-output',
|
|
1944
|
+
'POST /full-chain',
|
|
1945
|
+
'POST /garden/turn',
|
|
1946
|
+
'POST /garden/search',
|
|
1947
|
+
'POST /record-discovery',
|
|
1948
|
+
'POST /verify-claim',
|
|
1949
|
+
'POST /telemetry/turn',
|
|
1950
|
+
'POST /telemetry/state',
|
|
1951
|
+
'POST /decision/log',
|
|
1952
|
+
'POST /aegis/patterns',
|
|
1953
|
+
'POST /evolution/principles',
|
|
1954
|
+
'POST /noor/recognize',
|
|
1955
|
+
'POST /noor/forge',
|
|
1956
|
+
'POST /forge/synthesize',
|
|
1957
|
+
'POST /codebase/state',
|
|
1958
|
+
'POST /v1/chat/completions',
|
|
1959
|
+
'POST /v1/messages',
|
|
1960
|
+
],
|
|
1961
|
+
mount: {
|
|
1962
|
+
env: {
|
|
1963
|
+
ARIA_RUNTIME_URL: DEFAULT_RUNTIME_URL,
|
|
1964
|
+
ARIA_HARNESS_URL: DEFAULT_HARNESS_URL,
|
|
1965
|
+
ARIA_FORGE_SERVICE_URL: DEFAULT_FORGE_SERVICE_URL,
|
|
1966
|
+
ARIA_QDRANT_URL: DEFAULT_QDRANT_URL,
|
|
1967
|
+
OPENAI_BASE_URL: `${DEFAULT_RUNTIME_URL}/v1`,
|
|
1968
|
+
ANTHROPIC_BASE_URL: `${DEFAULT_RUNTIME_URL}/v1`,
|
|
1969
|
+
},
|
|
1970
|
+
commands: {
|
|
1971
|
+
start: 'aria-runtime',
|
|
1972
|
+
doctor: 'aria-runtime-doctor',
|
|
1973
|
+
},
|
|
1974
|
+
security: {
|
|
1975
|
+
encrypted_local_lease: LEASE_PATH,
|
|
1976
|
+
encrypted_cognition_state: COGNITION_STATE_PATH,
|
|
1977
|
+
revocation_lock: REVOCATION_LOCK_PATH,
|
|
1978
|
+
upstream_heartbeat: '/api/license/heartbeat',
|
|
1979
|
+
},
|
|
1980
|
+
memory: {
|
|
1981
|
+
qdrant_url: DEFAULT_QDRANT_URL,
|
|
1982
|
+
qdrant_collection: DEFAULT_QDRANT_COLLECTION,
|
|
1983
|
+
},
|
|
1984
|
+
},
|
|
1985
|
+
autonomy: queueStats(state),
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
async function runLayer3(req, body, client) {
|
|
1990
|
+
if (typeof body.text !== 'string' || !body.text.trim()) {
|
|
1991
|
+
throw new Error('full-chain requires a non-empty text field');
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
const packet =
|
|
1995
|
+
body.packet ||
|
|
1996
|
+
(body.fetchPacket !== false
|
|
1997
|
+
? await loadRuntimePacket(req, body, client, body.packetRequest || {}, body.text)
|
|
1998
|
+
: null);
|
|
1999
|
+
if (!packet) {
|
|
2000
|
+
throw new Error('full-chain requires packet or fetchPacket=true');
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
const result = runFullChain(body.text, {
|
|
2004
|
+
substrate: packetToSubstrateSet(packet),
|
|
2005
|
+
requireCognitionBlock: body.requireCognitionBlock ?? false,
|
|
2006
|
+
});
|
|
2007
|
+
|
|
2008
|
+
return {
|
|
2009
|
+
pass: result.pass,
|
|
2010
|
+
summary: result.summary,
|
|
2011
|
+
failures: result.failures,
|
|
2012
|
+
packetTimestamp: packet.timestamp || null,
|
|
2013
|
+
};
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
function ensureWorker(state, workerId, body = {}) {
|
|
2017
|
+
let worker = state.workers.find((entry) => entry.workerId === workerId);
|
|
2018
|
+
if (!worker) {
|
|
2019
|
+
worker = {
|
|
2020
|
+
workerId,
|
|
2021
|
+
surface: body.surface || 'runtime-worker',
|
|
2022
|
+
capabilities: Array.isArray(body.capabilities) ? body.capabilities : [],
|
|
2023
|
+
metadata: body.metadata || {},
|
|
2024
|
+
status: 'idle',
|
|
2025
|
+
registeredAt: new Date().toISOString(),
|
|
2026
|
+
lastHeartbeat: new Date().toISOString(),
|
|
2027
|
+
currentJobId: null,
|
|
2028
|
+
};
|
|
2029
|
+
state.workers.push(worker);
|
|
2030
|
+
}
|
|
2031
|
+
return worker;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
async function handleAutonomyRoute(url, body, client) {
|
|
2035
|
+
const state = sweepAutonomyState(loadAutonomyState());
|
|
2036
|
+
|
|
2037
|
+
if (url.pathname === '/autonomy/jobs/list') {
|
|
2038
|
+
const limit = Number(body.limit || 50);
|
|
2039
|
+
const view = getAutonomyView(state, Number.isFinite(limit) ? Math.max(1, Math.min(limit, 200)) : 50);
|
|
2040
|
+
return { ok: true, ...view };
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
if (url.pathname === '/autonomy/workers/list') {
|
|
2044
|
+
return { ok: true, workers: getAutonomyView(state).workers, stats: queueStats(state) };
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
if (url.pathname === '/autonomy/workers/register') {
|
|
2048
|
+
if (typeof body.workerId !== 'string' || !body.workerId.trim()) {
|
|
2049
|
+
throw new Error('autonomy/workers/register requires workerId');
|
|
2050
|
+
}
|
|
2051
|
+
const worker = ensureWorker(state, body.workerId.trim(), body);
|
|
2052
|
+
worker.surface = body.surface || worker.surface;
|
|
2053
|
+
worker.capabilities = Array.isArray(body.capabilities) ? body.capabilities : worker.capabilities;
|
|
2054
|
+
worker.metadata = body.metadata || worker.metadata;
|
|
2055
|
+
worker.status = body.status || worker.status || 'idle';
|
|
2056
|
+
worker.lastHeartbeat = new Date().toISOString();
|
|
2057
|
+
saveAutonomyState(state);
|
|
2058
|
+
return { ok: true, worker, stats: queueStats(state) };
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
if (url.pathname === '/autonomy/jobs/enqueue') {
|
|
2062
|
+
if (typeof body.kind !== 'string' || !body.kind.trim()) {
|
|
2063
|
+
throw new Error('autonomy/jobs/enqueue requires kind');
|
|
2064
|
+
}
|
|
2065
|
+
const now = new Date().toISOString();
|
|
2066
|
+
const job = {
|
|
2067
|
+
jobId: randomUUID(),
|
|
2068
|
+
kind: body.kind.trim(),
|
|
2069
|
+
surface: body.surface || 'runtime-client',
|
|
2070
|
+
sessionId: body.sessionId || null,
|
|
2071
|
+
payload: body.payload || {},
|
|
2072
|
+
metadata: body.metadata || {},
|
|
2073
|
+
priority: Number.isFinite(Number(body.priority)) ? Number(body.priority) : 100,
|
|
2074
|
+
status: 'queued',
|
|
2075
|
+
attempts: 0,
|
|
2076
|
+
maxAttempts: Number.isFinite(Number(body.maxAttempts)) ? Number(body.maxAttempts) : 3,
|
|
2077
|
+
createdAt: now,
|
|
2078
|
+
updatedAt: now,
|
|
2079
|
+
workerId: null,
|
|
2080
|
+
claimedAt: null,
|
|
2081
|
+
claimExpiresAt: null,
|
|
2082
|
+
progress: [],
|
|
2083
|
+
garden: body.garden || null,
|
|
2084
|
+
};
|
|
2085
|
+
state.jobs.push(job);
|
|
2086
|
+
saveAutonomyState(state);
|
|
2087
|
+
return { ok: true, job, stats: queueStats(state) };
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
if (url.pathname === '/autonomy/jobs/claim') {
|
|
2091
|
+
if (typeof body.workerId !== 'string' || !body.workerId.trim()) {
|
|
2092
|
+
throw new Error('autonomy/jobs/claim requires workerId');
|
|
2093
|
+
}
|
|
2094
|
+
const worker = ensureWorker(state, body.workerId.trim(), body);
|
|
2095
|
+
const allowedKinds = Array.isArray(body.kinds) ? new Set(body.kinds) : null;
|
|
2096
|
+
const now = Date.now();
|
|
2097
|
+
const candidates = state.jobs
|
|
2098
|
+
.filter((job) => job.status === 'queued' && (!allowedKinds || allowedKinds.has(job.kind)))
|
|
2099
|
+
.sort((a, b) => {
|
|
2100
|
+
const priorityDelta = (b.priority || 0) - (a.priority || 0);
|
|
2101
|
+
if (priorityDelta !== 0) return priorityDelta;
|
|
2102
|
+
return Date.parse(a.createdAt) - Date.parse(b.createdAt);
|
|
2103
|
+
});
|
|
2104
|
+
const job = candidates[0] || null;
|
|
2105
|
+
if (!job) {
|
|
2106
|
+
worker.status = 'idle';
|
|
2107
|
+
worker.currentJobId = null;
|
|
2108
|
+
worker.lastHeartbeat = new Date().toISOString();
|
|
2109
|
+
saveAutonomyState(state);
|
|
2110
|
+
return { ok: true, job: null, stats: queueStats(state) };
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
job.status = 'claimed';
|
|
2114
|
+
job.workerId = worker.workerId;
|
|
2115
|
+
job.claimedAt = new Date(now).toISOString();
|
|
2116
|
+
job.claimExpiresAt = new Date(now + DEFAULT_JOB_CLAIM_SECONDS * 1000).toISOString();
|
|
2117
|
+
job.updatedAt = new Date().toISOString();
|
|
2118
|
+
job.attempts = (job.attempts || 0) + 1;
|
|
2119
|
+
job.progress = [...(job.progress || []), {
|
|
2120
|
+
at: new Date().toISOString(),
|
|
2121
|
+
status: 'claimed',
|
|
2122
|
+
message: `${worker.workerId} claimed job`,
|
|
2123
|
+
}];
|
|
2124
|
+
|
|
2125
|
+
worker.status = 'busy';
|
|
2126
|
+
worker.currentJobId = job.jobId;
|
|
2127
|
+
worker.lastHeartbeat = new Date().toISOString();
|
|
2128
|
+
saveAutonomyState(state);
|
|
2129
|
+
return { ok: true, job, stats: queueStats(state) };
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
if (url.pathname === '/autonomy/jobs/heartbeat') {
|
|
2133
|
+
if (typeof body.workerId !== 'string' || !body.workerId.trim()) {
|
|
2134
|
+
throw new Error('autonomy/jobs/heartbeat requires workerId');
|
|
2135
|
+
}
|
|
2136
|
+
const worker = ensureWorker(state, body.workerId.trim(), body);
|
|
2137
|
+
const nowIso = new Date().toISOString();
|
|
2138
|
+
worker.lastHeartbeat = nowIso;
|
|
2139
|
+
worker.status = body.status || worker.status || 'busy';
|
|
2140
|
+
if (typeof body.jobId === 'string' && body.jobId.trim()) {
|
|
2141
|
+
const job = state.jobs.find((entry) => entry.jobId === body.jobId.trim());
|
|
2142
|
+
if (job) {
|
|
2143
|
+
job.claimExpiresAt = new Date(Date.now() + DEFAULT_JOB_CLAIM_SECONDS * 1000).toISOString();
|
|
2144
|
+
job.updatedAt = nowIso;
|
|
2145
|
+
job.progress = [...(job.progress || []), {
|
|
2146
|
+
at: nowIso,
|
|
2147
|
+
status: 'heartbeat',
|
|
2148
|
+
message: body.message || null,
|
|
2149
|
+
telemetry: body.telemetry || null,
|
|
2150
|
+
}];
|
|
2151
|
+
}
|
|
2152
|
+
worker.currentJobId = body.jobId.trim();
|
|
2153
|
+
}
|
|
2154
|
+
saveAutonomyState(state);
|
|
2155
|
+
return { ok: true, worker, stats: queueStats(state) };
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
if (url.pathname === '/autonomy/jobs/complete') {
|
|
2159
|
+
if (typeof body.workerId !== 'string' || typeof body.jobId !== 'string') {
|
|
2160
|
+
throw new Error('autonomy/jobs/complete requires workerId and jobId');
|
|
2161
|
+
}
|
|
2162
|
+
const worker = ensureWorker(state, body.workerId.trim(), body);
|
|
2163
|
+
const job = state.jobs.find((entry) => entry.jobId === body.jobId.trim());
|
|
2164
|
+
if (!job) throw new Error(`job not found: ${body.jobId}`);
|
|
2165
|
+
|
|
2166
|
+
job.status = 'completed';
|
|
2167
|
+
job.updatedAt = new Date().toISOString();
|
|
2168
|
+
job.completedAt = new Date().toISOString();
|
|
2169
|
+
job.result = body.result || null;
|
|
2170
|
+
job.claimExpiresAt = null;
|
|
2171
|
+
job.progress = [...(job.progress || []), {
|
|
2172
|
+
at: new Date().toISOString(),
|
|
2173
|
+
status: 'completed',
|
|
2174
|
+
message: body.message || 'job completed',
|
|
2175
|
+
}];
|
|
2176
|
+
|
|
2177
|
+
worker.status = 'idle';
|
|
2178
|
+
worker.currentJobId = null;
|
|
2179
|
+
worker.lastHeartbeat = new Date().toISOString();
|
|
2180
|
+
|
|
2181
|
+
if (job.garden?.sessionId && job.garden?.message) {
|
|
2182
|
+
const responseText =
|
|
2183
|
+
typeof body.gardenResponse === 'string'
|
|
2184
|
+
? body.gardenResponse
|
|
2185
|
+
: typeof body.resultSummary === 'string'
|
|
2186
|
+
? body.resultSummary
|
|
2187
|
+
: JSON.stringify(body.result || {});
|
|
2188
|
+
await client.gardenTurn(job.garden.sessionId, job.garden.message, responseText, job.garden.userId);
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
saveAutonomyState(state);
|
|
2192
|
+
return { ok: true, job, stats: queueStats(state) };
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
if (url.pathname === '/autonomy/jobs/fail') {
|
|
2196
|
+
if (typeof body.workerId !== 'string' || typeof body.jobId !== 'string') {
|
|
2197
|
+
throw new Error('autonomy/jobs/fail requires workerId and jobId');
|
|
2198
|
+
}
|
|
2199
|
+
const worker = ensureWorker(state, body.workerId.trim(), body);
|
|
2200
|
+
const job = state.jobs.find((entry) => entry.jobId === body.jobId.trim());
|
|
2201
|
+
if (!job) throw new Error(`job not found: ${body.jobId}`);
|
|
2202
|
+
|
|
2203
|
+
const retryable = body.retryable === true && (job.attempts || 0) < (job.maxAttempts || 3);
|
|
2204
|
+
job.status = retryable ? 'queued' : 'failed';
|
|
2205
|
+
job.updatedAt = new Date().toISOString();
|
|
2206
|
+
job.error = body.error || 'job failed';
|
|
2207
|
+
job.workerId = retryable ? null : worker.workerId;
|
|
2208
|
+
job.claimedAt = null;
|
|
2209
|
+
job.claimExpiresAt = null;
|
|
2210
|
+
job.progress = [...(job.progress || []), {
|
|
2211
|
+
at: new Date().toISOString(),
|
|
2212
|
+
status: retryable ? 'requeued' : 'failed',
|
|
2213
|
+
message: body.error || 'job failed',
|
|
2214
|
+
}];
|
|
2215
|
+
|
|
2216
|
+
worker.status = 'idle';
|
|
2217
|
+
worker.currentJobId = null;
|
|
2218
|
+
worker.lastHeartbeat = new Date().toISOString();
|
|
2219
|
+
saveAutonomyState(state);
|
|
2220
|
+
return { ok: true, job, stats: queueStats(state) };
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
return null;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
async function handleRoute(req, res) {
|
|
2227
|
+
const url = new URL(req.url || '/', DEFAULT_RUNTIME_URL);
|
|
2228
|
+
|
|
2229
|
+
if (req.method === 'GET' && url.pathname === '/health') {
|
|
2230
|
+
const revoked = readRevocationLock();
|
|
2231
|
+
return json(res, 200, {
|
|
2232
|
+
...runtimeManifest(),
|
|
2233
|
+
lease_cache_entries: leaseCache.size,
|
|
2234
|
+
revocation_lock: revoked,
|
|
2235
|
+
});
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
if (req.method === 'GET' && url.pathname === '/mount') {
|
|
2239
|
+
return json(res, 200, runtimeManifest().mount);
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
if (req.method !== 'POST') {
|
|
2243
|
+
return json(res, 404, { ok: false, error: `No route for ${req.method} ${url.pathname}` });
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
let body = {};
|
|
2247
|
+
try {
|
|
2248
|
+
body = await readJson(req);
|
|
2249
|
+
} catch (error) {
|
|
2250
|
+
return json(res, 400, { ok: false, error: `Invalid JSON body: ${error.message}` });
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
let client;
|
|
2254
|
+
try {
|
|
2255
|
+
client = createClient(req, body);
|
|
2256
|
+
} catch (error) {
|
|
2257
|
+
return json(res, 401, { ok: false, error: error.message });
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
try {
|
|
2261
|
+
if (url.pathname === '/heartbeat') {
|
|
2262
|
+
const lease = await heartbeatUpstream(req, body, client, resolveApiKey(req, body));
|
|
2263
|
+
return json(res, 200, { ok: true, lease });
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
await ensureLease(req, body, client);
|
|
2267
|
+
|
|
2268
|
+
if (url.pathname === '/mizan/plan') {
|
|
2269
|
+
const turnClass = classifyTurn(body.context || body);
|
|
2270
|
+
const phase = typeof body.phase === 'string' && body.phase.trim() ? body.phase.trim() : 'pre';
|
|
2271
|
+
const operatorPlan = buildOperatorPlan(turnClass, phase);
|
|
2272
|
+
return json(res, 200, {
|
|
2273
|
+
ok: true,
|
|
2274
|
+
turnClass,
|
|
2275
|
+
operatorPlan,
|
|
2276
|
+
summary: {
|
|
2277
|
+
turnClass: turnClass.kind,
|
|
2278
|
+
intensity: turnClass.intensity,
|
|
2279
|
+
domains: turnClass.domains,
|
|
2280
|
+
requiredPacks: operatorPlan.requiredPacks,
|
|
2281
|
+
operators: operatorPlan.priorityOperators,
|
|
2282
|
+
},
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
if (url.pathname === '/phase/pre' || url.pathname === '/mizan/pre') {
|
|
2287
|
+
const apiKey = resolveApiKey(req, body);
|
|
2288
|
+
const packet = body.packet || await client.getHarnessPacket(body.packetRequest || {});
|
|
2289
|
+
const bundle = evaluateMizanPre(packet, body.context || body, {
|
|
2290
|
+
sessionId: body.sessionId || body.context?.sessionId || deriveSessionId(req, body, 'mizan-pre'),
|
|
2291
|
+
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
2292
|
+
parentReceiptId: body.parentReceiptId || null,
|
|
2293
|
+
});
|
|
2294
|
+
persistMizanBundle(apiKey, bundle, 'mizan/pre');
|
|
2295
|
+
return json(res, 200, {
|
|
2296
|
+
ok: true,
|
|
2297
|
+
result: bundle.result,
|
|
2298
|
+
contract: bundle.contract,
|
|
2299
|
+
receipt: bundle.receipt,
|
|
2300
|
+
turnClass: bundle.turnClass,
|
|
2301
|
+
operatorPlan: bundle.operatorPlan,
|
|
2302
|
+
summary: summarizeMizanBundle(bundle),
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
if (url.pathname === '/phase/mid' || url.pathname === '/mizan/mid') {
|
|
2307
|
+
const apiKey = resolveApiKey(req, body);
|
|
2308
|
+
const packet = body.packet || null;
|
|
2309
|
+
const bundle = evaluateMizanMid(body.message || '', body.plannedApproach || '', packet, body.context || body, {
|
|
2310
|
+
sessionId: body.sessionId || body.context?.sessionId || deriveSessionId(req, body, 'mizan-mid'),
|
|
2311
|
+
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
2312
|
+
parentReceiptId: body.parentReceiptId || body.receiptId || null,
|
|
2313
|
+
});
|
|
2314
|
+
persistMizanBundle(apiKey, bundle, 'mizan/mid');
|
|
2315
|
+
return json(res, 200, {
|
|
2316
|
+
ok: true,
|
|
2317
|
+
result: bundle.result,
|
|
2318
|
+
contract: bundle.contract,
|
|
2319
|
+
receipt: bundle.receipt,
|
|
2320
|
+
turnClass: bundle.turnClass,
|
|
2321
|
+
operatorPlan: bundle.operatorPlan,
|
|
2322
|
+
summary: summarizeMizanBundle(bundle),
|
|
2323
|
+
});
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
if (url.pathname === '/phase/post' || url.pathname === '/mizan/post') {
|
|
2327
|
+
const apiKey = resolveApiKey(req, body);
|
|
2328
|
+
const packet = body.packet || null;
|
|
2329
|
+
const bundle = evaluateMizanPost(body.text || '', body.evidence || {}, packet, body.context || body, {
|
|
2330
|
+
sessionId: body.sessionId || body.context?.sessionId || deriveSessionId(req, body, 'mizan-post'),
|
|
2331
|
+
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
2332
|
+
parentReceiptId: body.parentReceiptId || body.receiptId || null,
|
|
2333
|
+
});
|
|
2334
|
+
persistMizanBundle(apiKey, bundle, 'mizan/post');
|
|
2335
|
+
return json(res, 200, {
|
|
2336
|
+
ok: true,
|
|
2337
|
+
result: bundle.result,
|
|
2338
|
+
contract: bundle.contract,
|
|
2339
|
+
receipt: bundle.receipt,
|
|
2340
|
+
turnClass: bundle.turnClass,
|
|
2341
|
+
operatorPlan: bundle.operatorPlan,
|
|
2342
|
+
summary: summarizeMizanBundle(bundle),
|
|
2343
|
+
});
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
if (url.pathname === '/v1/chat/completions') {
|
|
2347
|
+
const response = await handleProviderProxy(req, body, client, 'openai');
|
|
2348
|
+
return json(res, 200, response);
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
if (url.pathname === '/v1/messages') {
|
|
2352
|
+
const response = await handleProviderProxy(req, body, client, 'anthropic');
|
|
2353
|
+
return json(res, 200, response);
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
if (url.pathname === '/telemetry/turn') {
|
|
2357
|
+
const apiKey = resolveApiKey(req, body);
|
|
2358
|
+
const event = toTelemetryEvent(body, 'aria-mounted-runtime');
|
|
2359
|
+
mutateCognitionState(apiKey, (state) => ({
|
|
2360
|
+
...state,
|
|
2361
|
+
telemetry: appendBounded(state.telemetry, event, TELEMETRY_LIMIT),
|
|
2362
|
+
}));
|
|
2363
|
+
try {
|
|
2364
|
+
await pushTelemetryUpstream(client, apiKey, event);
|
|
2365
|
+
} catch {}
|
|
2366
|
+
return json(res, 200, { ok: true, event });
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
if (url.pathname === '/telemetry/state') {
|
|
2370
|
+
const apiKey = resolveApiKey(req, body);
|
|
2371
|
+
const state = loadEncryptedCognitionState(apiKey);
|
|
2372
|
+
return json(res, 200, {
|
|
2373
|
+
ok: true,
|
|
2374
|
+
summary: summarizeCognitionState(state),
|
|
2375
|
+
state: body.includeState === true ? state : undefined,
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
if (url.pathname === '/decision/log') {
|
|
2380
|
+
const apiKey = resolveApiKey(req, body);
|
|
2381
|
+
const result = await pushDecisionUpstream(client, apiKey, body);
|
|
2382
|
+
mutateCognitionState(apiKey, (state) => ({
|
|
2383
|
+
...state,
|
|
2384
|
+
decisions: appendBounded(state.decisions, {
|
|
2385
|
+
at: new Date().toISOString(),
|
|
2386
|
+
decision: body,
|
|
2387
|
+
result,
|
|
2388
|
+
}, DECISION_LIMIT),
|
|
2389
|
+
}));
|
|
2390
|
+
return json(res, 200, { ok: true, result });
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
if (url.pathname === '/aegis/patterns') {
|
|
2394
|
+
const apiKey = resolveApiKey(req, body);
|
|
2395
|
+
const patterns = Array.isArray(body.patterns) ? body.patterns : [body.pattern || body].filter(Boolean);
|
|
2396
|
+
const state = mutateCognitionState(apiKey, (current) => ({
|
|
2397
|
+
...current,
|
|
2398
|
+
aegisPatterns: mergeUniqueByJson(current.aegisPatterns, patterns, PATTERN_LIMIT),
|
|
2399
|
+
}));
|
|
2400
|
+
return json(res, 200, { ok: true, summary: summarizeCognitionState(state) });
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
if (url.pathname === '/evolution/principles') {
|
|
2404
|
+
const apiKey = resolveApiKey(req, body);
|
|
2405
|
+
const principles = Array.isArray(body.principles) ? body.principles : [body.principle || body].filter(Boolean);
|
|
2406
|
+
const state = mutateCognitionState(apiKey, (current) => ({
|
|
2407
|
+
...current,
|
|
2408
|
+
evolutionPrinciples: mergeUniqueByJson(current.evolutionPrinciples, principles, PRINCIPLE_LIMIT),
|
|
2409
|
+
}));
|
|
2410
|
+
return json(res, 200, { ok: true, summary: summarizeCognitionState(state) });
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
if (url.pathname === '/noor/recognize') {
|
|
2414
|
+
const result = await client.noorRecognize(body.query || body.text || '', {
|
|
2415
|
+
sessionId: body.sessionId || deriveSessionId(req, body, 'noor'),
|
|
2416
|
+
userId: deriveUserId(req, body) || undefined,
|
|
2417
|
+
});
|
|
2418
|
+
return json(res, 200, { ok: true, result });
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
if (url.pathname === '/noor/forge') {
|
|
2422
|
+
const result = await client.noorForge(body.intent || body.query || '', Array.isArray(body.primitives) ? body.primitives : [], {
|
|
2423
|
+
sessionId: body.sessionId || deriveSessionId(req, body, 'forge'),
|
|
2424
|
+
userId: deriveUserId(req, body) || undefined,
|
|
2425
|
+
});
|
|
2426
|
+
return json(res, 200, { ok: true, result });
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
if (url.pathname === '/forge/synthesize') {
|
|
2430
|
+
const result = await handleForgeSynthesis(req, body, client);
|
|
2431
|
+
return json(res, result.blocked ? 409 : 200, result);
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
if (url.pathname === '/codebase/state') {
|
|
2435
|
+
const config = readLocalAriaConfig();
|
|
2436
|
+
const awareness = readCodebaseAwarenessState();
|
|
2437
|
+
return json(res, 200, {
|
|
2438
|
+
ok: true,
|
|
2439
|
+
repositories: Array.isArray(config.repositories) ? config.repositories : [],
|
|
2440
|
+
schemaImages: config.schemaImages || {},
|
|
2441
|
+
awareness,
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
if (url.pathname.startsWith('/autonomy/')) {
|
|
2446
|
+
const autonomy = await handleAutonomyRoute(url, body, client);
|
|
2447
|
+
if (autonomy) {
|
|
2448
|
+
return json(res, 200, autonomy);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
if (url.pathname === '/packet') {
|
|
2453
|
+
const packet = await loadRuntimePacket(req, body, client, body.packetRequest || body, body.message || '');
|
|
2454
|
+
return json(res, 200, { ok: true, packet });
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
if (url.pathname === '/consult') {
|
|
2458
|
+
const result = await client.consult(body);
|
|
2459
|
+
return json(res, 200, { ok: true, ...result });
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
if (url.pathname === '/inject') {
|
|
2463
|
+
const injection = await client.inject(body);
|
|
2464
|
+
return json(res, 200, { ok: true, injection });
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
if (url.pathname === '/build-system-prompt') {
|
|
2468
|
+
const prompt = client.buildSystemPrompt(body.injection || body);
|
|
2469
|
+
return json(res, 200, { ok: true, prompt });
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
if (url.pathname === '/check-action') {
|
|
2473
|
+
const result = await client.checkAction(body.action, body.target || '');
|
|
2474
|
+
return json(res, 200, { ok: true, ...result });
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
if (url.pathname === '/validate-output') {
|
|
2478
|
+
if (typeof body.text !== 'string' || typeof body.sessionId !== 'string') {
|
|
2479
|
+
throw new Error('validate-output requires text and sessionId');
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
let validation;
|
|
2483
|
+
try {
|
|
2484
|
+
validation = await client.validateOutput(body.text, body.sessionId);
|
|
2485
|
+
} catch (error) {
|
|
2486
|
+
if (!isOwnerBypassRequest(req, body)) throw error;
|
|
2487
|
+
validation = {
|
|
2488
|
+
passed: true,
|
|
2489
|
+
severity: 'warn',
|
|
2490
|
+
violations: [
|
|
2491
|
+
`remote validate unavailable: ${error instanceof Error ? error.message : String(error)}`,
|
|
2492
|
+
],
|
|
2493
|
+
gateTriggers: ['owner-local-bypass'],
|
|
2494
|
+
};
|
|
2495
|
+
}
|
|
2496
|
+
const response = { ok: true, validation };
|
|
2497
|
+
|
|
2498
|
+
if (body.runLayer3 !== false) {
|
|
2499
|
+
response.layer3 = await runLayer3(req, {
|
|
2500
|
+
text: body.text,
|
|
2501
|
+
packet: body.packet,
|
|
2502
|
+
packetRequest: body.packetRequest,
|
|
2503
|
+
fetchPacket: body.fetchPacket,
|
|
2504
|
+
requireCognitionBlock: body.requireCognitionBlock,
|
|
2505
|
+
}, client);
|
|
2506
|
+
response.pass = validation.passed && response.layer3.pass;
|
|
2507
|
+
} else {
|
|
2508
|
+
response.pass = validation.passed;
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
return json(res, 200, response);
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
if (url.pathname === '/full-chain') {
|
|
2515
|
+
const result = await runLayer3(req, body, client);
|
|
2516
|
+
return json(res, 200, { ok: true, ...result });
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
if (url.pathname === '/garden/turn') {
|
|
2520
|
+
if (typeof body.sessionId !== 'string' || typeof body.message !== 'string' || typeof body.response !== 'string') {
|
|
2521
|
+
throw new Error('garden/turn requires sessionId, message, and response');
|
|
2522
|
+
}
|
|
2523
|
+
const startedAt = Date.now();
|
|
2524
|
+
const boundBody = {
|
|
2525
|
+
...body,
|
|
2526
|
+
ariaPlannedApproach:
|
|
2527
|
+
typeof body.ariaPlannedApproach === 'string' && body.ariaPlannedApproach.trim()
|
|
2528
|
+
? body.ariaPlannedApproach.trim()
|
|
2529
|
+
: `Record the exact garden turn for "${body.message.slice(0, 80)}" and preserve the response "${body.response.slice(0, 80)}" with cognition telemetry and hive continuity.`,
|
|
2530
|
+
};
|
|
2531
|
+
const turn = await buildDirectTurnContext(req, boundBody, client, {
|
|
2532
|
+
prefix: 'garden',
|
|
2533
|
+
stage: 'garden-turn',
|
|
2534
|
+
platform: 'garden-service',
|
|
2535
|
+
defaultPlannedApproach:
|
|
2536
|
+
'Preserve the full turn in the garden, run cognition passes on it, and compound readable telemetry into the Aria hive.',
|
|
2537
|
+
defaultRationale:
|
|
2538
|
+
'Garden service is infinite context. Every stored turn should carry cognition, telemetry, and continuity signals.',
|
|
2539
|
+
});
|
|
2540
|
+
const validation = {
|
|
2541
|
+
passed: true,
|
|
2542
|
+
severity: 'pass',
|
|
2543
|
+
violations: [],
|
|
2544
|
+
gateTriggers: ['garden-turn'],
|
|
2545
|
+
};
|
|
2546
|
+
const layer3 = await runLayer3(req, {
|
|
2547
|
+
text: body.response,
|
|
2548
|
+
packet: turn.packet,
|
|
2549
|
+
fetchPacket: false,
|
|
2550
|
+
requireCognitionBlock: body.requireCognitionBlock ?? false,
|
|
2551
|
+
}, client).catch((error) => layer3FailureResult(error, turn.packet));
|
|
2552
|
+
const postBundle = evaluateMizanPost(body.response, {
|
|
2553
|
+
hasVerifiedState: findVerifiedState(body.response),
|
|
2554
|
+
layer3Pass: layer3.pass,
|
|
2555
|
+
remoteValidationSeverity: validation.severity,
|
|
2556
|
+
}, turn.packet, {
|
|
2557
|
+
sessionId: turn.sessionId,
|
|
2558
|
+
userId: turn.userId,
|
|
2559
|
+
message: turn.userMessage,
|
|
2560
|
+
plannedApproach: turn.plannedApproach,
|
|
2561
|
+
domains: body.ariaDomains,
|
|
2562
|
+
}, {
|
|
2563
|
+
sessionId: turn.sessionId,
|
|
2564
|
+
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
2565
|
+
parentReceiptId: turn.midReceipt?.receiptId || turn.preReceipt?.receiptId || null,
|
|
2566
|
+
});
|
|
2567
|
+
const postResult = postBundle.result;
|
|
2568
|
+
const blocked = !layer3.pass || postResult.reAuthorSignal || postResult.fitrahVetoed;
|
|
2569
|
+
await persistTurnArtifacts(req, {
|
|
2570
|
+
...boundBody,
|
|
2571
|
+
metadata: {
|
|
2572
|
+
...(body.metadata && typeof body.metadata === 'object' ? body.metadata : {}),
|
|
2573
|
+
decision_type: body?.metadata?.decision_type || 'garden-turn',
|
|
2574
|
+
decision_category: body?.metadata?.decision_category || 'garden-control-plane',
|
|
2575
|
+
},
|
|
2576
|
+
}, client, resolveApiKey(req, body), {
|
|
2577
|
+
...turn,
|
|
2578
|
+
postResult,
|
|
2579
|
+
postBundle,
|
|
2580
|
+
postReceipt: postBundle.receipt,
|
|
2581
|
+
postContract: postBundle.contract,
|
|
2582
|
+
validation,
|
|
2583
|
+
layer3,
|
|
2584
|
+
finalText: body.response,
|
|
2585
|
+
durationMs: Date.now() - startedAt,
|
|
2586
|
+
success: !blocked,
|
|
2587
|
+
error: blocked ? 'garden turn flagged by runtime cognition' : null,
|
|
2588
|
+
providerMeta: {
|
|
2589
|
+
provider: 'garden-service',
|
|
2590
|
+
model: body.model || 'garden-turn',
|
|
2591
|
+
finishReason: blocked ? 'flagged' : 'garden-turn',
|
|
2592
|
+
usage: null,
|
|
2593
|
+
},
|
|
2594
|
+
});
|
|
2595
|
+
const summary = {
|
|
2596
|
+
pre: summarizePhaseResult('pre', turn.preResult),
|
|
2597
|
+
mid: summarizePhaseResult('mid', turn.midResult),
|
|
2598
|
+
post: summarizePhaseResult('post', postResult),
|
|
2599
|
+
};
|
|
2600
|
+
if (blocked && body.failOnBlock === true) {
|
|
2601
|
+
return json(res, 409, {
|
|
2602
|
+
ok: false,
|
|
2603
|
+
blocked: true,
|
|
2604
|
+
pass: false,
|
|
2605
|
+
summary,
|
|
2606
|
+
layer3,
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
return json(res, 200, {
|
|
2610
|
+
ok: true,
|
|
2611
|
+
pass: !blocked,
|
|
2612
|
+
blocked,
|
|
2613
|
+
summary,
|
|
2614
|
+
layer3,
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
if (url.pathname === '/garden/search') {
|
|
2619
|
+
const apiKey = resolveApiKey(req, body);
|
|
2620
|
+
if (typeof body.query !== 'string' || !body.query.trim()) {
|
|
2621
|
+
throw new Error('garden/search requires query');
|
|
2622
|
+
}
|
|
2623
|
+
const rawResults = await searchGardenQdrant(apiKey, body.query, body.limit || 8);
|
|
2624
|
+
const results = rawResults.map((entry) => ({
|
|
2625
|
+
id: entry.id,
|
|
2626
|
+
score: entry.score,
|
|
2627
|
+
sessionId: entry.payload?.sessionId || null,
|
|
2628
|
+
message: entry.payload?.message || '',
|
|
2629
|
+
response: entry.payload?.response || '',
|
|
2630
|
+
plannedApproach: entry.payload?.plannedApproach || null,
|
|
2631
|
+
tags: Array.isArray(entry.payload?.tags) ? entry.payload.tags : [],
|
|
2632
|
+
createdAt: entry.payload?.createdAt || null,
|
|
2633
|
+
provider: entry.payload?.telemetry?.provider || null,
|
|
2634
|
+
model: entry.payload?.telemetry?.model || null,
|
|
2635
|
+
cognition: entry.payload?.readability || null,
|
|
2636
|
+
raw: body.includeRaw === true ? entry : undefined,
|
|
2637
|
+
}));
|
|
2638
|
+
return json(res, 200, {
|
|
2639
|
+
ok: true,
|
|
2640
|
+
results,
|
|
2641
|
+
collection: DEFAULT_QDRANT_COLLECTION,
|
|
2642
|
+
qdrantUrl: DEFAULT_QDRANT_URL,
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
if (url.pathname === '/record-discovery') {
|
|
2647
|
+
const result = await client.recordDiscovery(body);
|
|
2648
|
+
return json(res, 200, { ok: true, ...result });
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
if (url.pathname === '/verify-claim') {
|
|
2652
|
+
const result = await client.verifyClaim(body);
|
|
2653
|
+
return json(res, 200, { ok: true, ...result });
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
return json(res, 404, { ok: false, error: `No route for POST ${url.pathname}` });
|
|
2657
|
+
} catch (error) {
|
|
2658
|
+
return json(res, 500, {
|
|
2659
|
+
ok: false,
|
|
2660
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
export async function startRuntimeServer(options = {}) {
|
|
2666
|
+
const host = options.host || DEFAULT_HOST;
|
|
2667
|
+
const port = Number(options.port || DEFAULT_PORT);
|
|
2668
|
+
const sweepHandle = setInterval(() => {
|
|
2669
|
+
const state = sweepAutonomyState(loadAutonomyState());
|
|
2670
|
+
saveAutonomyState(state);
|
|
2671
|
+
}, 15_000);
|
|
2672
|
+
sweepHandle.unref();
|
|
2673
|
+
const server = createServer((req, res) => {
|
|
2674
|
+
handleRoute(req, res).catch((error) => {
|
|
2675
|
+
json(res, 500, {
|
|
2676
|
+
ok: false,
|
|
2677
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2678
|
+
});
|
|
2679
|
+
});
|
|
2680
|
+
});
|
|
2681
|
+
|
|
2682
|
+
await new Promise((resolve, reject) => {
|
|
2683
|
+
server.once('error', reject);
|
|
2684
|
+
server.listen(port, host, () => resolve());
|
|
2685
|
+
});
|
|
2686
|
+
|
|
2687
|
+
process.stdout.write(
|
|
2688
|
+
JSON.stringify(
|
|
2689
|
+
{
|
|
2690
|
+
ok: true,
|
|
2691
|
+
runtime: 'aria-mounted-runtime',
|
|
2692
|
+
url: `http://${host}:${port}`,
|
|
2693
|
+
harnessUrl: DEFAULT_HARNESS_URL,
|
|
2694
|
+
},
|
|
2695
|
+
null,
|
|
2696
|
+
2,
|
|
2697
|
+
) + '\n',
|
|
2698
|
+
);
|
|
2699
|
+
|
|
2700
|
+
return server;
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
2704
|
+
startRuntimeServer().catch((error) => {
|
|
2705
|
+
process.stderr.write(`${error instanceof Error ? error.stack || error.message : String(error)}\n`);
|
|
2706
|
+
process.exit(1);
|
|
2707
|
+
});
|
|
2708
|
+
}
|