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
1 change: 1 addition & 0 deletions src/bus/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { GenesisEventBus } from './event-bus.js';
// Re-export types and classes
export { GenesisEventBus } from './event-bus.js';
export type { Subscription, SubscribeOptions, BusStats } from './event-bus.js';
export { createTypedPublisher, createTypedSubscriber, type TypedPublisher, type TypedSubscriber } from './typed-publisher.js';

export type {
// Base
Expand Down
27 changes: 4 additions & 23 deletions src/core/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,30 @@ import { getDIContainer, type DIContainer } from '../di/container.js';
* 3. Use resolve<ServiceTokenMap['yourToken']>('yourToken')
*/
export interface ServiceTokenMap {
// Infrastructure
// Infrastructure (L1)
eventBus: import('../bus/index.js').GenesisEventBus;
config: any; // TODO: type when config module is typed
fek: import('../kernel/free-energy-kernel.js').FreeEnergyKernel;
neuromodulation: import('../neuromodulation/index.js').NeuromodulationSystem;
nociception: import('../nociception/index.js').NociceptiveSystem;
allostasis: import('../allostasis/index.js').AllostasisSystem;
daemon: import('../daemon/index.js').Daemon;

// Memory & Persistence
// Memory & Persistence (L2)
memory: import('../memory/index.js').MemorySystem;
persistence: any;
graphRAG: any;

// Cognition
// Cognition (L3)
brain: import('../brain/index.js').Brain;
consciousness: import('../consciousness/index.js').ConsciousnessSystem;
worldModel: import('../world-model/index.js').WorldModelSystem;
thinking: import('../thinking/index.js').ThinkingEngine;
metacognitive: import('../reasoning/metacognitive-controller.js').MetacognitiveController;
grounding: import('../grounding/index.js').GroundingSystem;
mctsEngine: any;
outcomeIntegrator: any;

// Autonomous
goalSystem: any;
attentionController: any;
selfReflection: any;
governance: import('../governance/index.js').GovernanceSystem;

// Market & Content
marketStrategist: any;
contentOrchestrator: any;
newsletter: any;
mcpClient: any;

// Tools & Agents
// Tools & Agents (L3)
toolRegistry: Map<string, import('../tools/index.js').Tool>;
agentPool: import('../agents/index.js').AgentPool;

// Observability
dashboard: any;

// Core (v35)
agentLoop: import('./agent-loop.js').AgentLoop;
}
Expand Down
51 changes: 19 additions & 32 deletions src/core/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export function isLeft<A, E>(e: Either<A, E>): e is Left<E> {
export type Effect<A, E = never, R = unknown> = {
readonly _tag: 'Effect';
readonly run: (env: R) => Promise<Either<A, E>>;
/** Optional synchronous evaluator — set by `sync()` and `succeed()` for `runSync` support. */
readonly _sync?: (env: R) => Either<A, E>;
};

// ============================================================================
Expand All @@ -81,9 +83,11 @@ export type Effect<A, E = never, R = unknown> = {
* // Effect<number, never>
*/
export function succeed<A>(value: A): Effect<A, never> {
const r = right(value);
return {
_tag: 'Effect',
run: (_env) => Promise.resolve(right(value)),
run: (_env) => Promise.resolve(r),
_sync: (_env) => r,
};
}

Expand Down Expand Up @@ -142,6 +146,7 @@ export function sync<A>(fn: () => A): Effect<A, never> {
return {
_tag: 'Effect',
run: (_env) => Promise.resolve(right(fn())),
_sync: (_env) => right(fn()),
};
}

Expand Down Expand Up @@ -321,6 +326,7 @@ export function provide<A, E, R>(
return {
_tag: 'Effect',
run: (_ignoredEnv: unknown) => effect.run(env),
_sync: effect._sync ? (_ignoredEnv: unknown) => effect._sync!(env) : undefined,
};
}

Expand Down Expand Up @@ -449,39 +455,20 @@ export async function runEither<A, E>(effect: Effect<A, E>): Promise<Either<A, E
* const value = runSync(sync(() => computePhi(state)));
*/
export function runSync<A>(effect: Effect<A, never>): A {
// We rely on the invariant that sync/succeed return already-settled Promises.
// There is no way to block a Promise synchronously in Node without native
// extensions, so we surface the result through a shared slot.
let resolved = false;
let value: A | undefined;
let threw: unknown;

effect.run(undefined).then(
(result) => {
resolved = true;
if (isRight(result)) {
value = result.value;
} else {
// Effect<A, never> guarantees this branch is unreachable at compile
// time, but we defend against incorrect runtime usage.
threw = result.error;
}
},
(err) => {
resolved = true;
threw = err;
},
);

if (!resolved) {
throw new Error(
'runSync called on an asynchronous Effect. ' +
'Use runPromise or runEither for Effects that perform I/O.',
);
// Use the synchronous evaluator if available (set by sync/succeed).
if (effect._sync) {
const result = effect._sync(undefined);
if (isRight(result)) return result.value;
// Effect<A, never> guarantees this branch is unreachable at compile time,
// but we defend against incorrect runtime usage.
throw (result as Left<unknown>).error;
}

if (threw !== undefined) throw threw;
return value as A;
throw new Error(
'runSync called on an Effect without a synchronous evaluator. ' +
'Only Effects created via sync() or succeed() support runSync. ' +
'Use runPromise or runEither for Effects that perform I/O.',
);
}

// ============================================================================
Expand Down
45 changes: 7 additions & 38 deletions src/core/fek-brain-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
* bridge.feedbackResult(result);
*/

import { estimateComplexity } from '../thinking/budget-forcing.js';

// ============================================================================
// Types
// ============================================================================
Expand Down Expand Up @@ -122,45 +124,11 @@ function selectStrategy(
}

/**
* Estimate query complexity using fast heuristics (no LLM call).
*
* Factors:
* - Length (longer = more complex)
* - Question words (what/why/how)
* - Domain keywords
* - Nested structure (clauses, conditions)
* - Multi-step indicators
* Estimate query complexity using the budget-forcing module's algorithm.
* Delegates to estimateComplexity() to avoid duplication.
*/
function estimateQueryComplexity(query: string): number {
const lower = query.toLowerCase();
let complexity = 0;

// Length factor (0-0.3)
const wordCount = query.split(/\s+/).length;
complexity += Math.min(0.3, wordCount / 200);

// Deep reasoning indicators (0-0.3)
const deepWords = ['why', 'how', 'explain', 'analyze', 'compare', 'evaluate',
'design', 'architect', 'optimize', 'debug', 'prove', 'derive'];
const deepCount = deepWords.filter(w => lower.includes(w)).length;
complexity += Math.min(0.3, deepCount * 0.1);

// Multi-step indicators (0-0.2)
const multiStep = ['and then', 'first', 'second', 'step', 'after that',
'followed by', 'next', 'finally', 'also', 'additionally'];
const stepCount = multiStep.filter(w => lower.includes(w)).length;
complexity += Math.min(0.2, stepCount * 0.05);

// Nested structure (0-0.1)
const nestingIndicators = (query.match(/[({[\]})]/g) || []).length;
complexity += Math.min(0.1, nestingIndicators * 0.02);

// Code indicators (0-0.1)
if (/```|function\s|class\s|import\s|const\s/.test(query)) {
complexity += 0.1;
}

return Math.min(1, complexity);
return estimateComplexity(query).score;
}

/**
Expand Down Expand Up @@ -235,7 +203,8 @@ export class FEKBrainBridge {
} = {}
): FEKRouting {
// 1. Run FEK cycle to get current free energy
let freeEnergy = 0.5;
// Default 0.1 = calm/low-uncertainty when no FEK; query complexity drives strategy
let freeEnergy = 0.1;
let fekStrategy = 'sequential';

if (this.fek) {
Expand Down
50 changes: 50 additions & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Genesis v35 — Core Module Barrel
*
* Re-exports all core architectural modules for clean imports:
* import { createLogger, AgentLoop, FEKBrainBridge } from '../core/index.js';
*/

// Structured logging
export { createLogger, getLogger, setLogger, logger, type Logger, type LogLevel } from './logger.js';

// Typed effect system
export {
// Either
right, left, isRight, isLeft,
type Right, type Left, type Either,
// Effect constructors
succeed, fail, tryPromise, sync, tryCatch, fromNullable,
type Effect,
// Combinators
map, flatMap, catchAll, tap, tapError, provide,
// Concurrency
all, allSettled, race,
// Runtime
runPromise, runEither, runSync,
// Utilities
timeout, wrapLegacy, pipe,
// Error types
GenesisError, LLMError, ToolError, MemoryError,
BusError, ConfigError, TimeoutError,
} from './effect.js';

// FEK ↔ Brain bridge
export {
FEKBrainBridge,
type FEKSnapshot, type FEKRouting, type ThinkingStrategy,
type BrainModuleHint, type TokenBudget, type BrainStepFeedback,
} from './fek-brain-bridge.js';

// Agent loop (CoALA)
export { AgentLoop, type AgentModules } from './agent-loop.js';

// DI typed resolution
export {
bootstrap, resolve, resolveSync,
hasService, isResolved, shutdown, getContainer,
type ServiceTokenMap, type ServiceToken,
} from './bootstrap.js';

// Module registry (L1→L4 boot sequencing)
export { ModuleRegistry, registerGenesisModules, getModuleRegistry } from './module-registry.js';
4 changes: 2 additions & 2 deletions src/core/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ function wrapPino(pinoLogger: PinoLogger): Logger {
): (o: Record<string, unknown> | string, m?: string | unknown, ...r: unknown[]) => void {
return (o, m, ..._rest) => {
if (typeof o === 'string') {
fn.call(pinoLogger, o);
(fn as Function).call(pinoLogger, o, m, ..._rest);
} else {
fn.call(pinoLogger, o, typeof m === 'string' ? m : '');
(fn as Function).call(pinoLogger, o, typeof m === 'string' ? m : '');
}
};
}
Expand Down
16 changes: 11 additions & 5 deletions src/core/module-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* genesis.ts can delegate its boot fields to this registry incrementally.
*/

import { createLogger } from './logger.js';
import { getFreeEnergyKernel } from '../kernel/free-energy-kernel.js';
import { getBrain } from '../brain/index.js';
import { getEventBus } from '../bus/index.js';
Expand All @@ -35,6 +36,12 @@ import { getAgentPool } from '../agents/index.js';
import { getGovernanceSystem } from '../governance/index.js';
import { getSelfImprovementEngine } from '../self-modification/index.js';

// ============================================================================
// Logging
// ============================================================================

const log = createLogger('module-registry');

// ============================================================================
// Public types
// ============================================================================
Expand Down Expand Up @@ -278,9 +285,8 @@ export class ModuleRegistry {
entry.health.bootTimeMs = Date.now() - t0;

if (entry.opts.optional) {
console.warn(
`[ModuleRegistry] Optional module '${entry.id}' failed to boot — ` +
`continuing. ${msg}`,
log.warn(
`Optional module '${entry.id}' failed to boot — continuing. ${msg}`,
);
} else {
throw new Error(
Expand Down Expand Up @@ -368,8 +374,8 @@ export class ModuleRegistry {
entry.bootedAt = null;
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
console.warn(
`[ModuleRegistry] Shutdown error for '${entry.id}': ${msg}`,
log.warn(
`Shutdown error for '${entry.id}': ${msg}`,
);
entry.health.status = 'degraded';
}
Expand Down
Loading
Loading