magi-ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.ja.md +377 -0
- package/README.md +377 -0
- package/dist/bin/magi-benchmark.d.ts +14 -0
- package/dist/bin/magi-benchmark.js +93 -0
- package/dist/bin/magi-mcp.d.ts +8 -0
- package/dist/bin/magi-mcp.js +28 -0
- package/dist/bin/magi.d.ts +2 -0
- package/dist/bin/magi.js +634 -0
- package/dist/src/adapters/base.d.ts +34 -0
- package/dist/src/adapters/base.js +149 -0
- package/dist/src/adapters/claude.d.ts +29 -0
- package/dist/src/adapters/claude.js +65 -0
- package/dist/src/adapters/codex.d.ts +21 -0
- package/dist/src/adapters/codex.js +41 -0
- package/dist/src/adapters/gemini.d.ts +18 -0
- package/dist/src/adapters/gemini.js +31 -0
- package/dist/src/adapters/registry.d.ts +19 -0
- package/dist/src/adapters/registry.js +59 -0
- package/dist/src/audit/hash-chain.d.ts +21 -0
- package/dist/src/audit/hash-chain.js +70 -0
- package/dist/src/audit/types.d.ts +25 -0
- package/dist/src/audit/types.js +1 -0
- package/dist/src/audit/writer.d.ts +18 -0
- package/dist/src/audit/writer.js +100 -0
- package/dist/src/benchmark/golden-tasks.d.ts +9 -0
- package/dist/src/benchmark/golden-tasks.js +476 -0
- package/dist/src/benchmark/reporter.d.ts +5 -0
- package/dist/src/benchmark/reporter.js +107 -0
- package/dist/src/benchmark/runner.d.ts +30 -0
- package/dist/src/benchmark/runner.js +224 -0
- package/dist/src/benchmark/scorer.d.ts +12 -0
- package/dist/src/benchmark/scorer.js +124 -0
- package/dist/src/benchmark/types.d.ts +54 -0
- package/dist/src/benchmark/types.js +1 -0
- package/dist/src/cache/deliberation-cache.d.ts +49 -0
- package/dist/src/cache/deliberation-cache.js +127 -0
- package/dist/src/cli/commands/config-cmd.d.ts +11 -0
- package/dist/src/cli/commands/config-cmd.js +190 -0
- package/dist/src/cli/commands/demo.d.ts +12 -0
- package/dist/src/cli/commands/demo.js +66 -0
- package/dist/src/cli/commands/setup.d.ts +7 -0
- package/dist/src/cli/commands/setup.js +182 -0
- package/dist/src/cli/i18n.d.ts +89 -0
- package/dist/src/cli/i18n.js +176 -0
- package/dist/src/cli/interactive-select.d.ts +27 -0
- package/dist/src/cli/interactive-select.js +130 -0
- package/dist/src/cli/tui-setup.d.ts +24 -0
- package/dist/src/cli/tui-setup.js +42 -0
- package/dist/src/config/cli-detector.d.ts +37 -0
- package/dist/src/config/cli-detector.js +99 -0
- package/dist/src/config/user-config.d.ts +81 -0
- package/dist/src/config/user-config.js +134 -0
- package/dist/src/context/auto-collector.d.ts +43 -0
- package/dist/src/context/auto-collector.js +337 -0
- package/dist/src/context/manager.d.ts +35 -0
- package/dist/src/context/manager.js +162 -0
- package/dist/src/context/serializer.d.ts +20 -0
- package/dist/src/context/serializer.js +52 -0
- package/dist/src/demo/recorded-deliberation.d.ts +13 -0
- package/dist/src/demo/recorded-deliberation.js +277 -0
- package/dist/src/engine/angel-detector.d.ts +83 -0
- package/dist/src/engine/angel-detector.js +334 -0
- package/dist/src/engine/at-field.d.ts +40 -0
- package/dist/src/engine/at-field.js +195 -0
- package/dist/src/engine/berserk-orchestrator.d.ts +66 -0
- package/dist/src/engine/berserk-orchestrator.js +378 -0
- package/dist/src/engine/change-metrics.d.ts +56 -0
- package/dist/src/engine/change-metrics.js +214 -0
- package/dist/src/engine/consensus.d.ts +20 -0
- package/dist/src/engine/consensus.js +146 -0
- package/dist/src/engine/dead-sea-scrolls.d.ts +132 -0
- package/dist/src/engine/dead-sea-scrolls.js +610 -0
- package/dist/src/engine/drift-detector.d.ts +39 -0
- package/dist/src/engine/drift-detector.js +225 -0
- package/dist/src/engine/dummy-plug.d.ts +44 -0
- package/dist/src/engine/dummy-plug.js +190 -0
- package/dist/src/engine/engram-manager.d.ts +55 -0
- package/dist/src/engine/engram-manager.js +306 -0
- package/dist/src/engine/events.d.ts +130 -0
- package/dist/src/engine/events.js +44 -0
- package/dist/src/engine/gospel.d.ts +30 -0
- package/dist/src/engine/gospel.js +129 -0
- package/dist/src/engine/hallucination-detector.d.ts +33 -0
- package/dist/src/engine/hallucination-detector.js +215 -0
- package/dist/src/engine/human-resolver.d.ts +19 -0
- package/dist/src/engine/human-resolver.js +89 -0
- package/dist/src/engine/instrumentality.d.ts +64 -0
- package/dist/src/engine/instrumentality.js +297 -0
- package/dist/src/engine/iruel-battle.d.ts +79 -0
- package/dist/src/engine/iruel-battle.js +319 -0
- package/dist/src/engine/kernel/deliberation-kernel.d.ts +12 -0
- package/dist/src/engine/kernel/deliberation-kernel.js +303 -0
- package/dist/src/engine/kernel/index.d.ts +8 -0
- package/dist/src/engine/kernel/index.js +7 -0
- package/dist/src/engine/kernel/phase-runner.d.ts +10 -0
- package/dist/src/engine/kernel/phase-runner.js +155 -0
- package/dist/src/engine/kernel/post-processor.d.ts +17 -0
- package/dist/src/engine/kernel/post-processor.js +131 -0
- package/dist/src/engine/kernel/types.d.ts +107 -0
- package/dist/src/engine/kernel/types.js +1 -0
- package/dist/src/engine/kernel/unit-executor.d.ts +6 -0
- package/dist/src/engine/kernel/unit-executor.js +132 -0
- package/dist/src/engine/lcl-manager.d.ts +44 -0
- package/dist/src/engine/lcl-manager.js +143 -0
- package/dist/src/engine/middleware/cache.d.ts +7 -0
- package/dist/src/engine/middleware/cache.js +29 -0
- package/dist/src/engine/middleware/chain.d.ts +18 -0
- package/dist/src/engine/middleware/chain.js +45 -0
- package/dist/src/engine/middleware/firewall.d.ts +8 -0
- package/dist/src/engine/middleware/firewall.js +24 -0
- package/dist/src/engine/middleware/index.d.ts +4 -0
- package/dist/src/engine/middleware/index.js +3 -0
- package/dist/src/engine/middleware/types.d.ts +43 -0
- package/dist/src/engine/middleware/types.js +1 -0
- package/dist/src/engine/nebuchadnezzar-key.d.ts +61 -0
- package/dist/src/engine/nebuchadnezzar-key.js +203 -0
- package/dist/src/engine/neon-genesis.d.ts +52 -0
- package/dist/src/engine/neon-genesis.js +203 -0
- package/dist/src/engine/objective-judge.d.ts +53 -0
- package/dist/src/engine/objective-judge.js +214 -0
- package/dist/src/engine/offline-mode.d.ts +18 -0
- package/dist/src/engine/offline-mode.js +46 -0
- package/dist/src/engine/orchestrator.d.ts +79 -0
- package/dist/src/engine/orchestrator.js +58 -0
- package/dist/src/engine/secret-cipher.d.ts +26 -0
- package/dist/src/engine/secret-cipher.js +114 -0
- package/dist/src/engine/seele-council.d.ts +90 -0
- package/dist/src/engine/seele-council.js +482 -0
- package/dist/src/engine/self-destruct.d.ts +61 -0
- package/dist/src/engine/self-destruct.js +231 -0
- package/dist/src/engine/self-evolution.d.ts +64 -0
- package/dist/src/engine/self-evolution.js +368 -0
- package/dist/src/engine/sync-rate.d.ts +45 -0
- package/dist/src/engine/sync-rate.js +151 -0
- package/dist/src/engine/type666-firewall.d.ts +76 -0
- package/dist/src/engine/type666-firewall.js +343 -0
- package/dist/src/engine/umbilical-cable.d.ts +41 -0
- package/dist/src/engine/umbilical-cable.js +192 -0
- package/dist/src/index.d.ts +106 -0
- package/dist/src/index.js +426 -0
- package/dist/src/mcp/server.d.ts +38 -0
- package/dist/src/mcp/server.js +196 -0
- package/dist/src/metrics/token-tracker.d.ts +38 -0
- package/dist/src/metrics/token-tracker.js +112 -0
- package/dist/src/parsers/json-extractor.d.ts +9 -0
- package/dist/src/parsers/json-extractor.js +239 -0
- package/dist/src/parsers/opinion-schema.d.ts +81 -0
- package/dist/src/parsers/opinion-schema.js +147 -0
- package/dist/src/parsers/unstructured-parser.d.ts +20 -0
- package/dist/src/parsers/unstructured-parser.js +122 -0
- package/dist/src/pipelines/architecture.d.ts +10 -0
- package/dist/src/pipelines/architecture.js +9 -0
- package/dist/src/pipelines/bug-analysis.d.ts +9 -0
- package/dist/src/pipelines/bug-analysis.js +8 -0
- package/dist/src/pipelines/code-review.d.ts +10 -0
- package/dist/src/pipelines/code-review.js +30 -0
- package/dist/src/pipelines/custom.d.ts +14 -0
- package/dist/src/pipelines/custom.js +29 -0
- package/dist/src/pipelines/registry.d.ts +9 -0
- package/dist/src/pipelines/registry.js +20 -0
- package/dist/src/prompts/personas.d.ts +6 -0
- package/dist/src/prompts/personas.js +44 -0
- package/dist/src/prompts/schemas.d.ts +4 -0
- package/dist/src/prompts/schemas.js +24 -0
- package/dist/src/prompts/templates.d.ts +6 -0
- package/dist/src/prompts/templates.js +91 -0
- package/dist/src/repl/accessibility.d.ts +23 -0
- package/dist/src/repl/accessibility.js +46 -0
- package/dist/src/repl/banner.d.ts +4 -0
- package/dist/src/repl/banner.js +28 -0
- package/dist/src/repl/boot-animation.d.ts +13 -0
- package/dist/src/repl/boot-animation.js +143 -0
- package/dist/src/repl/completer.d.ts +21 -0
- package/dist/src/repl/completer.js +168 -0
- package/dist/src/repl/context.d.ts +24 -0
- package/dist/src/repl/context.js +42 -0
- package/dist/src/repl/display-utils.d.ts +13 -0
- package/dist/src/repl/display-utils.js +65 -0
- package/dist/src/repl/event-listener.d.ts +18 -0
- package/dist/src/repl/event-listener.js +112 -0
- package/dist/src/repl/export-formatter.d.ts +8 -0
- package/dist/src/repl/export-formatter.js +73 -0
- package/dist/src/repl/ghost-text.d.ts +31 -0
- package/dist/src/repl/ghost-text.js +119 -0
- package/dist/src/repl/handoff-animation.d.ts +15 -0
- package/dist/src/repl/handoff-animation.js +65 -0
- package/dist/src/repl/history.d.ts +16 -0
- package/dist/src/repl/history.js +130 -0
- package/dist/src/repl/job-registry.d.ts +26 -0
- package/dist/src/repl/job-registry.js +80 -0
- package/dist/src/repl/magi-repl.d.ts +72 -0
- package/dist/src/repl/magi-repl.js +1008 -0
- package/dist/src/repl/multiline-input.d.ts +45 -0
- package/dist/src/repl/multiline-input.js +78 -0
- package/dist/src/repl/prompt-builder.d.ts +19 -0
- package/dist/src/repl/prompt-builder.js +36 -0
- package/dist/src/repl/repl-state.d.ts +5 -0
- package/dist/src/repl/repl-state.js +19 -0
- package/dist/src/repl/result-display.d.ts +8 -0
- package/dist/src/repl/result-display.js +195 -0
- package/dist/src/repl/session-stats.d.ts +26 -0
- package/dist/src/repl/session-stats.js +119 -0
- package/dist/src/repl/slash-commands.d.ts +60 -0
- package/dist/src/repl/slash-commands.js +725 -0
- package/dist/src/repl/terminal-sanitize.d.ts +14 -0
- package/dist/src/repl/terminal-sanitize.js +19 -0
- package/dist/src/reporters/console.d.ts +7 -0
- package/dist/src/reporters/console.js +78 -0
- package/dist/src/reporters/json.d.ts +2 -0
- package/dist/src/reporters/json.js +3 -0
- package/dist/src/reporters/markdown.d.ts +2 -0
- package/dist/src/reporters/markdown.js +65 -0
- package/dist/src/reporters/streaming.d.ts +20 -0
- package/dist/src/reporters/streaming.js +178 -0
- package/dist/src/tui/activity-log.d.ts +23 -0
- package/dist/src/tui/activity-log.js +67 -0
- package/dist/src/tui/animations.d.ts +39 -0
- package/dist/src/tui/animations.js +167 -0
- package/dist/src/tui/ansi.d.ts +28 -0
- package/dist/src/tui/ansi.js +51 -0
- package/dist/src/tui/boot-sequence.d.ts +11 -0
- package/dist/src/tui/boot-sequence.js +98 -0
- package/dist/src/tui/colors.d.ts +101 -0
- package/dist/src/tui/colors.js +71 -0
- package/dist/src/tui/header.d.ts +24 -0
- package/dist/src/tui/header.js +122 -0
- package/dist/src/tui/index.d.ts +3 -0
- package/dist/src/tui/index.js +3 -0
- package/dist/src/tui/keypress.d.ts +25 -0
- package/dist/src/tui/keypress.js +95 -0
- package/dist/src/tui/layout.d.ts +74 -0
- package/dist/src/tui/layout.js +171 -0
- package/dist/src/tui/magi-tui.d.ts +101 -0
- package/dist/src/tui/magi-tui.js +754 -0
- package/dist/src/tui/panel.d.ts +45 -0
- package/dist/src/tui/panel.js +292 -0
- package/dist/src/tui/screen-buffer.d.ts +54 -0
- package/dist/src/tui/screen-buffer.js +262 -0
- package/dist/src/tui/status-bar.d.ts +25 -0
- package/dist/src/tui/status-bar.js +124 -0
- package/dist/src/tui/terminal-detect.d.ts +26 -0
- package/dist/src/tui/terminal-detect.js +44 -0
- package/dist/src/tui/tui-helpers.d.ts +12 -0
- package/dist/src/tui/tui-helpers.js +37 -0
- package/dist/src/types/adapter.d.ts +75 -0
- package/dist/src/types/adapter.js +36 -0
- package/dist/src/types/config.d.ts +108 -0
- package/dist/src/types/config.js +85 -0
- package/dist/src/types/consensus.d.ts +55 -0
- package/dist/src/types/consensus.js +17 -0
- package/dist/src/types/core.d.ts +178 -0
- package/dist/src/types/core.js +85 -0
- package/dist/src/types/magi-api.d.ts +62 -0
- package/dist/src/types/magi-api.js +7 -0
- package/dist/src/types/phase-h.d.ts +142 -0
- package/dist/src/types/phase-h.js +7 -0
- package/dist/src/types/phase-i.d.ts +186 -0
- package/dist/src/types/phase-i.js +6 -0
- package/dist/src/types/phase-k.d.ts +259 -0
- package/dist/src/types/phase-k.js +6 -0
- package/dist/src/types/phase-l.d.ts +199 -0
- package/dist/src/types/phase-l.js +6 -0
- package/dist/src/types/pipeline.d.ts +37 -0
- package/dist/src/types/pipeline.js +2 -0
- package/dist/src/utils/abstain-factory.d.ts +2 -0
- package/dist/src/utils/abstain-factory.js +18 -0
- package/dist/src/utils/errors.d.ts +34 -0
- package/dist/src/utils/errors.js +59 -0
- package/dist/src/utils/file-validator.d.ts +50 -0
- package/dist/src/utils/file-validator.js +124 -0
- package/dist/src/utils/fire-and-forget.d.ts +5 -0
- package/dist/src/utils/fire-and-forget.js +10 -0
- package/dist/src/utils/flag-validator.d.ts +21 -0
- package/dist/src/utils/flag-validator.js +79 -0
- package/dist/src/utils/freeze.d.ts +8 -0
- package/dist/src/utils/freeze.js +16 -0
- package/dist/src/utils/language-detector.d.ts +16 -0
- package/dist/src/utils/language-detector.js +159 -0
- package/dist/src/utils/latency-tracker.d.ts +45 -0
- package/dist/src/utils/latency-tracker.js +100 -0
- package/dist/src/utils/logger.d.ts +33 -0
- package/dist/src/utils/logger.js +112 -0
- package/dist/src/utils/process.d.ts +40 -0
- package/dist/src/utils/process.js +253 -0
- package/dist/src/utils/retry.d.ts +12 -0
- package/dist/src/utils/retry.js +30 -0
- package/dist/src/utils/safe-fs.d.ts +38 -0
- package/dist/src/utils/safe-fs.js +56 -0
- package/dist/src/utils/safe-json-parse.d.ts +15 -0
- package/dist/src/utils/safe-json-parse.js +49 -0
- package/dist/src/utils/sanitize.d.ts +14 -0
- package/dist/src/utils/sanitize.js +186 -0
- package/dist/src/utils/semaphore.d.ts +22 -0
- package/dist/src/utils/semaphore.js +57 -0
- package/dist/src/utils/shutdown.d.ts +6 -0
- package/dist/src/utils/shutdown.js +51 -0
- package/dist/src/utils/tty.d.ts +5 -0
- package/dist/src/utils/tty.js +7 -0
- package/package.json +82 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MagiDeliberation } from './types.js';
|
|
2
|
+
import type { MagiTask } from '../../types/core.js';
|
|
3
|
+
import type { KernelDependencies } from './types.js';
|
|
4
|
+
export declare class DeliberationKernel {
|
|
5
|
+
private readonly deps;
|
|
6
|
+
private readonly phaseRunner;
|
|
7
|
+
private readonly postProcessor;
|
|
8
|
+
private readonly middleware;
|
|
9
|
+
constructor(deps: KernelDependencies);
|
|
10
|
+
deliberate(task: MagiTask, signal?: AbortSignal): Promise<MagiDeliberation>;
|
|
11
|
+
private buildResult;
|
|
12
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeliberationKernel — The main deliberation loop.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Middleware chain execution (cache check, firewall scan)
|
|
6
|
+
* - Pipeline config setup with sync rate weights
|
|
7
|
+
* - Phase loop with hard timeout
|
|
8
|
+
* - Early consensus exit
|
|
9
|
+
* - Final consensus calculation
|
|
10
|
+
* - Instrumentality fusion for deadlock resolution
|
|
11
|
+
* - Human-in-the-loop deadlock resolution
|
|
12
|
+
* - Build result
|
|
13
|
+
*/
|
|
14
|
+
import { randomUUID } from 'node:crypto';
|
|
15
|
+
import { isUnanimous as isUnanimousDecision, isMajority as isMajorityDecision } from '../../types/consensus.js';
|
|
16
|
+
import { ConsensusEngine } from '../consensus.js';
|
|
17
|
+
import { HumanResolver } from '../human-resolver.js';
|
|
18
|
+
import { logger } from '../../utils/logger.js';
|
|
19
|
+
import { DeliberationTimeoutError } from '../../utils/errors.js';
|
|
20
|
+
import { MiddlewareChain } from '../middleware/chain.js';
|
|
21
|
+
import { createCacheMiddleware } from '../middleware/cache.js';
|
|
22
|
+
import { createFirewallMiddleware } from '../middleware/firewall.js';
|
|
23
|
+
import { PhaseRunner } from './phase-runner.js';
|
|
24
|
+
import { PostProcessor } from './post-processor.js';
|
|
25
|
+
export class DeliberationKernel {
|
|
26
|
+
deps;
|
|
27
|
+
phaseRunner;
|
|
28
|
+
postProcessor;
|
|
29
|
+
middleware;
|
|
30
|
+
constructor(deps) {
|
|
31
|
+
this.deps = deps;
|
|
32
|
+
this.phaseRunner = new PhaseRunner(deps);
|
|
33
|
+
this.postProcessor = new PostProcessor(deps);
|
|
34
|
+
// Build middleware chain (firewall FIRST, then cache)
|
|
35
|
+
this.middleware = new MiddlewareChain();
|
|
36
|
+
if (deps.modules.type666Firewall) {
|
|
37
|
+
this.middleware.use(createFirewallMiddleware(deps.modules.type666Firewall));
|
|
38
|
+
}
|
|
39
|
+
if (deps.modules.cache) {
|
|
40
|
+
this.middleware.use(createCacheMiddleware(deps.modules.cache));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async deliberate(task, signal) {
|
|
44
|
+
const id = task.id ?? randomUUID();
|
|
45
|
+
const { adapters, pipelines, contextManager, eventBus } = this.deps;
|
|
46
|
+
const { objectiveJudge, syncRateTracker, instrumentality } = this.deps.modules;
|
|
47
|
+
// Run pre-deliberation middleware chain (cache check, firewall scan, etc.)
|
|
48
|
+
if (this.middleware.length > 0) {
|
|
49
|
+
const mwCtx = {
|
|
50
|
+
deliberationId: id,
|
|
51
|
+
task,
|
|
52
|
+
config: {}, // not used by current middlewares
|
|
53
|
+
eventBus,
|
|
54
|
+
metadata: new Map(),
|
|
55
|
+
};
|
|
56
|
+
await this.middleware.execute(mwCtx);
|
|
57
|
+
if (mwCtx.blocked) {
|
|
58
|
+
throw new Error(mwCtx.blockedReason ?? 'Deliberation blocked by firewall');
|
|
59
|
+
}
|
|
60
|
+
if (mwCtx.skipDeliberation && mwCtx.cachedResult) {
|
|
61
|
+
return mwCtx.cachedResult;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const pipeline = pipelines.get(task.type);
|
|
65
|
+
const config = {
|
|
66
|
+
...pipeline.defaultConfig,
|
|
67
|
+
...task.config,
|
|
68
|
+
consensus: { ...pipeline.defaultConfig.consensus, ...task.config?.consensus },
|
|
69
|
+
};
|
|
70
|
+
// Phase H: Merge sync rate weights into consensus config
|
|
71
|
+
if (syncRateTracker) {
|
|
72
|
+
const units = adapters.getAll().map(a => a.unit);
|
|
73
|
+
const syncWeights = syncRateTracker.computeWeights(units, task.type);
|
|
74
|
+
if (Object.keys(syncWeights).length > 0) {
|
|
75
|
+
config.consensus = {
|
|
76
|
+
...config.consensus,
|
|
77
|
+
unitWeights: { ...config.consensus.unitWeights, ...syncWeights },
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const consensusEngine = new ConsensusEngine(config.consensus);
|
|
82
|
+
const startedAt = new Date();
|
|
83
|
+
const rounds = [];
|
|
84
|
+
const pendingIO = [];
|
|
85
|
+
await contextManager.initWorkspace(id, task);
|
|
86
|
+
logger.info(`MAGI deliberation started: ${id}`, { type: task.type, title: task.title });
|
|
87
|
+
logger.audit('deliberation.start', id, { type: task.type, title: task.title });
|
|
88
|
+
eventBus?.emit('deliberation:start', {
|
|
89
|
+
deliberationId: id,
|
|
90
|
+
taskType: task.type,
|
|
91
|
+
taskTitle: task.title,
|
|
92
|
+
emittedAt: new Date(),
|
|
93
|
+
});
|
|
94
|
+
// Run ObjectiveJudge for code-review/security-audit tasks (before phases)
|
|
95
|
+
let objectiveResult;
|
|
96
|
+
if (objectiveJudge && (task.type === 'code-review' || task.type === 'security-audit')) {
|
|
97
|
+
try {
|
|
98
|
+
objectiveResult = await objectiveJudge.evaluate();
|
|
99
|
+
logger.info('ObjectiveJudge evaluation complete', { score: objectiveResult.score });
|
|
100
|
+
logger.audit('objective.complete', id, { score: objectiveResult.score });
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
logger.warn('ObjectiveJudge evaluation failed, continuing without', { error: String(err) });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const objectiveSummary = objectiveResult?.summary;
|
|
107
|
+
const objectiveScore = objectiveResult?.score;
|
|
108
|
+
// Hard timeout for entire deliberation
|
|
109
|
+
const deliberationTimeout = config.deliberationTimeoutMs;
|
|
110
|
+
const deadline = startedAt.getTime() + deliberationTimeout;
|
|
111
|
+
// Save baseline excludeFromUnanimous to prevent DummyPlug accumulation across phases
|
|
112
|
+
const baseExcludeFromUnanimous = [...(config.consensus.excludeFromUnanimous ?? [])];
|
|
113
|
+
for (const phase of config.phases) {
|
|
114
|
+
// P0-2: Check external abort signal before starting a new phase
|
|
115
|
+
if (signal?.aborted) {
|
|
116
|
+
throw new Error('Deliberation cancelled');
|
|
117
|
+
}
|
|
118
|
+
// Deep-clone config per phase to isolate from async mutations (fire-and-forget, event handlers).
|
|
119
|
+
// Prerequisite: config must be JSON-serializable (no functions, class instances, or Symbols).
|
|
120
|
+
let phaseConfig;
|
|
121
|
+
try {
|
|
122
|
+
phaseConfig = structuredClone(config);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Fallback to JSON round-trip to deep-clone (preserves nested objects)
|
|
126
|
+
try {
|
|
127
|
+
phaseConfig = JSON.parse(JSON.stringify(config));
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
phaseConfig = { ...config };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
phaseConfig.consensus.excludeFromUnanimous = [...baseExcludeFromUnanimous];
|
|
134
|
+
// File access requires more time for CLIs to explore the codebase
|
|
135
|
+
if (this.deps.fileAccessEnabled) {
|
|
136
|
+
phaseConfig.phaseTimeoutMs = Math.min(phaseConfig.phaseTimeoutMs * 2, 3_600_000);
|
|
137
|
+
}
|
|
138
|
+
const roundNumber = rounds.length + 1;
|
|
139
|
+
if (roundNumber > phaseConfig.maxRounds)
|
|
140
|
+
break;
|
|
141
|
+
// Check hard timeout before starting a new phase
|
|
142
|
+
if (Date.now() >= deadline) {
|
|
143
|
+
logger.warn(`Deliberation hard timeout reached`, { id, timeoutMs: deliberationTimeout });
|
|
144
|
+
logger.audit('phase.timeout', id, { phase: 'deliberation', timeoutMs: deliberationTimeout });
|
|
145
|
+
throw new DeliberationTimeoutError(id, deliberationTimeout);
|
|
146
|
+
}
|
|
147
|
+
logger.info(`Phase: ${phase} (round ${roundNumber})`);
|
|
148
|
+
logger.audit('phase.start', id, { phase, roundNumber });
|
|
149
|
+
const roundStart = new Date();
|
|
150
|
+
eventBus?.emit('phase:start', {
|
|
151
|
+
deliberationId: id,
|
|
152
|
+
phase,
|
|
153
|
+
roundNumber,
|
|
154
|
+
emittedAt: new Date(),
|
|
155
|
+
});
|
|
156
|
+
// Phase timeout with Promise.race
|
|
157
|
+
let opinions = await this.phaseRunner.runWithTimeout({
|
|
158
|
+
deliberationId: id, task, pipeline, phase,
|
|
159
|
+
previousRounds: rounds, config: phaseConfig, objectiveSummary,
|
|
160
|
+
fileAccessEnabled: this.deps.fileAccessEnabled,
|
|
161
|
+
}, signal);
|
|
162
|
+
// Post-phase processing (LCL, ATField, DummyPlug recording)
|
|
163
|
+
opinions = this.postProcessor.processPhaseOpinions(opinions, phase, id, task.type);
|
|
164
|
+
const round = {
|
|
165
|
+
roundNumber,
|
|
166
|
+
phase,
|
|
167
|
+
opinions,
|
|
168
|
+
startedAt: roundStart,
|
|
169
|
+
completedAt: new Date(),
|
|
170
|
+
};
|
|
171
|
+
rounds.push(round);
|
|
172
|
+
// Fire-and-forget: push IO to pending queue instead of awaiting
|
|
173
|
+
pendingIO.push(contextManager.saveRound(id, round).catch((err) => {
|
|
174
|
+
logger.warn('Failed to save round', { roundNumber, error: String(err) });
|
|
175
|
+
}));
|
|
176
|
+
const phaseDurationMs = round.completedAt.getTime() - round.startedAt.getTime();
|
|
177
|
+
logger.audit('phase.complete', id, {
|
|
178
|
+
phase,
|
|
179
|
+
roundNumber,
|
|
180
|
+
durationMs: phaseDurationMs,
|
|
181
|
+
votes: opinions.map((o) => ({ unit: o.unit, vote: o.vote })),
|
|
182
|
+
});
|
|
183
|
+
eventBus?.emit('phase:complete', {
|
|
184
|
+
deliberationId: id,
|
|
185
|
+
phase,
|
|
186
|
+
roundNumber,
|
|
187
|
+
durationMs: phaseDurationMs,
|
|
188
|
+
emittedAt: new Date(),
|
|
189
|
+
});
|
|
190
|
+
// Adaptive early consensus exit (skip only for final-vote)
|
|
191
|
+
if (phaseConfig.earlyConsensusExit && phase !== 'final-vote') {
|
|
192
|
+
const earlyOpinions = objectiveScore !== undefined
|
|
193
|
+
? opinions.map(o => ({ ...o, confidence: o.confidence * (0.5 + 0.5 * objectiveScore) }))
|
|
194
|
+
: opinions;
|
|
195
|
+
const result = consensusEngine.calculate(earlyOpinions);
|
|
196
|
+
const thresholds = phaseConfig.earlyExitThresholds ?? { unanimous: 0.7, majority: 0.85 };
|
|
197
|
+
const isUnanimousExit = isUnanimousDecision(result.decision) && result.confidence >= thresholds.unanimous;
|
|
198
|
+
const isMajorityExit = isMajorityDecision(result.decision) && result.confidence >= thresholds.majority;
|
|
199
|
+
if (isUnanimousExit || isMajorityExit) {
|
|
200
|
+
const reason = isUnanimousExit ? 'unanimous_early_exit' : 'majority_early_exit';
|
|
201
|
+
const currentIdx = config.phases.indexOf(phase);
|
|
202
|
+
for (const skipped of config.phases.slice(currentIdx + 1)) {
|
|
203
|
+
eventBus?.emit('phase:skipped', {
|
|
204
|
+
deliberationId: id,
|
|
205
|
+
phase: skipped,
|
|
206
|
+
reason,
|
|
207
|
+
emittedAt: new Date(),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
logger.info(`Early consensus reached: ${result.decision}`);
|
|
211
|
+
logger.audit('deliberation.complete', id, {
|
|
212
|
+
decision: result.decision,
|
|
213
|
+
method: 'early_consensus',
|
|
214
|
+
rounds: rounds.length,
|
|
215
|
+
});
|
|
216
|
+
await Promise.allSettled(pendingIO);
|
|
217
|
+
const earlyResult = this.buildResult(id, task, rounds, result, startedAt, objectiveResult);
|
|
218
|
+
await contextManager.saveDeliberation(earlyResult).catch((err) => {
|
|
219
|
+
logger.warn('Failed to save early deliberation', { error: String(err) });
|
|
220
|
+
});
|
|
221
|
+
eventBus?.emit('deliberation:complete', {
|
|
222
|
+
deliberationId: id,
|
|
223
|
+
decision: result.decision,
|
|
224
|
+
totalDurationMs: earlyResult.totalDurationMs,
|
|
225
|
+
rounds: rounds.length,
|
|
226
|
+
fromCache: false,
|
|
227
|
+
emittedAt: new Date(),
|
|
228
|
+
});
|
|
229
|
+
return earlyResult;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Calculate final consensus from the last round (with objective confidence adjustment)
|
|
234
|
+
const lastRound = rounds[rounds.length - 1];
|
|
235
|
+
const finalOpinions = lastRound?.opinions ?? [];
|
|
236
|
+
const adjustedFinalOpinions = objectiveScore !== undefined
|
|
237
|
+
? finalOpinions.map(o => ({ ...o, confidence: o.confidence * (0.5 + 0.5 * objectiveScore) }))
|
|
238
|
+
: finalOpinions;
|
|
239
|
+
let consensus = consensusEngine.calculate(adjustedFinalOpinions);
|
|
240
|
+
// Phase I: Instrumentality fusion for deadlock resolution
|
|
241
|
+
if (consensus.decision === 'DEADLOCK' && instrumentality &&
|
|
242
|
+
instrumentality.shouldTrigger(rounds, consensus.decision)) {
|
|
243
|
+
try {
|
|
244
|
+
const fusionResult = await instrumentality.fuse(adjustedFinalOpinions, task);
|
|
245
|
+
// Replace consensus with fused opinion result
|
|
246
|
+
const fusedOpinions = [fusionResult.fused];
|
|
247
|
+
consensus = consensusEngine.calculate(fusedOpinions);
|
|
248
|
+
logger.info('Instrumentality fusion resolved deadlock', { decision: consensus.decision });
|
|
249
|
+
logger.audit('instrumentality.resolve', id, { decision: consensus.decision });
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
logger.warn('Instrumentality fusion failed, falling through', { error: String(err) });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Human-in-the-loop deadlock resolution
|
|
256
|
+
if (consensus.decision === 'DEADLOCK' && config.consensus.deadlockStrategy === 'human-in-the-loop') {
|
|
257
|
+
const humanResolver = new HumanResolver();
|
|
258
|
+
if (humanResolver.isAvailable()) {
|
|
259
|
+
consensus = await humanResolver.resolve(adjustedFinalOpinions, consensus.votes);
|
|
260
|
+
logger.info('Deadlock resolved by human', { decision: consensus.decision });
|
|
261
|
+
logger.audit('human.resolve', id, { decision: consensus.decision });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Flush all pending round IO before saving final deliberation
|
|
265
|
+
await Promise.allSettled(pendingIO);
|
|
266
|
+
const deliberation = this.buildResult(id, task, rounds, consensus, startedAt, objectiveResult);
|
|
267
|
+
await contextManager.saveDeliberation(deliberation);
|
|
268
|
+
// Post-deliberation side effects
|
|
269
|
+
await this.postProcessor.runPostDeliberation(id, task, lastRound, consensus, deliberation);
|
|
270
|
+
logger.info(`MAGI deliberation complete: ${consensus.decision}`, {
|
|
271
|
+
id,
|
|
272
|
+
rounds: rounds.length,
|
|
273
|
+
totalDurationMs: deliberation.totalDurationMs,
|
|
274
|
+
});
|
|
275
|
+
logger.audit('deliberation.complete', id, {
|
|
276
|
+
decision: consensus.decision,
|
|
277
|
+
rounds: rounds.length,
|
|
278
|
+
totalDurationMs: deliberation.totalDurationMs,
|
|
279
|
+
});
|
|
280
|
+
eventBus?.emit('deliberation:complete', {
|
|
281
|
+
deliberationId: id,
|
|
282
|
+
decision: consensus.decision,
|
|
283
|
+
totalDurationMs: deliberation.totalDurationMs,
|
|
284
|
+
rounds: rounds.length,
|
|
285
|
+
fromCache: false,
|
|
286
|
+
emittedAt: new Date(),
|
|
287
|
+
});
|
|
288
|
+
return deliberation;
|
|
289
|
+
}
|
|
290
|
+
buildResult(id, task, rounds, consensus, startedAt, objectiveResult) {
|
|
291
|
+
const completedAt = new Date();
|
|
292
|
+
return {
|
|
293
|
+
id,
|
|
294
|
+
task,
|
|
295
|
+
rounds,
|
|
296
|
+
consensus,
|
|
297
|
+
totalDurationMs: completedAt.getTime() - startedAt.getTime(),
|
|
298
|
+
startedAt,
|
|
299
|
+
completedAt,
|
|
300
|
+
objectiveResult,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel module re-exports.
|
|
3
|
+
*/
|
|
4
|
+
export { DeliberationKernel } from './deliberation-kernel.js';
|
|
5
|
+
export { PhaseRunner } from './phase-runner.js';
|
|
6
|
+
export { UnitExecutor } from './unit-executor.js';
|
|
7
|
+
export { PostProcessor } from './post-processor.js';
|
|
8
|
+
export type { KernelDependencies, OptionalModules, UnitExecutionParams, PhaseRunParams, DeliberationContext, } from './types.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { KernelDependencies, PhaseRunParams, MagiOpinion } from './types.js';
|
|
2
|
+
export declare class PhaseRunner {
|
|
3
|
+
private readonly deps;
|
|
4
|
+
private readonly unitExecutor;
|
|
5
|
+
constructor(deps: KernelDependencies);
|
|
6
|
+
/** Execute a phase with a timeout guard (Promise.race). */
|
|
7
|
+
runWithTimeout(params: PhaseRunParams, externalSignal?: AbortSignal): Promise<MagiOpinion[]>;
|
|
8
|
+
/** Execute a phase: filter units, run in parallel, apply DummyPlug/Iruel/Offline. */
|
|
9
|
+
private run;
|
|
10
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhaseRunner — Executes a deliberation phase across all active MAGI units.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - AbortController + phase timeout management
|
|
6
|
+
* - UmbilicalCable unit filtering (circuit breaker, battery depletion)
|
|
7
|
+
* - Parallel execution via Promise.allSettled
|
|
8
|
+
* - UmbilicalCable result recording (success/failure)
|
|
9
|
+
* - DummyPlug replacement for ABSTAIN units
|
|
10
|
+
* - Iruel consistency verification
|
|
11
|
+
* - Offline fallback for skipped adapters
|
|
12
|
+
*/
|
|
13
|
+
import { logger } from '../../utils/logger.js';
|
|
14
|
+
import { createAbstainOpinion } from '../../utils/abstain-factory.js';
|
|
15
|
+
import { PhaseTimeoutError } from '../../utils/errors.js';
|
|
16
|
+
import { UnitExecutor } from './unit-executor.js';
|
|
17
|
+
export class PhaseRunner {
|
|
18
|
+
deps;
|
|
19
|
+
unitExecutor;
|
|
20
|
+
constructor(deps) {
|
|
21
|
+
this.deps = deps;
|
|
22
|
+
this.unitExecutor = new UnitExecutor(deps);
|
|
23
|
+
}
|
|
24
|
+
/** Execute a phase with a timeout guard (Promise.race). */
|
|
25
|
+
async runWithTimeout(params, externalSignal) {
|
|
26
|
+
const { config } = params;
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
// Link external signal (from REPL Ctrl+C) to internal phase controller
|
|
29
|
+
const onExternalAbort = () => controller.abort();
|
|
30
|
+
externalSignal?.addEventListener('abort', onExternalAbort, { once: true });
|
|
31
|
+
const phasePromise = this.run(params, controller.signal);
|
|
32
|
+
let timer;
|
|
33
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
34
|
+
timer = setTimeout(() => {
|
|
35
|
+
controller.abort(); // Signal child processes to terminate
|
|
36
|
+
logger.audit('phase.timeout', params.deliberationId, {
|
|
37
|
+
phase: params.phase, timeoutMs: config.phaseTimeoutMs,
|
|
38
|
+
});
|
|
39
|
+
reject(new PhaseTimeoutError(params.phase, config.phaseTimeoutMs));
|
|
40
|
+
}, config.phaseTimeoutMs);
|
|
41
|
+
});
|
|
42
|
+
try {
|
|
43
|
+
return await Promise.race([phasePromise, timeoutPromise]);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
externalSignal?.removeEventListener('abort', onExternalAbort);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Execute a phase: filter units, run in parallel, apply DummyPlug/Iruel/Offline. */
|
|
51
|
+
async run(params, signal) {
|
|
52
|
+
const { deliberationId, task, pipeline, phase, previousRounds, config, objectiveSummary, fileAccessEnabled } = params;
|
|
53
|
+
const { adapters, eventBus } = this.deps;
|
|
54
|
+
const { umbilicalCable, dummyPlug, iruelBattle, offlineMode } = this.deps.modules;
|
|
55
|
+
const allAdapters = adapters.getAll();
|
|
56
|
+
// Phase H: Filter out disconnected + battery-depleted units (with circuit breaker)
|
|
57
|
+
const activeAdapters = allAdapters.filter(adapter => {
|
|
58
|
+
if (umbilicalCable) {
|
|
59
|
+
// Circuit breaker: fail fast for OPEN circuits
|
|
60
|
+
if (!umbilicalCable.shouldAllow(adapter.unit)) {
|
|
61
|
+
logger.info(`${adapter.unit} skipped: circuit breaker OPEN`);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const status = umbilicalCable.getStatus(adapter.unit);
|
|
65
|
+
if (status === 'disconnected' && umbilicalCable.isBatteryDepleted(adapter.unit)) {
|
|
66
|
+
logger.info(`${adapter.unit} skipped: disconnected + battery depleted`);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
// All phases run in parallel (Promise.allSettled for graceful degradation)
|
|
73
|
+
const results = await Promise.allSettled(activeAdapters.map((adapter) => this.unitExecutor.execute({
|
|
74
|
+
deliberationId, adapter, task, pipeline, phase,
|
|
75
|
+
previousRounds, config, objectiveSummary, signal,
|
|
76
|
+
fileAccessEnabled,
|
|
77
|
+
})));
|
|
78
|
+
const opinions = results.map((result, i) => {
|
|
79
|
+
const adapter = activeAdapters[i];
|
|
80
|
+
if (result.status === 'fulfilled') {
|
|
81
|
+
// Phase H: Record success in UmbilicalCable
|
|
82
|
+
umbilicalCable?.recordResult(adapter.unit, 'SUCCESS', eventBus);
|
|
83
|
+
return result.value;
|
|
84
|
+
}
|
|
85
|
+
// Phase H: Record failure in UmbilicalCable
|
|
86
|
+
const errorCode = String(result.reason).includes('TIMEOUT') ? 'TIMEOUT' : 'CRASH';
|
|
87
|
+
umbilicalCable?.recordResult(adapter.unit, errorCode, eventBus);
|
|
88
|
+
// On failure, produce an ABSTAIN opinion
|
|
89
|
+
logger.warn(`${adapter.displayName} failed in phase ${phase}`, {
|
|
90
|
+
error: String(result.reason),
|
|
91
|
+
});
|
|
92
|
+
logger.audit('adapter.failure', deliberationId, {
|
|
93
|
+
unit: adapter.unit,
|
|
94
|
+
phase,
|
|
95
|
+
error: String(result.reason),
|
|
96
|
+
});
|
|
97
|
+
eventBus?.emit('unit:error', {
|
|
98
|
+
deliberationId,
|
|
99
|
+
unit: adapter.unit,
|
|
100
|
+
phase,
|
|
101
|
+
error: String(result.reason),
|
|
102
|
+
emittedAt: new Date(),
|
|
103
|
+
});
|
|
104
|
+
return createAbstainOpinion(adapter.unit, `${adapter.displayName} failed: ${result.reason?.message ?? 'unknown error'}`, ['Adapter execution failed']);
|
|
105
|
+
});
|
|
106
|
+
// Phase H: Replace ABSTAIN/down units with DummyPlug proxy opinions
|
|
107
|
+
if (dummyPlug) {
|
|
108
|
+
for (let i = 0; i < opinions.length; i++) {
|
|
109
|
+
const op = opinions[i];
|
|
110
|
+
if (op.vote === 'ABSTAIN' && op.confidence === 0) {
|
|
111
|
+
const proxy = dummyPlug.generateProxy(op.unit, activeAdapters.map(a => a.unit), opinions, task.type);
|
|
112
|
+
if (proxy) {
|
|
113
|
+
opinions[i] = proxy;
|
|
114
|
+
logger.info(`DummyPlug activated for ${op.unit}`);
|
|
115
|
+
logger.audit('dummyplug.activate', deliberationId, { unit: op.unit });
|
|
116
|
+
eventBus?.emit('dummyplug:activated', {
|
|
117
|
+
deliberationId, unit: op.unit,
|
|
118
|
+
confidence: proxy.confidence, profileSamples: proxy.profileSamples,
|
|
119
|
+
emittedAt: new Date(),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Set excludeFromUnanimous for dummy plug units
|
|
125
|
+
const dummyUnits = dummyPlug.getDummyUnits(opinions);
|
|
126
|
+
if (dummyUnits.length > 0) {
|
|
127
|
+
config.consensus = {
|
|
128
|
+
...config.consensus,
|
|
129
|
+
excludeFromUnanimous: [
|
|
130
|
+
...(config.consensus.excludeFromUnanimous ?? []),
|
|
131
|
+
...dummyUnits,
|
|
132
|
+
],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Phase L: Iruel Battle consistency verification + filtering
|
|
137
|
+
if (iruelBattle) {
|
|
138
|
+
for (let i = 0; i < opinions.length; i++) {
|
|
139
|
+
const op = opinions[i];
|
|
140
|
+
const check = iruelBattle.verifyConsistency(op, opinions);
|
|
141
|
+
iruelBattle.detectCorruption(op, check);
|
|
142
|
+
opinions[i] = iruelBattle.filterOpinion(op);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Phase H: Add offline fallback opinions for skipped (depleted) adapters
|
|
146
|
+
if (offlineMode) {
|
|
147
|
+
const skipped = allAdapters.filter(a => !activeAdapters.includes(a));
|
|
148
|
+
for (const adapter of skipped) {
|
|
149
|
+
const fallback = offlineMode.generateFallbackOpinion(adapter.unit, task);
|
|
150
|
+
opinions.push(fallback);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return opinions;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { KernelDependencies, MagiOpinion, MagiTask, DeliberationRound, MagiDeliberation } from './types.js';
|
|
2
|
+
import type { ConsensusResult } from '../../types/consensus.js';
|
|
3
|
+
export declare class PostProcessor {
|
|
4
|
+
private readonly deps;
|
|
5
|
+
constructor(deps: KernelDependencies);
|
|
6
|
+
/**
|
|
7
|
+
* Process opinions after a phase completes.
|
|
8
|
+
* - LCL purify (cross-examination only)
|
|
9
|
+
* - ATField bias analysis
|
|
10
|
+
* - DummyPlug profile recording
|
|
11
|
+
*/
|
|
12
|
+
processPhaseOpinions(opinions: MagiOpinion[], phase: string, deliberationId: string, taskType: string): MagiOpinion[];
|
|
13
|
+
/**
|
|
14
|
+
* Run all post-deliberation side effects (mostly fire-and-forget).
|
|
15
|
+
*/
|
|
16
|
+
runPostDeliberation(deliberationId: string, task: MagiTask, lastRound: DeliberationRound | undefined, consensus: ConsensusResult, deliberation: MagiDeliberation): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostProcessor — Handles post-phase and post-deliberation side effects.
|
|
3
|
+
*
|
|
4
|
+
* Phase opinion processing (after each phase):
|
|
5
|
+
* - LCL purify opinions
|
|
6
|
+
* - ATField bias analysis
|
|
7
|
+
* - DummyPlug profile recording
|
|
8
|
+
*
|
|
9
|
+
* Post-deliberation processing (after consensus is determined):
|
|
10
|
+
* - SyncRate update
|
|
11
|
+
* - Gospel chronicle record
|
|
12
|
+
* - Engram memory record
|
|
13
|
+
* - Drift detection
|
|
14
|
+
* - Firewall learning
|
|
15
|
+
* - Nebuchadnezzar key reset
|
|
16
|
+
* - Cache save
|
|
17
|
+
* - Token persist
|
|
18
|
+
*/
|
|
19
|
+
import { logger } from '../../utils/logger.js';
|
|
20
|
+
import { fireAndForget } from '../../utils/fire-and-forget.js';
|
|
21
|
+
export class PostProcessor {
|
|
22
|
+
deps;
|
|
23
|
+
constructor(deps) {
|
|
24
|
+
this.deps = deps;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Process opinions after a phase completes.
|
|
28
|
+
* - LCL purify (cross-examination only)
|
|
29
|
+
* - ATField bias analysis
|
|
30
|
+
* - DummyPlug profile recording
|
|
31
|
+
*/
|
|
32
|
+
processPhaseOpinions(opinions, phase, deliberationId, taskType) {
|
|
33
|
+
let processed = opinions;
|
|
34
|
+
const { lclManager, atField, dummyPlug } = this.deps.modules;
|
|
35
|
+
// Phase I: LCL purify opinions before cross-examination
|
|
36
|
+
if (lclManager && phase === 'cross-examination') {
|
|
37
|
+
for (let i = 0; i < processed.length; i++) {
|
|
38
|
+
const result = lclManager.purify(processed[i], deliberationId);
|
|
39
|
+
if (result.purified) {
|
|
40
|
+
processed[i] = { ...processed[i], confidence: result.adjustedConfidence };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Phase H: A.T. Field bias analysis
|
|
45
|
+
if (atField) {
|
|
46
|
+
const biasResult = atField.analyze(processed, this.deps.eventBus, deliberationId);
|
|
47
|
+
if (biasResult.biasWarning && biasResult.confidenceDiscount > 0) {
|
|
48
|
+
processed = processed.map(o => ({
|
|
49
|
+
...o,
|
|
50
|
+
confidence: o.confidence * (1 - biasResult.confidenceDiscount),
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Phase H: Record profiles for DummyPlug (exclude dummy opinions)
|
|
55
|
+
if (dummyPlug) {
|
|
56
|
+
for (const opinion of processed) {
|
|
57
|
+
if (!('isDummyPlug' in opinion)) {
|
|
58
|
+
dummyPlug.recordOpinion(opinion, taskType);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return processed;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Run all post-deliberation side effects (mostly fire-and-forget).
|
|
66
|
+
*/
|
|
67
|
+
async runPostDeliberation(deliberationId, task, lastRound, consensus, deliberation) {
|
|
68
|
+
const { adapters, eventBus } = this.deps;
|
|
69
|
+
const { syncRateTracker, gospel, engramManager, driftDetector, type666Firewall, nebuchadnezzarKey, cache, tokenTracker, } = this.deps.modules;
|
|
70
|
+
// Phase H: Update sync rates for all units
|
|
71
|
+
if (syncRateTracker && lastRound) {
|
|
72
|
+
const units = adapters.getAll().map(a => a.unit);
|
|
73
|
+
for (const opinion of lastRound.opinions) {
|
|
74
|
+
syncRateTracker.update(opinion.unit, task.type, opinion.vote, consensus.decision);
|
|
75
|
+
}
|
|
76
|
+
const rates = syncRateTracker.getAllRates(units, task.type);
|
|
77
|
+
eventBus?.emit('syncrate:updated', {
|
|
78
|
+
deliberationId, rates, domain: task.type, emittedAt: new Date(),
|
|
79
|
+
});
|
|
80
|
+
// Berserk check
|
|
81
|
+
const berserk = syncRateTracker.checkBerserk(units, task.type);
|
|
82
|
+
if (berserk) {
|
|
83
|
+
eventBus?.emit('berserk:warning', {
|
|
84
|
+
deliberationId, totalSyncRate: berserk.totalRate, threshold: 4.0,
|
|
85
|
+
units: berserk.rates, emittedAt: new Date(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
fireAndForget(syncRateTracker.persist(), 'syncrate.persist');
|
|
89
|
+
}
|
|
90
|
+
// Phase H: Record in Gospel chronicle
|
|
91
|
+
if (gospel) {
|
|
92
|
+
fireAndForget(gospel.record(deliberation, eventBus), 'gospel.record');
|
|
93
|
+
}
|
|
94
|
+
// Phase I: Record in engram memory + drift detection (fire-and-forget)
|
|
95
|
+
if (engramManager) {
|
|
96
|
+
fireAndForget(engramManager.recordDeliberation(deliberation), 'engram.record');
|
|
97
|
+
}
|
|
98
|
+
if (driftDetector && lastRound) {
|
|
99
|
+
for (const opinion of lastRound.opinions) {
|
|
100
|
+
driftDetector.updateVector(opinion.unit, opinion, consensus.decision);
|
|
101
|
+
driftDetector.checkDrift(opinion.unit, eventBus);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Phase K: Firewall learns from deliberation (fire-and-forget)
|
|
105
|
+
if (type666Firewall) {
|
|
106
|
+
try {
|
|
107
|
+
type666Firewall.learnFromDeliberation({ task, consensus });
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
logger.debug('Firewall learn failed', { error: String(err) });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Phase K: Reset Nebuchadnezzar consecutive overrides on normal completion
|
|
114
|
+
if (nebuchadnezzarKey) {
|
|
115
|
+
nebuchadnezzarKey.resetConsecutiveOverrides();
|
|
116
|
+
}
|
|
117
|
+
// Cache result (fire-and-forget)
|
|
118
|
+
if (cache) {
|
|
119
|
+
try {
|
|
120
|
+
cache.set(task, deliberation);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
logger.debug('Cache set failed', { error: String(err) });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Persist token data (fire-and-forget)
|
|
127
|
+
if (tokenTracker) {
|
|
128
|
+
fireAndForget(tokenTracker.persist(deliberationId), 'token.persist');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|