wyrm-mcp 4.0.0 → 5.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/dist/agent-daemon.d.ts +72 -0
- package/dist/agent-daemon.d.ts.map +1 -0
- package/dist/agent-daemon.js +268 -0
- package/dist/agent-daemon.js.map +1 -0
- package/dist/agent-loop.d.ts +86 -0
- package/dist/agent-loop.d.ts.map +1 -0
- package/dist/agent-loop.js +321 -0
- package/dist/agent-loop.js.map +1 -0
- package/dist/autoconfig.d.ts.map +1 -1
- package/dist/autoconfig.js +13 -2
- package/dist/autoconfig.js.map +1 -1
- package/dist/goals.d.ts +95 -0
- package/dist/goals.d.ts.map +1 -0
- package/dist/goals.js +146 -0
- package/dist/goals.js.map +1 -0
- package/dist/index.js +576 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-client.d.ts +76 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +259 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +101 -0
- package/dist/migrations.js.map +1 -1
- package/dist/wyrm-loop.d.ts +27 -0
- package/dist/wyrm-loop.d.ts.map +1 -0
- package/dist/wyrm-loop.js +162 -0
- package/dist/wyrm-loop.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent daemon process manager.
|
|
3
|
+
*
|
|
4
|
+
* Lets an AI client (Claude / Codex / Cursor / etc.) bootstrap, monitor,
|
|
5
|
+
* and tear down the `wyrm-loop` autonomous scheduler without the
|
|
6
|
+
* operator running shell commands. The MCP server can spawn the daemon
|
|
7
|
+
* as a detached background process, write a PID + log file under
|
|
8
|
+
* `~/.wyrm/`, and check liveness on demand.
|
|
9
|
+
*
|
|
10
|
+
* Files (all under `~/.wyrm/`):
|
|
11
|
+
* wyrm-loop.pid PID of the running daemon (single-line)
|
|
12
|
+
* wyrm-loop.log Stdout/stderr of the daemon (rotated at 1MB)
|
|
13
|
+
*
|
|
14
|
+
* Single-instance guarantee — if a PID file exists and the process is
|
|
15
|
+
* alive, `start()` refuses (no fork-bomb). `restart()` is provided as
|
|
16
|
+
* an explicit operation.
|
|
17
|
+
*
|
|
18
|
+
* @copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
19
|
+
* @license Proprietary
|
|
20
|
+
*/
|
|
21
|
+
import type Database from 'better-sqlite3';
|
|
22
|
+
export interface DaemonStatus {
|
|
23
|
+
running: boolean;
|
|
24
|
+
pid: number | null;
|
|
25
|
+
pid_file: string;
|
|
26
|
+
log_file: string;
|
|
27
|
+
started_at?: string;
|
|
28
|
+
uptime_seconds?: number;
|
|
29
|
+
last_action?: {
|
|
30
|
+
ran_at: string;
|
|
31
|
+
actor: string;
|
|
32
|
+
goal_id: number | null;
|
|
33
|
+
summary: string;
|
|
34
|
+
result_status: string | null;
|
|
35
|
+
};
|
|
36
|
+
active_goals: number;
|
|
37
|
+
total_iterations: number;
|
|
38
|
+
}
|
|
39
|
+
export interface StartOptions {
|
|
40
|
+
interval_seconds?: number;
|
|
41
|
+
max_steps?: number;
|
|
42
|
+
project_path?: string;
|
|
43
|
+
verbose?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface StartResult {
|
|
46
|
+
ok: boolean;
|
|
47
|
+
pid?: number;
|
|
48
|
+
status?: DaemonStatus;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
export declare class AgentDaemon {
|
|
52
|
+
private db;
|
|
53
|
+
constructor(db: Database.Database);
|
|
54
|
+
/** Current daemon status. Always safe to call. */
|
|
55
|
+
status(): DaemonStatus;
|
|
56
|
+
/** Start the daemon. No-op if already running. */
|
|
57
|
+
start(opts?: StartOptions): StartResult;
|
|
58
|
+
/** Stop the daemon. Sends SIGTERM, then SIGKILL after a grace period. */
|
|
59
|
+
stop(opts?: {
|
|
60
|
+
grace_ms?: number;
|
|
61
|
+
}): Promise<{
|
|
62
|
+
ok: boolean;
|
|
63
|
+
was_running: boolean;
|
|
64
|
+
pid?: number;
|
|
65
|
+
error?: string;
|
|
66
|
+
}>;
|
|
67
|
+
/** Stop + Start in sequence. */
|
|
68
|
+
restart(opts?: StartOptions): Promise<StartResult>;
|
|
69
|
+
/** Read the last N lines of the daemon log. */
|
|
70
|
+
recentLog(lines?: number): string;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=agent-daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-daemon.d.ts","sourceRoot":"","sources":["../src/agent-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqED,qBAAa,WAAW;IACV,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAEzC,kDAAkD;IAClD,MAAM,IAAI,YAAY;IAuDtB,kDAAkD;IAClD,KAAK,CAAC,IAAI,GAAE,YAAiB,GAAG,WAAW;IA8D3C,yEAAyE;IACnE,IAAI,CAAC,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAgC1H,gCAAgC;IAC1B,OAAO,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IAK5D,+CAA+C;IAC/C,SAAS,CAAC,KAAK,SAAK,GAAG,MAAM;CAU9B"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent daemon process manager.
|
|
3
|
+
*
|
|
4
|
+
* Lets an AI client (Claude / Codex / Cursor / etc.) bootstrap, monitor,
|
|
5
|
+
* and tear down the `wyrm-loop` autonomous scheduler without the
|
|
6
|
+
* operator running shell commands. The MCP server can spawn the daemon
|
|
7
|
+
* as a detached background process, write a PID + log file under
|
|
8
|
+
* `~/.wyrm/`, and check liveness on demand.
|
|
9
|
+
*
|
|
10
|
+
* Files (all under `~/.wyrm/`):
|
|
11
|
+
* wyrm-loop.pid PID of the running daemon (single-line)
|
|
12
|
+
* wyrm-loop.log Stdout/stderr of the daemon (rotated at 1MB)
|
|
13
|
+
*
|
|
14
|
+
* Single-instance guarantee — if a PID file exists and the process is
|
|
15
|
+
* alive, `start()` refuses (no fork-bomb). `restart()` is provided as
|
|
16
|
+
* an explicit operation.
|
|
17
|
+
*
|
|
18
|
+
* @copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
19
|
+
* @license Proprietary
|
|
20
|
+
*/
|
|
21
|
+
import { spawn } from 'child_process';
|
|
22
|
+
import { existsSync, readFileSync, writeFileSync, statSync, openSync, renameSync, unlinkSync, mkdirSync } from 'fs';
|
|
23
|
+
import { homedir } from 'os';
|
|
24
|
+
import { join, dirname, resolve } from 'path';
|
|
25
|
+
import { fileURLToPath } from 'url';
|
|
26
|
+
const WYRM_DIR = join(homedir(), '.wyrm');
|
|
27
|
+
const PID_FILE = join(WYRM_DIR, 'wyrm-loop.pid');
|
|
28
|
+
const LOG_FILE = join(WYRM_DIR, 'wyrm-loop.log');
|
|
29
|
+
const LOG_FILE_OLD = join(WYRM_DIR, 'wyrm-loop.log.1');
|
|
30
|
+
const MAX_LOG_BYTES = 1_000_000;
|
|
31
|
+
function ensureWyrmDir() {
|
|
32
|
+
if (!existsSync(WYRM_DIR))
|
|
33
|
+
mkdirSync(WYRM_DIR, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
function rotateLogIfLarge() {
|
|
36
|
+
try {
|
|
37
|
+
if (existsSync(LOG_FILE) && statSync(LOG_FILE).size > MAX_LOG_BYTES) {
|
|
38
|
+
if (existsSync(LOG_FILE_OLD))
|
|
39
|
+
unlinkSync(LOG_FILE_OLD);
|
|
40
|
+
renameSync(LOG_FILE, LOG_FILE_OLD);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch { /* best-effort */ }
|
|
44
|
+
}
|
|
45
|
+
function readPid() {
|
|
46
|
+
try {
|
|
47
|
+
const raw = readFileSync(PID_FILE, 'utf-8').trim();
|
|
48
|
+
const pid = parseInt(raw, 10);
|
|
49
|
+
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isProcessAlive(pid) {
|
|
56
|
+
try {
|
|
57
|
+
// signal 0 doesn't kill; just checks existence + permission
|
|
58
|
+
process.kill(pid, 0);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Find the bundled `wyrm-loop` script path. Resolves relative to this
|
|
66
|
+
* module so it works whether installed via npm, run from source, or
|
|
67
|
+
* invoked from a global symlink. */
|
|
68
|
+
function locateLoopBinary() {
|
|
69
|
+
// 1. import.meta.url → packages/mcp-server/dist/agent-daemon.js
|
|
70
|
+
try {
|
|
71
|
+
const here = fileURLToPath(import.meta.url);
|
|
72
|
+
const candidates = [
|
|
73
|
+
// installed alongside (dist/wyrm-loop.js)
|
|
74
|
+
resolve(dirname(here), 'wyrm-loop.js'),
|
|
75
|
+
// source layout
|
|
76
|
+
resolve(dirname(here), '..', 'dist', 'wyrm-loop.js'),
|
|
77
|
+
];
|
|
78
|
+
for (const p of candidates) {
|
|
79
|
+
if (existsSync(p))
|
|
80
|
+
return p;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch { /* fall through */ }
|
|
84
|
+
// 2. Look in PATH for the `wyrm-loop` binary (set up by `npm install -g`)
|
|
85
|
+
const pathDirs = (process.env.PATH ?? '').split(':');
|
|
86
|
+
for (const dir of pathDirs) {
|
|
87
|
+
const cand = join(dir, 'wyrm-loop');
|
|
88
|
+
if (existsSync(cand))
|
|
89
|
+
return cand;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
export class AgentDaemon {
|
|
94
|
+
db;
|
|
95
|
+
constructor(db) {
|
|
96
|
+
this.db = db;
|
|
97
|
+
}
|
|
98
|
+
/** Current daemon status. Always safe to call. */
|
|
99
|
+
status() {
|
|
100
|
+
const pid = readPid();
|
|
101
|
+
const running = pid != null && isProcessAlive(pid);
|
|
102
|
+
let started_at;
|
|
103
|
+
let uptime_seconds;
|
|
104
|
+
try {
|
|
105
|
+
if (existsSync(PID_FILE)) {
|
|
106
|
+
const st = statSync(PID_FILE);
|
|
107
|
+
started_at = st.mtime.toISOString();
|
|
108
|
+
uptime_seconds = Math.round((Date.now() - st.mtime.getTime()) / 1000);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch { /* best-effort */ }
|
|
112
|
+
// Read latest agent_actions row for "last action" summary
|
|
113
|
+
let last_action;
|
|
114
|
+
try {
|
|
115
|
+
const row = this.db.prepare(`
|
|
116
|
+
SELECT actor, goal_id, action_kind, summary, result_status, ran_at
|
|
117
|
+
FROM agent_actions ORDER BY id DESC LIMIT 1
|
|
118
|
+
`).get();
|
|
119
|
+
if (row)
|
|
120
|
+
last_action = {
|
|
121
|
+
ran_at: row.ran_at, actor: row.actor, goal_id: row.goal_id,
|
|
122
|
+
summary: `${row.action_kind}: ${row.summary}`.slice(0, 200),
|
|
123
|
+
result_status: row.result_status,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
catch { /* table may not exist on pre-v5 DBs */ }
|
|
127
|
+
let active_goals = 0;
|
|
128
|
+
let total_iterations = 0;
|
|
129
|
+
try {
|
|
130
|
+
active_goals = this.db.prepare(`SELECT COUNT(*) as c FROM goals WHERE status = 'active'`).get().c;
|
|
131
|
+
total_iterations = this.db.prepare(`SELECT COALESCE(SUM(iterations_count), 0) as c FROM goals`).get().c;
|
|
132
|
+
}
|
|
133
|
+
catch { /* pre-v5 DB */ }
|
|
134
|
+
return {
|
|
135
|
+
running,
|
|
136
|
+
pid: running ? pid : null,
|
|
137
|
+
pid_file: PID_FILE,
|
|
138
|
+
log_file: LOG_FILE,
|
|
139
|
+
started_at: running ? started_at : undefined,
|
|
140
|
+
uptime_seconds: running ? uptime_seconds : undefined,
|
|
141
|
+
last_action,
|
|
142
|
+
active_goals,
|
|
143
|
+
total_iterations,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/** Start the daemon. No-op if already running. */
|
|
147
|
+
start(opts = {}) {
|
|
148
|
+
ensureWyrmDir();
|
|
149
|
+
rotateLogIfLarge();
|
|
150
|
+
const cur = this.status();
|
|
151
|
+
if (cur.running) {
|
|
152
|
+
return { ok: true, pid: cur.pid ?? undefined, status: cur };
|
|
153
|
+
}
|
|
154
|
+
// Clear stale PID file from a crashed prior run
|
|
155
|
+
if (existsSync(PID_FILE)) {
|
|
156
|
+
try {
|
|
157
|
+
unlinkSync(PID_FILE);
|
|
158
|
+
}
|
|
159
|
+
catch { /* ignore */ }
|
|
160
|
+
}
|
|
161
|
+
const binary = locateLoopBinary();
|
|
162
|
+
if (!binary) {
|
|
163
|
+
return { ok: false, error: 'Could not locate wyrm-loop binary. Run `npm install -g wyrm-mcp` or `npm run build` in packages/mcp-server.' };
|
|
164
|
+
}
|
|
165
|
+
const args = ['--interval', String(opts.interval_seconds ?? 600)];
|
|
166
|
+
if (opts.max_steps)
|
|
167
|
+
args.push('--max-steps', String(opts.max_steps));
|
|
168
|
+
if (opts.project_path)
|
|
169
|
+
args.push('--project', opts.project_path);
|
|
170
|
+
if (opts.verbose)
|
|
171
|
+
args.push('--verbose');
|
|
172
|
+
// Open the log file once, share fd with the child
|
|
173
|
+
let logFd;
|
|
174
|
+
try {
|
|
175
|
+
logFd = openSync(LOG_FILE, 'a');
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
return { ok: false, error: `Could not open log file ${LOG_FILE}: ${err.message}` };
|
|
179
|
+
}
|
|
180
|
+
let child;
|
|
181
|
+
try {
|
|
182
|
+
child = spawn('node', [binary, ...args], {
|
|
183
|
+
detached: true,
|
|
184
|
+
stdio: ['ignore', logFd, logFd],
|
|
185
|
+
env: { ...process.env, WYRM_LOOP_LOG: opts.verbose ? '1' : '0' },
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
return { ok: false, error: `spawn failed: ${err.message}` };
|
|
190
|
+
}
|
|
191
|
+
if (!child.pid) {
|
|
192
|
+
return { ok: false, error: 'spawn returned no PID' };
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
writeFileSync(PID_FILE, String(child.pid), 'utf-8');
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
// Process is up but we can't track it — kill to keep state consistent
|
|
199
|
+
try {
|
|
200
|
+
process.kill(child.pid, 'SIGTERM');
|
|
201
|
+
}
|
|
202
|
+
catch { /* ignore */ }
|
|
203
|
+
return { ok: false, error: `Could not write PID file: ${err.message}` };
|
|
204
|
+
}
|
|
205
|
+
// unref so this process doesn't wait on the child
|
|
206
|
+
child.unref();
|
|
207
|
+
// Brief settle delay so status() reflects the new state
|
|
208
|
+
return { ok: true, pid: child.pid, status: this.status() };
|
|
209
|
+
}
|
|
210
|
+
/** Stop the daemon. Sends SIGTERM, then SIGKILL after a grace period. */
|
|
211
|
+
async stop(opts = {}) {
|
|
212
|
+
const pid = readPid();
|
|
213
|
+
if (pid == null) {
|
|
214
|
+
return { ok: true, was_running: false };
|
|
215
|
+
}
|
|
216
|
+
if (!isProcessAlive(pid)) {
|
|
217
|
+
// Stale PID file
|
|
218
|
+
try {
|
|
219
|
+
unlinkSync(PID_FILE);
|
|
220
|
+
}
|
|
221
|
+
catch { /* ignore */ }
|
|
222
|
+
return { ok: true, was_running: false, pid };
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
process.kill(pid, 'SIGTERM');
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
return { ok: false, was_running: true, pid, error: `SIGTERM failed: ${err.message}` };
|
|
229
|
+
}
|
|
230
|
+
const grace = Math.max(100, Math.min(opts.grace_ms ?? 3000, 30_000));
|
|
231
|
+
const start = Date.now();
|
|
232
|
+
while (Date.now() - start < grace) {
|
|
233
|
+
if (!isProcessAlive(pid))
|
|
234
|
+
break;
|
|
235
|
+
await new Promise(r => setTimeout(r, 100));
|
|
236
|
+
}
|
|
237
|
+
if (isProcessAlive(pid)) {
|
|
238
|
+
try {
|
|
239
|
+
process.kill(pid, 'SIGKILL');
|
|
240
|
+
}
|
|
241
|
+
catch { /* may already be dead */ }
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
unlinkSync(PID_FILE);
|
|
245
|
+
}
|
|
246
|
+
catch { /* ignore */ }
|
|
247
|
+
return { ok: true, was_running: true, pid };
|
|
248
|
+
}
|
|
249
|
+
/** Stop + Start in sequence. */
|
|
250
|
+
async restart(opts = {}) {
|
|
251
|
+
await this.stop({ grace_ms: 3000 });
|
|
252
|
+
return this.start(opts);
|
|
253
|
+
}
|
|
254
|
+
/** Read the last N lines of the daemon log. */
|
|
255
|
+
recentLog(lines = 40) {
|
|
256
|
+
try {
|
|
257
|
+
if (!existsSync(LOG_FILE))
|
|
258
|
+
return '(log file does not exist)';
|
|
259
|
+
const raw = readFileSync(LOG_FILE, 'utf-8');
|
|
260
|
+
const all = raw.split('\n');
|
|
261
|
+
return all.slice(-Math.max(1, Math.min(lines, 1000))).join('\n');
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
return `(could not read log: ${err.message})`;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=agent-daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-daemon.js","sourceRoot":"","sources":["../src/agent-daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent loop — OODA + ReAct (Observe → Orient → Decide → Act).
|
|
3
|
+
*
|
|
4
|
+
* This is the thing that turns Wyrm from "memory tool" into "agent".
|
|
5
|
+
* Given a goal (or ad-hoc query), we run a multi-turn loop where:
|
|
6
|
+
*
|
|
7
|
+
* 1. Observe — assemble relevant context from Wyrm's own data
|
|
8
|
+
* (failures, truths, sessions, symbols, prior iterations)
|
|
9
|
+
* 2. Orient — LLM synthesises: "given this context, what's the state?"
|
|
10
|
+
* 3. Decide — LLM proposes ONE action: either a Wyrm tool call,
|
|
11
|
+
* an external MCP server call, or 'done' / 'block' / 'escalate'
|
|
12
|
+
* 4. Act — execute the proposed action, capture result
|
|
13
|
+
* 5. Loop — feed result back into the next Observe step
|
|
14
|
+
*
|
|
15
|
+
* Each iteration logs to `goal_iterations` if attached to a goal.
|
|
16
|
+
* Hard caps: `max_iterations` per goal, ~60s wall clock per iteration,
|
|
17
|
+
* actions matched against a whitelist (no `wyrm_audit_export` or other
|
|
18
|
+
* data-exfiltration tools from inside the loop).
|
|
19
|
+
*
|
|
20
|
+
* LLM protocol — JSON envelope works with both:
|
|
21
|
+
* - Ollama JSON mode (most models 7B+)
|
|
22
|
+
* - OpenAI native function calling (gpt-4o, gpt-4o-mini, ...)
|
|
23
|
+
*
|
|
24
|
+
* The response shape we ask for:
|
|
25
|
+
* {"thought":"...","action":"<tool_name>","args":{...}} or
|
|
26
|
+
* {"thought":"...","action":"done","summary":"..."} or
|
|
27
|
+
* {"thought":"...","action":"block","reason":"..."}
|
|
28
|
+
*
|
|
29
|
+
* @copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
30
|
+
* @license Proprietary
|
|
31
|
+
*/
|
|
32
|
+
import type Database from 'better-sqlite3';
|
|
33
|
+
import { OutboundMcpClient } from './mcp-client.js';
|
|
34
|
+
export interface AgentAction {
|
|
35
|
+
thought?: string;
|
|
36
|
+
action: string;
|
|
37
|
+
args?: Record<string, unknown>;
|
|
38
|
+
summary?: string;
|
|
39
|
+
reason?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface IterationResult {
|
|
42
|
+
iteration_num: number;
|
|
43
|
+
observe_summary: string;
|
|
44
|
+
orient_summary: string;
|
|
45
|
+
decided: AgentAction;
|
|
46
|
+
action_result: string;
|
|
47
|
+
outcome: 'progressed' | 'blocked' | 'done' | 'error';
|
|
48
|
+
latency_ms: number;
|
|
49
|
+
tokens_in?: number;
|
|
50
|
+
tokens_out?: number;
|
|
51
|
+
model: string;
|
|
52
|
+
degraded: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface ToolDispatcher {
|
|
55
|
+
(toolName: string, args: Record<string, unknown>): Promise<{
|
|
56
|
+
ok: boolean;
|
|
57
|
+
result?: unknown;
|
|
58
|
+
error?: string;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
export declare class AgentLoop {
|
|
62
|
+
private db;
|
|
63
|
+
private externalClient;
|
|
64
|
+
private internalToolDispatch;
|
|
65
|
+
private subAgent;
|
|
66
|
+
private goals;
|
|
67
|
+
private failures;
|
|
68
|
+
constructor(db: Database.Database, externalClient: OutboundMcpClient, internalToolDispatch: ToolDispatcher);
|
|
69
|
+
/** Run ONE OODA iteration on a goal. Returns the iteration result. */
|
|
70
|
+
iterate(goal_id: number, opts?: {
|
|
71
|
+
ollama_url?: string;
|
|
72
|
+
openai_api_key?: string;
|
|
73
|
+
model_override?: string;
|
|
74
|
+
}): Promise<IterationResult | null>;
|
|
75
|
+
/** Iterate until done / blocked / cap hit. Returns the array of iterations. */
|
|
76
|
+
pursue(goal_id: number, opts?: {
|
|
77
|
+
max_steps?: number;
|
|
78
|
+
ollama_url?: string;
|
|
79
|
+
openai_api_key?: string;
|
|
80
|
+
model_override?: string;
|
|
81
|
+
}): Promise<IterationResult[]>;
|
|
82
|
+
private observe;
|
|
83
|
+
private orientAndDecide;
|
|
84
|
+
private act;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=agent-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAwBpD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/G;AAED,qBAAa,SAAS;IAMlB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,oBAAoB;IAP9B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAkB;gBAGxB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,cAAc,EAAE,iBAAiB,EACjC,oBAAoB,EAAE,cAAc;IAO9C,sEAAsE;IAChE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IA+EjJ,+EAA+E;IACzE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAgB/J,OAAO,CAAC,OAAO;YAwED,eAAe;YA0Ef,GAAG;CA4BlB"}
|