Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions feat/aegis-sdk-integration
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Drop files into their correct locations:
cp aegis-adapter.mjs sdk/aegis-adapter.mjs
cp CLAUDE.md CLAUDE.md
cp adapter.test.mjs tests/aegis/adapter.test.mjs
cp aegis-health.mjs scripts/aegis-health.mjs
cp crucix-ci.yml .github/workflows/crucix-ci.yml
cp package.json package.json
cp .env.example .env.example

mkdir -p .claude/skills docs/agent-guides
cp aegis-sdk.md .claude/skills/aegis-sdk.md
cp build-test-verify.md .claude/skills/build-test-verify.md
cp git-commit.md .claude/skills/git-commit.md
cp architecture.md docs/agent-guides/architecture.md
cp aegis-sdk-guide.md docs/agent-guides/aegis-sdk-guide.md
123 changes: 123 additions & 0 deletions sdk/aegis-adapter.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* sdk/aegis-adapter.mjs
* Ethos Aegis integration layer for Crucix.
* Uses the native Node.js AegisClient for robust subprocess/HTTP management.
*/

import { AegisClient } from './ethos-aegis/sdk/node/src/index.js';

// ─── Config ───────────────────────────────────────────────────────────────────

const SIDECAR_URL = process.env.AEGIS_SIDECAR_URL || 'http://localhost:8080';
const BEARER_TOKEN = process.env.AEGIS_BEARER_TOKEN || 'local-dev-key';
const STRICT_MODE = process.env.AEGIS_STRICT_MODE === 'true';

// Initialize the real AegisClient
const aegis = new AegisClient({
baseUrl: SIDECAR_URL,
apiKey: BEARER_TOKEN,
throwOnCondemned: false, // We handle the escalation manually in Crucix
timeoutMs: parseInt(process.env.AEGIS_TIMEOUT_MS || '3000', 10)
});

// ─── Severity → Crucix tier mapping ──────────────────────────────────────────

/**
* Maps an Aegis depth to a Crucix alert tier.
* @param {string} depth
* @returns {'FLASH'|'PRIORITY'|'ROUTINE'|'PASS'}
*/
export function depthToTier(depth) {
switch (depth?.toUpperCase()) {
case 'CONDEMNED': return 'FLASH';
case 'GRAVE': return 'PRIORITY';
case 'CAUTION': return 'ROUTINE';
case 'TRACE': return 'ROUTINE';
case 'VOID':
default: return 'PASS';
}
}

// ─── Guard Functions ─────────────────────────────────────────────────────────

export async function guardInput(rawText, context = {}) {
try {
const verdict = await aegis.score(rawText, { guardPoint: 'input', ...context });
return {
sanctified: verdict.sanctified,
payload: verdict.sanitized || rawText, // Fallback to raw if not sanitized
verdict
};
} catch (err) {
if (STRICT_MODE) throw new Error(`[Aegis] Strict mode active. Blocked due to sidecar failure: ${err.message}`);
console.warn(`[Aegis] Warning: Sidecar unreachable. Failing open. (${err.message})`);
return { sanctified: true, payload: rawText, verdict: _syntheticPass() };
}
}

export async function guardOutput(llmResponse, context = {}) {
try {
const verdict = await aegis.score(llmResponse, { guardPoint: 'output', ...context });
return {
sanctified: verdict.sanctified,
payload: verdict.sanitized || llmResponse,
verdict
};
} catch (err) {
if (STRICT_MODE) throw new Error(`[Aegis] Output guard failed: ${err.message}`);
return { sanctified: true, payload: llmResponse, verdict: _syntheticPass() };
}
}

export async function guardBotCommand(commandText, userId) {
try {
const verdict = await aegis.score(commandText, { guardPoint: 'bot_command', userId });
return {
sanctified: verdict.sanctified,
payload: verdict.sanitized || commandText,
verdict
};
} catch (err) {
if (STRICT_MODE) throw new Error(`[Aegis] Bot command guard failed: ${err.message}`);
return { sanctified: true, payload: commandText, verdict: _syntheticPass() };
}
}

export async function evaluateSignal(signal) {
const { sanctified, payload, verdict } = await guardInput(signal.content, {
source: signal.source,
feedId: signal.id
});

const tier = depthToTier(verdict.depth);

if (!sanctified && verdict.condemned) {
console.error(`[Aegis] CONDEMNED Signal Blocked. RequestID: ${verdict.requestId}`);
return {
signal: { ...signal, content: '[CONTENT REDACTED BY AEGIS]' },
tier: 'FLASH',
blocked: true,
verdict,
};
}

return {
signal: { ...signal, content: payload ?? signal.content },
tier: tier === 'PASS' ? null : tier,
blocked: false,
verdict,
};
}

function _syntheticPass() {
return {
sanctified: true,
condemned: false,
depth: 'VOID',
malignaCount: 0,
sanitized: null,
report: 'Synthetic pass (sidecar offline)',
latencyMs: 0,
requestId: `synth-${Date.now()}`
};
}