Skip to content

Commit 14c97c2

Browse files
committed
Integrate Cognitive Loop into Agent Class #7968
1 parent 13de816 commit 14c97c2

3 files changed

Lines changed: 124 additions & 6 deletions

File tree

ai/Agent.mjs

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import Base from '../src/core/Base.mjs';
2-
import Client from './mcp/client/Client.mjs';
1+
import Base from '../src/core/Base.mjs';
2+
import Client from './mcp/client/Client.mjs';
3+
import ContextAssembler from './context/Assembler.mjs';
4+
import GeminiProvider from './provider/Gemini.mjs';
5+
import Loop from './agent/Loop.mjs';
6+
import Scheduler from './agent/Scheduler.mjs';
37

48
/**
5-
* A base class for AI Agents that manages multiple MCP Client connections.
9+
* A base class for AI Agents that manages multiple MCP Client connections
10+
* and orchestrates the autonomous cognitive runtime.
11+
*
612
* @class Neo.ai.Agent
713
* @extends Neo.core.Base
814
*/
@@ -13,6 +19,16 @@ class Agent extends Base {
1319
* @protected
1420
*/
1521
className: 'Neo.ai.Agent',
22+
/**
23+
* The Loop instance.
24+
* @member {Neo.ai.agent.Loop|null} loop=null
25+
*/
26+
loop: null,
27+
/**
28+
* The AI Provider class or instance.
29+
* @member {Neo.ai.provider.Base} modelProvider=GeminiProvider
30+
*/
31+
modelProvider: GeminiProvider,
1632
/**
1733
* A list of server names (keys in ClientConfig) to connect to.
1834
* @member {String[]} servers=[]
@@ -28,12 +44,13 @@ class Agent extends Base {
2844

2945
/**
3046
* Async initialization sequence.
31-
* Creates and connects all configured clients.
47+
* Creates and connects all configured clients, then initializes the Cognitive Runtime.
3248
* @returns {Promise<void>}
3349
*/
3450
async initAsync() {
3551
await super.initAsync();
3652

53+
// 1. Connect to MCP Servers
3754
const readyPromises = [];
3855

3956
for (const serverName of this.servers) {
@@ -48,19 +65,70 @@ class Agent extends Base {
4865
}
4966

5067
await Promise.all(readyPromises);
68+
console.log('[Agent] Connected to MCP servers:', Object.keys(this.clients));
69+
70+
// 2. Initialize Cognitive Runtime
71+
console.log('[Agent] Initializing Cognitive Runtime...');
72+
73+
const provider = Neo.create(this.modelProvider);
5174

52-
console.log('[Agent] Final clients map:', Object.keys(this.clients));
75+
const assembler = Neo.create(ContextAssembler);
76+
await assembler.initAsync(); // Connects to Memory Core via Services SDK
77+
78+
const scheduler = Neo.create(Scheduler);
79+
80+
// Create the Loop
81+
this.loop = Neo.create(Loop, {
82+
provider,
83+
assembler,
84+
scheduler,
85+
// Inject clients into the loop for Tool Execution (Future Phase)
86+
// tools: this.clients
87+
});
88+
89+
console.log('[Agent] Runtime Ready.');
5390
}
5491

5592
/**
56-
* Disconnects all clients.
93+
* Disconnects all clients and stops the loop.
5794
*/
5895
async disconnect() {
96+
this.stop();
97+
5998
for (const client of Object.values(this.clients)) {
6099
await client.destroy();
61100
}
62101
this.clients = {};
63102
}
103+
104+
/**
105+
* Starts the autonomous loop.
106+
*/
107+
start() {
108+
this.loop?.start();
109+
}
110+
111+
/**
112+
* Stops the autonomous loop.
113+
*/
114+
stop() {
115+
this.loop?.stop();
116+
}
117+
118+
/**
119+
* Schedules an event for the agent to process.
120+
* @param {Object} event
121+
* @param {String} event.type
122+
* @param {*} event.data
123+
* @param {String} [event.priority]
124+
*/
125+
schedule(event) {
126+
if (!this.loop) {
127+
console.warn('[Agent] Cannot schedule event: Loop not initialized.');
128+
return;
129+
}
130+
this.loop.scheduler.add(event);
131+
}
64132
}
65133

66134
export default Neo.setupClass(Agent);

ai/agent/Scheduler.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ class Scheduler extends Base {
4242
*/
4343
add(event) {
4444
const priority = event.priority || this.determinePriority(event.type);
45+
46+
// Ensure priority is set on the stored event for downstream visibility
47+
event.priority = priority;
4548

4649
if (!this.queues[priority]) {
4750
console.warn(`[Scheduler] Unknown priority '${priority}' for event '${event.type}'. Defaulting to 'normal'.`);

ai/examples/test-agent.mjs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env node
2+
3+
import Neo from '../../src/Neo.mjs';
4+
import * as core from '../../src/core/_export.mjs';
5+
import Agent from '../Agent.mjs';
6+
import path from 'path';
7+
import { fileURLToPath } from 'url';
8+
import dotenv from 'dotenv';
9+
10+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
11+
dotenv.config({path: path.resolve(__dirname, '../.env'), quiet: true});
12+
13+
async function run() {
14+
console.log('🧪 Testing Neo.ai.Agent Integration...');
15+
16+
if (!process.env.GEMINI_API_KEY) {
17+
console.error('❌ Skipped: GEMINI_API_KEY not found');
18+
return;
19+
}
20+
21+
// 1. Create Agent (connecting to memory-core via MCP for testing if needed, but Loop uses SDK)
22+
// We don't strictly need MCP servers running for this test since the Loop uses "Thick Client" services.
23+
// But let's pass an empty servers list to keep it fast.
24+
const agent = Neo.create(Agent, {
25+
servers: []
26+
});
27+
28+
await agent.initAsync();
29+
30+
// 2. Feed Event
31+
console.log('📥 Scheduling: "Who is the CEO of Google?"');
32+
agent.schedule({
33+
type: 'user:input',
34+
data: 'Who is the CEO of Google?'
35+
});
36+
37+
// 3. Start
38+
agent.start();
39+
40+
// 4. Wait
41+
setTimeout(() => {
42+
agent.stop();
43+
process.exit(0);
44+
}, 5000);
45+
}
46+
47+
run();

0 commit comments

Comments
 (0)