groove-dev 0.27.175 → 0.27.180
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/AUTONOMOUS_AGENT_FRAMEWORK.md +654 -0
- package/innerchat/Screenshot_2026-06-09_at_2.19.42_PM.png +0 -0
- package/moe-training/client/envelope-builder.js +22 -5
- package/moe-training/shared/constants.js +11 -1
- package/moe-training/shared/envelope-schema.js +11 -3
- package/moe-training/test/client/envelope-builder.test.js +42 -6
- package/moe-training/test/shared/envelope-schema.test.js +11 -4
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +3 -1
- package/node_modules/@groove-dev/daemon/src/autostate.js +198 -0
- package/node_modules/@groove-dev/daemon/src/index.js +6 -0
- package/node_modules/@groove-dev/daemon/src/orchestrator.js +585 -0
- package/node_modules/@groove-dev/daemon/src/process.js +27 -2
- package/node_modules/@groove-dev/daemon/src/registry.js +2 -1
- package/node_modules/@groove-dev/daemon/src/routes/auto-agents.js +264 -0
- package/node_modules/@groove-dev/daemon/src/validate.js +6 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-CTer01Vg.js +1065 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-DTFtRtkx.css +1 -0
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/App.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +53 -0
- package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +95 -2
- package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +50 -1
- package/node_modules/@groove-dev/gui/src/components/auto-agents/auto-agent-card.jsx +139 -0
- package/node_modules/@groove-dev/gui/src/components/auto-agents/auto-agent-detail.jsx +286 -0
- package/node_modules/@groove-dev/gui/src/components/auto-agents/setup-wizard.jsx +284 -0
- package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -1
- package/node_modules/@groove-dev/gui/src/stores/groove.js +14 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/auto-agents-slice.js +149 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +14 -2
- package/node_modules/@groove-dev/gui/src/views/auto-agents.jsx +70 -0
- package/node_modules/@groove-dev/gui/src/views/settings.jsx +13 -6
- package/node_modules/moe-training/client/envelope-builder.js +22 -5
- package/node_modules/moe-training/shared/constants.js +11 -1
- package/node_modules/moe-training/shared/envelope-schema.js +11 -3
- package/node_modules/moe-training/test/client/envelope-builder.test.js +42 -6
- package/node_modules/moe-training/test/shared/envelope-schema.test.js +11 -4
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +3 -1
- package/packages/daemon/src/autostate.js +198 -0
- package/packages/daemon/src/index.js +6 -0
- package/packages/daemon/src/orchestrator.js +585 -0
- package/packages/daemon/src/process.js +27 -2
- package/packages/daemon/src/registry.js +2 -1
- package/packages/daemon/src/routes/auto-agents.js +264 -0
- package/packages/daemon/src/validate.js +6 -0
- package/packages/gui/dist/assets/index-CTer01Vg.js +1065 -0
- package/packages/gui/dist/assets/index-DTFtRtkx.css +1 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/App.jsx +2 -0
- package/packages/gui/src/components/agents/agent-config.jsx +53 -0
- package/packages/gui/src/components/agents/agent-panel.jsx +95 -2
- package/packages/gui/src/components/agents/spawn-wizard.jsx +50 -1
- package/packages/gui/src/components/auto-agents/auto-agent-card.jsx +139 -0
- package/packages/gui/src/components/auto-agents/auto-agent-detail.jsx +286 -0
- package/packages/gui/src/components/auto-agents/setup-wizard.jsx +284 -0
- package/packages/gui/src/components/layout/activity-bar.jsx +2 -1
- package/packages/gui/src/stores/groove.js +14 -0
- package/packages/gui/src/stores/slices/auto-agents-slice.js +149 -0
- package/packages/gui/src/stores/slices/ui-slice.js +14 -2
- package/packages/gui/src/views/auto-agents.jsx +70 -0
- package/packages/gui/src/views/settings.jsx +13 -6
- package/node_modules/@groove-dev/gui/dist/assets/index-BMaxZVeX.js +0 -1035
- package/node_modules/@groove-dev/gui/dist/assets/index-BvJwMNAX.css +0 -1
- package/packages/gui/dist/assets/index-BMaxZVeX.js +0 -1035
- package/packages/gui/dist/assets/index-BvJwMNAX.css +0 -1
|
@@ -28,7 +28,17 @@ export const QUALITY_MULTIPLIERS = {
|
|
|
28
28
|
highQuality: 1.5,
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
// Hard ceiling on step.content, shared by the client trimmer (envelope-builder)
|
|
32
|
+
// and the ingest validator (envelope-schema). These MUST stay equal: the
|
|
33
|
+
// validator rejects the whole envelope when exceeded, which drops the entire
|
|
34
|
+
// session — so the client must trim to exactly this before building.
|
|
35
|
+
export const MAX_STEP_CONTENT_CHARS = 100_000;
|
|
36
|
+
export const MAX_TOKEN_COUNT = 100_000;
|
|
37
|
+
|
|
38
|
+
// Per-observation budget, in estimated tokens (~4 chars/token). Kept safely
|
|
39
|
+
// under MAX_STEP_CONTENT_CHARS so a parser-truncated observation plus its
|
|
40
|
+
// "[TRUNCATED …]" suffix still fits without a second trim downstream.
|
|
41
|
+
export const OBSERVATION_TOKEN_LIMIT = 24_000;
|
|
32
42
|
export const TIER_A_MIN_QUALITY = 70;
|
|
33
43
|
export const TIER_B_MIN_QUALITY = 50;
|
|
34
44
|
export const TRAINING_MIN_STEPS = 5;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
SUPPORTED_PROVIDERS,
|
|
5
|
+
MODEL_TIERS,
|
|
6
|
+
TRAINING_EXCLUSION_REASONS,
|
|
7
|
+
MAX_STEP_CONTENT_CHARS,
|
|
8
|
+
MAX_TOKEN_COUNT,
|
|
9
|
+
} from './constants.js';
|
|
4
10
|
|
|
5
11
|
export const STEP_TYPES = ['thought', 'action', 'observation', 'correction', 'resolution', 'error', 'coordination', 'edit', 'instruction', 'clarification', 'approval', 'delegate', 'yield'];
|
|
6
12
|
const VALID_QUALITY_TIERS = ['TIER_A', 'TIER_B', 'TIER_C'];
|
|
@@ -10,8 +16,10 @@ const VALID_MODEL_ENGINES = Object.keys(MODEL_TIERS);
|
|
|
10
16
|
const VALID_COMPLEXITIES = ['light', 'medium', 'heavy'];
|
|
11
17
|
const VALID_OUTCOME_STATUSES = ['SUCCESS', 'CRASH', 'KILLED'];
|
|
12
18
|
const MAX_STEPS_PER_ENVELOPE = 500;
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
// Sourced from shared constants — the client trims to the same value before
|
|
20
|
+
// building envelopes. Keeping one definition prevents the drift that silently
|
|
21
|
+
// truncated observations at 10k while the validator allowed more.
|
|
22
|
+
const MAX_STEP_CONTENT_LENGTH = MAX_STEP_CONTENT_CHARS;
|
|
15
23
|
const MAX_STEP_NUMBER = 50_000;
|
|
16
24
|
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
17
25
|
const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { describe, it } from 'node:test';
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
5
|
import { EnvelopeBuilder } from '../../client/envelope-builder.js';
|
|
6
|
-
import { CHUNK_SIZE } from '../../shared/constants.js';
|
|
6
|
+
import { CHUNK_SIZE, MAX_STEP_CONTENT_CHARS } from '../../shared/constants.js';
|
|
7
7
|
|
|
8
8
|
const metadata = {
|
|
9
9
|
model_engine: 'claude-opus-4-6',
|
|
@@ -74,12 +74,48 @@ describe('EnvelopeBuilder', () => {
|
|
|
74
74
|
assert.deepEqual(close.outcome, outcome);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
it('
|
|
77
|
+
it('leaves content under the ingest ceiling untouched', () => {
|
|
78
78
|
const builder = new EnvelopeBuilder('sess_1', 'user_1', metadata);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
assert.
|
|
79
|
+
builder.addStep({ step: 1, type: 'thought', timestamp: 123, content: 'x'.repeat(15_000) });
|
|
80
|
+
const step = builder.flush().trajectory_log[0];
|
|
81
|
+
assert.equal(step.content.length, 15_000);
|
|
82
|
+
assert.ok(!step.truncated);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('truncates step content at MAX_STEP_CONTENT_CHARS', () => {
|
|
86
|
+
const builder = new EnvelopeBuilder('sess_1', 'user_1', metadata);
|
|
87
|
+
builder.addStep({ step: 1, type: 'thought', timestamp: 123, content: 'x'.repeat(150_000) });
|
|
88
|
+
const step = builder.flush().trajectory_log[0];
|
|
89
|
+
assert.equal(step.content.length, MAX_STEP_CONTENT_CHARS);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Regression: a trim that doesn't flag itself looks like complete data to
|
|
93
|
+
// downstream training and silently corrupts the corpus.
|
|
94
|
+
it('never truncates silently — always sets truncated + original_token_count', () => {
|
|
95
|
+
const builder = new EnvelopeBuilder('sess_1', 'user_1', metadata);
|
|
96
|
+
builder.addStep({ step: 1, type: 'observation', timestamp: 123, content: 'x'.repeat(150_000) });
|
|
97
|
+
const step = builder.flush().trajectory_log[0];
|
|
98
|
+
assert.equal(step.truncated, true);
|
|
99
|
+
assert.equal(step.original_token_count, 37_500); // 150k chars / 4
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('preserves a parser-supplied original_token_count when trimming again', () => {
|
|
103
|
+
const builder = new EnvelopeBuilder('sess_1', 'user_1', metadata);
|
|
104
|
+
builder.addStep({
|
|
105
|
+
step: 1, type: 'observation', timestamp: 123,
|
|
106
|
+
content: 'x'.repeat(150_000), truncated: true, original_token_count: 99_000,
|
|
107
|
+
});
|
|
108
|
+
const step = builder.flush().trajectory_log[0];
|
|
109
|
+
// The parser saw the true original; our count only sees what survived it.
|
|
110
|
+
assert.equal(step.original_token_count, 99_000);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('output always satisfies the ingest validator', () => {
|
|
114
|
+
const builder = new EnvelopeBuilder('sess_1', 'user_1', metadata);
|
|
115
|
+
builder.addStep({ step: 1, type: 'observation', timestamp: 123, content: 'x'.repeat(500_000) });
|
|
116
|
+
const step = builder.flush().trajectory_log[0];
|
|
117
|
+
assert.ok(step.content.length <= MAX_STEP_CONTENT_CHARS,
|
|
118
|
+
'client must trim to the validator ceiling or the whole session is rejected');
|
|
83
119
|
});
|
|
84
120
|
|
|
85
121
|
it('caps token_count at 100000', () => {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { describe, it } from 'node:test';
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
5
|
import { validateEnvelope, STEP_TYPES } from '../../shared/envelope-schema.js';
|
|
6
|
-
import { TRAINING_EXCLUSION_REASONS } from '../../shared/constants.js';
|
|
6
|
+
import { TRAINING_EXCLUSION_REASONS, MAX_STEP_CONTENT_CHARS } from '../../shared/constants.js';
|
|
7
7
|
|
|
8
8
|
const VALID_HMAC = 'a'.repeat(64);
|
|
9
9
|
const VALID_APP_HASH = 'b'.repeat(64);
|
|
@@ -113,12 +113,19 @@ describe('envelope-schema', () => {
|
|
|
113
113
|
assert.ok(result.errors.some(e => e.includes('500')));
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
it('
|
|
116
|
+
it('accepts step content up to MAX_STEP_CONTENT_CHARS', () => {
|
|
117
117
|
const env = validEnvelope();
|
|
118
|
-
env.trajectory_log[0].content = 'x'.repeat(
|
|
118
|
+
env.trajectory_log[0].content = 'x'.repeat(MAX_STEP_CONTENT_CHARS);
|
|
119
|
+
const result = validateEnvelope(env);
|
|
120
|
+
assert.ok(!result.errors.some(e => e.includes('step.content exceeds')));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('rejects step content over MAX_STEP_CONTENT_CHARS', () => {
|
|
124
|
+
const env = validEnvelope();
|
|
125
|
+
env.trajectory_log[0].content = 'x'.repeat(MAX_STEP_CONTENT_CHARS + 1);
|
|
119
126
|
const result = validateEnvelope(env);
|
|
120
127
|
assert.equal(result.valid, false);
|
|
121
|
-
assert.ok(result.errors.some(e => e.includes(
|
|
128
|
+
assert.ok(result.errors.some(e => e.includes(String(MAX_STEP_CONTENT_CHARS))));
|
|
122
129
|
});
|
|
123
130
|
|
|
124
131
|
it('rejects step with token_count > 100,000', () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groove-dev",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.180",
|
|
4
4
|
"description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
|
|
5
5
|
"license": "FSL-1.1-Apache-2.0",
|
|
6
6
|
"author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
|
|
@@ -28,6 +28,7 @@ import { registerFileRoutes, resetEditorRoot } from './routes/files.js';
|
|
|
28
28
|
import { registerNetworkRoutes } from './routes/network.js';
|
|
29
29
|
import { registerScheduleRoutes } from './routes/schedules.js';
|
|
30
30
|
import { registerInnerChatRoutes } from './routes/innerchat.js';
|
|
31
|
+
import { registerAutoAgentRoutes } from './routes/auto-agents.js';
|
|
31
32
|
|
|
32
33
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
33
34
|
const pkgVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
@@ -127,7 +128,7 @@ export function createApi(app, daemon) {
|
|
|
127
128
|
next();
|
|
128
129
|
});
|
|
129
130
|
|
|
130
|
-
app.use(express.json({ limit: '
|
|
131
|
+
app.use(express.json({ limit: '100mb' }));
|
|
131
132
|
|
|
132
133
|
// Health check
|
|
133
134
|
app.get('/api/health', (req, res) => {
|
|
@@ -177,6 +178,7 @@ export function createApi(app, daemon) {
|
|
|
177
178
|
registerNetworkRoutes(app, daemon);
|
|
178
179
|
registerScheduleRoutes(app, daemon);
|
|
179
180
|
registerInnerChatRoutes(app, daemon);
|
|
181
|
+
registerAutoAgentRoutes(app, daemon);
|
|
180
182
|
|
|
181
183
|
|
|
182
184
|
// Token usage
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// GROOVE — Auto Agent State Persistence
|
|
2
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
3
|
+
//
|
|
4
|
+
// Manages the persistent state layer for autonomous agents:
|
|
5
|
+
// .groove/auto/<agentDefId>/
|
|
6
|
+
// state.json — phase, cycle, history, champion
|
|
7
|
+
// journal.jsonl — append-only accumulated knowledge
|
|
8
|
+
// roadmap.md — staged goals with graduation criteria
|
|
9
|
+
// prompt.md — system prompt (identity + tools + rules)
|
|
10
|
+
// runs/ — per-run logs and output
|
|
11
|
+
|
|
12
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync, readdirSync, renameSync, copyFileSync, statSync, rmSync } from 'fs';
|
|
13
|
+
import { resolve } from 'path';
|
|
14
|
+
import { randomUUID } from 'crypto';
|
|
15
|
+
|
|
16
|
+
const MAX_HISTORY = 200;
|
|
17
|
+
const MAX_JOURNAL_ENTRIES = 500;
|
|
18
|
+
|
|
19
|
+
function safeJsonParse(str, fallback) {
|
|
20
|
+
try { return JSON.parse(str); } catch { return fallback; }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function safeDict(obj, key) {
|
|
24
|
+
const v = obj?.[key];
|
|
25
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class AutoState {
|
|
29
|
+
constructor(grooveDir) {
|
|
30
|
+
this.baseDir = resolve(grooveDir, 'auto');
|
|
31
|
+
mkdirSync(this.baseDir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_agentDir(defId) {
|
|
35
|
+
const dir = resolve(this.baseDir, defId);
|
|
36
|
+
mkdirSync(dir, { recursive: true });
|
|
37
|
+
mkdirSync(resolve(dir, 'runs'), { recursive: true });
|
|
38
|
+
return dir;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// --- State (state.json) ---
|
|
42
|
+
|
|
43
|
+
getState(defId) {
|
|
44
|
+
const p = resolve(this._agentDir(defId), 'state.json');
|
|
45
|
+
if (!existsSync(p)) return this._defaultState();
|
|
46
|
+
return safeJsonParse(readFileSync(p, 'utf8'), this._defaultState());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setState(defId, updates) {
|
|
50
|
+
const dir = this._agentDir(defId);
|
|
51
|
+
const p = resolve(dir, 'state.json');
|
|
52
|
+
const bak = resolve(dir, 'state.json.bak');
|
|
53
|
+
const current = this.getState(defId);
|
|
54
|
+
|
|
55
|
+
const merged = { ...current };
|
|
56
|
+
const allowed = ['phase', 'phase_note', 'cycle', 'current_run', 'champion', 'paused', 'error'];
|
|
57
|
+
for (const key of allowed) {
|
|
58
|
+
if (key in updates) merged[key] = updates[key];
|
|
59
|
+
}
|
|
60
|
+
merged.updatedAt = new Date().toISOString();
|
|
61
|
+
|
|
62
|
+
if (existsSync(p)) {
|
|
63
|
+
try { copyFileSync(p, bak); } catch { /* best effort */ }
|
|
64
|
+
}
|
|
65
|
+
const tmp = resolve(dir, `state.${randomUUID().slice(0, 8)}.tmp`);
|
|
66
|
+
writeFileSync(tmp, JSON.stringify(merged, null, 2));
|
|
67
|
+
renameSync(tmp, p);
|
|
68
|
+
return merged;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
appendHistory(defId, entry) {
|
|
72
|
+
const state = this.getState(defId);
|
|
73
|
+
if (!Array.isArray(state.history)) state.history = [];
|
|
74
|
+
state.history.push({
|
|
75
|
+
...entry,
|
|
76
|
+
timestamp: new Date().toISOString(),
|
|
77
|
+
});
|
|
78
|
+
if (state.history.length > MAX_HISTORY) {
|
|
79
|
+
state.history = state.history.slice(-MAX_HISTORY);
|
|
80
|
+
}
|
|
81
|
+
this.setState(defId, { history: state.history });
|
|
82
|
+
return state.history;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
_defaultState() {
|
|
86
|
+
return {
|
|
87
|
+
phase: 'idle',
|
|
88
|
+
phase_note: '',
|
|
89
|
+
cycle: 0,
|
|
90
|
+
current_run: null,
|
|
91
|
+
champion: null,
|
|
92
|
+
history: [],
|
|
93
|
+
paused: false,
|
|
94
|
+
error: null,
|
|
95
|
+
createdAt: new Date().toISOString(),
|
|
96
|
+
updatedAt: new Date().toISOString(),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- Journal (journal.jsonl) ---
|
|
101
|
+
|
|
102
|
+
getJournal(defId, { limit = 50, since } = {}) {
|
|
103
|
+
const p = resolve(this._agentDir(defId), 'journal.jsonl');
|
|
104
|
+
if (!existsSync(p)) return [];
|
|
105
|
+
const lines = readFileSync(p, 'utf8').trim().split('\n').filter(Boolean);
|
|
106
|
+
let entries = lines.map(l => safeJsonParse(l, null)).filter(Boolean);
|
|
107
|
+
if (since) {
|
|
108
|
+
entries = entries.filter(e => e.timestamp >= since);
|
|
109
|
+
}
|
|
110
|
+
return entries.slice(-limit);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
appendJournal(defId, entry) {
|
|
114
|
+
const p = resolve(this._agentDir(defId), 'journal.jsonl');
|
|
115
|
+
const record = {
|
|
116
|
+
...entry,
|
|
117
|
+
timestamp: new Date().toISOString(),
|
|
118
|
+
};
|
|
119
|
+
appendFileSync(p, JSON.stringify(record) + '\n');
|
|
120
|
+
this._pruneJournal(defId);
|
|
121
|
+
return record;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
_pruneJournal(defId) {
|
|
125
|
+
const p = resolve(this._agentDir(defId), 'journal.jsonl');
|
|
126
|
+
if (!existsSync(p)) return;
|
|
127
|
+
const lines = readFileSync(p, 'utf8').trim().split('\n').filter(Boolean);
|
|
128
|
+
if (lines.length > MAX_JOURNAL_ENTRIES) {
|
|
129
|
+
writeFileSync(p, lines.slice(-MAX_JOURNAL_ENTRIES).join('\n') + '\n');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// --- Roadmap (roadmap.md) ---
|
|
134
|
+
|
|
135
|
+
getRoadmap(defId) {
|
|
136
|
+
const p = resolve(this._agentDir(defId), 'roadmap.md');
|
|
137
|
+
if (!existsSync(p)) return '';
|
|
138
|
+
return readFileSync(p, 'utf8');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
setRoadmap(defId, content) {
|
|
142
|
+
const p = resolve(this._agentDir(defId), 'roadmap.md');
|
|
143
|
+
writeFileSync(p, content);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// --- Prompt (prompt.md) ---
|
|
147
|
+
|
|
148
|
+
getPrompt(defId) {
|
|
149
|
+
const p = resolve(this._agentDir(defId), 'prompt.md');
|
|
150
|
+
if (!existsSync(p)) return '';
|
|
151
|
+
return readFileSync(p, 'utf8');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
setPrompt(defId, content) {
|
|
155
|
+
const p = resolve(this._agentDir(defId), 'prompt.md');
|
|
156
|
+
writeFileSync(p, content);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// --- Run Logs ---
|
|
160
|
+
|
|
161
|
+
logRun(defId, runId, data) {
|
|
162
|
+
const dir = resolve(this._agentDir(defId), 'runs');
|
|
163
|
+
const p = resolve(dir, `${runId}.json`);
|
|
164
|
+
writeFileSync(p, JSON.stringify(data, null, 2));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
getRunLog(defId, runId) {
|
|
168
|
+
const p = resolve(this._agentDir(defId), 'runs', `${runId}.json`);
|
|
169
|
+
if (!existsSync(p)) return null;
|
|
170
|
+
return safeJsonParse(readFileSync(p, 'utf8'), null);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
listRuns(defId, { limit = 20 } = {}) {
|
|
174
|
+
const dir = resolve(this._agentDir(defId), 'runs');
|
|
175
|
+
if (!existsSync(dir)) return [];
|
|
176
|
+
const files = readdirSync(dir)
|
|
177
|
+
.filter(f => f.endsWith('.json'))
|
|
178
|
+
.map(f => {
|
|
179
|
+
const stat = statSync(resolve(dir, f));
|
|
180
|
+
return { runId: f.replace('.json', ''), mtime: stat.mtimeMs };
|
|
181
|
+
})
|
|
182
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
183
|
+
.slice(0, limit);
|
|
184
|
+
return files.map(f => {
|
|
185
|
+
const data = safeJsonParse(readFileSync(resolve(dir, `${f.runId}.json`), 'utf8'), {});
|
|
186
|
+
return { runId: f.runId, ...data };
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// --- Cleanup ---
|
|
191
|
+
|
|
192
|
+
deleteAll(defId) {
|
|
193
|
+
const dir = resolve(this.baseDir, defId);
|
|
194
|
+
if (existsSync(dir)) {
|
|
195
|
+
rmSync(dir, { recursive: true, force: true });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -47,6 +47,8 @@ import { RepoImporter } from './repo-import.js';
|
|
|
47
47
|
import { ConversationManager } from './conversations.js';
|
|
48
48
|
import { Toys } from './toys.js';
|
|
49
49
|
import { InnerChat } from './innerchat.js';
|
|
50
|
+
import { AutoState } from './autostate.js';
|
|
51
|
+
import { Orchestrator } from './orchestrator.js';
|
|
50
52
|
import { TrajectoryCapture, ConsentManager } from '../../../moe-training/client/index.js';
|
|
51
53
|
import { isFirstRun, runFirstTimeSetup, loadConfig, saveConfig, printWelcome } from './firstrun.js';
|
|
52
54
|
import { bindDaemon as bindGrooveNetworkDaemon } from './providers/groove-network.js';
|
|
@@ -160,6 +162,8 @@ export class Daemon {
|
|
|
160
162
|
this.modelLab = new ModelLab(this);
|
|
161
163
|
this.toys = new Toys(this);
|
|
162
164
|
this.innerchat = new InnerChat(this);
|
|
165
|
+
this.autoState = new AutoState(this.grooveDir);
|
|
166
|
+
this.orchestrator = new Orchestrator(this);
|
|
163
167
|
this.trajectoryCapture = null;
|
|
164
168
|
|
|
165
169
|
// Hook teams.delete to clean up agent-loop session files
|
|
@@ -613,6 +617,7 @@ export class Daemon {
|
|
|
613
617
|
this.journalist.start();
|
|
614
618
|
this.rotator.start();
|
|
615
619
|
this.scheduler.start();
|
|
620
|
+
this.orchestrator.start();
|
|
616
621
|
this.timeline.start();
|
|
617
622
|
this.gateways.start();
|
|
618
623
|
this.federation.initialize();
|
|
@@ -837,6 +842,7 @@ export class Daemon {
|
|
|
837
842
|
this.journalist.stop();
|
|
838
843
|
this.rotator.stop();
|
|
839
844
|
this.scheduler.stop();
|
|
845
|
+
this.orchestrator.stop();
|
|
840
846
|
this.timeline.stop();
|
|
841
847
|
if (this._gcInterval) clearInterval(this._gcInterval);
|
|
842
848
|
if (this._stateSaveInterval) clearInterval(this._stateSaveInterval);
|