pi-continuous-learning 0.5.1 → 0.7.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/README.md +78 -0
- package/dist/agents-md.d.ts +23 -2
- package/dist/agents-md.d.ts.map +1 -1
- package/dist/agents-md.js +58 -3
- package/dist/agents-md.js.map +1 -1
- package/dist/cli/analyze-single-shot.d.ts +62 -0
- package/dist/cli/analyze-single-shot.d.ts.map +1 -0
- package/dist/cli/analyze-single-shot.js +105 -0
- package/dist/cli/analyze-single-shot.js.map +1 -0
- package/dist/cli/analyze.js +82 -81
- package/dist/cli/analyze.js.map +1 -1
- package/dist/command-scaffold.d.ts +25 -0
- package/dist/command-scaffold.d.ts.map +1 -0
- package/dist/command-scaffold.js +77 -0
- package/dist/command-scaffold.js.map +1 -0
- package/dist/confidence.d.ts.map +1 -1
- package/dist/confidence.js +2 -1
- package/dist/confidence.js.map +1 -1
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -0
- package/dist/config.js.map +1 -1
- package/dist/graduation.d.ts +63 -0
- package/dist/graduation.d.ts.map +1 -0
- package/dist/graduation.js +155 -0
- package/dist/graduation.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/instinct-cleanup.d.ts +57 -0
- package/dist/instinct-cleanup.d.ts.map +1 -0
- package/dist/instinct-cleanup.js +150 -0
- package/dist/instinct-cleanup.js.map +1 -0
- package/dist/instinct-graduate.d.ts +43 -0
- package/dist/instinct-graduate.d.ts.map +1 -0
- package/dist/instinct-graduate.js +253 -0
- package/dist/instinct-graduate.js.map +1 -0
- package/dist/instinct-parser.d.ts.map +1 -1
- package/dist/instinct-parser.js +12 -0
- package/dist/instinct-parser.js.map +1 -1
- package/dist/instinct-tools.d.ts.map +1 -1
- package/dist/instinct-tools.js +19 -0
- package/dist/instinct-tools.js.map +1 -1
- package/dist/instinct-validator.d.ts +61 -0
- package/dist/instinct-validator.d.ts.map +1 -0
- package/dist/instinct-validator.js +235 -0
- package/dist/instinct-validator.js.map +1 -0
- package/dist/observation-preprocessor.d.ts +26 -0
- package/dist/observation-preprocessor.d.ts.map +1 -0
- package/dist/observation-preprocessor.js +31 -0
- package/dist/observation-preprocessor.js.map +1 -0
- package/dist/prompts/analyzer-system-single-shot.d.ts +6 -0
- package/dist/prompts/analyzer-system-single-shot.d.ts.map +1 -0
- package/dist/prompts/analyzer-system-single-shot.js +164 -0
- package/dist/prompts/analyzer-system-single-shot.js.map +1 -0
- package/dist/prompts/analyzer-user-single-shot.d.ts +22 -0
- package/dist/prompts/analyzer-user-single-shot.d.ts.map +1 -0
- package/dist/prompts/analyzer-user-single-shot.js +53 -0
- package/dist/prompts/analyzer-user-single-shot.js.map +1 -0
- package/dist/prompts/analyzer-user.d.ts +3 -1
- package/dist/prompts/analyzer-user.d.ts.map +1 -1
- package/dist/prompts/analyzer-user.js +20 -7
- package/dist/prompts/analyzer-user.js.map +1 -1
- package/dist/skill-scaffold.d.ts +23 -0
- package/dist/skill-scaffold.d.ts.map +1 -0
- package/dist/skill-scaffold.js +62 -0
- package/dist/skill-scaffold.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agents-md.ts +73 -3
- package/src/cli/analyze-single-shot.ts +175 -0
- package/src/cli/analyze.ts +93 -124
- package/src/command-scaffold.ts +105 -0
- package/src/confidence.ts +2 -1
- package/src/config.ts +40 -0
- package/src/graduation.ts +243 -0
- package/src/index.ts +14 -0
- package/src/instinct-cleanup.ts +204 -0
- package/src/instinct-graduate.ts +377 -0
- package/src/instinct-parser.ts +12 -0
- package/src/instinct-tools.ts +26 -0
- package/src/instinct-validator.ts +287 -0
- package/src/observation-preprocessor.ts +48 -0
- package/src/prompts/analyzer-system-single-shot.ts +163 -0
- package/src/prompts/analyzer-user-single-shot.ts +94 -0
- package/src/prompts/analyzer-user.ts +26 -8
- package/src/skill-scaffold.ts +90 -0
- package/src/types.ts +10 -0
package/src/cli/analyze.ts
CHANGED
|
@@ -7,36 +7,36 @@ import {
|
|
|
7
7
|
unlinkSync,
|
|
8
8
|
} from "node:fs";
|
|
9
9
|
import { join } from "node:path";
|
|
10
|
-
import {
|
|
11
|
-
createAgentSession,
|
|
12
|
-
SessionManager,
|
|
13
|
-
AuthStorage,
|
|
14
|
-
ModelRegistry,
|
|
15
|
-
DefaultResourceLoader,
|
|
16
|
-
} from "@mariozechner/pi-coding-agent";
|
|
10
|
+
import { AuthStorage } from "@mariozechner/pi-coding-agent";
|
|
17
11
|
import { getModel } from "@mariozechner/pi-ai";
|
|
18
12
|
|
|
19
13
|
import { loadConfig, DEFAULT_CONFIG } from "../config.js";
|
|
20
|
-
import type { ProjectEntry } from "../types.js";
|
|
14
|
+
import type { InstalledSkill, ProjectEntry } from "../types.js";
|
|
21
15
|
import {
|
|
22
16
|
getBaseDir,
|
|
23
17
|
getProjectsRegistryPath,
|
|
24
18
|
getObservationsPath,
|
|
25
19
|
getProjectDir,
|
|
20
|
+
getProjectInstinctsDir,
|
|
21
|
+
getGlobalInstinctsDir,
|
|
26
22
|
} from "../storage.js";
|
|
27
23
|
import { countObservations } from "../observations.js";
|
|
28
24
|
import { runDecayPass } from "../instinct-decay.js";
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
25
|
+
import { runCleanupPass } from "../instinct-cleanup.js";
|
|
26
|
+
import { tailObservationsSince } from "../prompts/analyzer-user.js";
|
|
27
|
+
import { buildSingleShotSystemPrompt } from "../prompts/analyzer-system-single-shot.js";
|
|
28
|
+
import { buildSingleShotUserPrompt } from "../prompts/analyzer-user-single-shot.js";
|
|
29
|
+
import {
|
|
30
|
+
runSingleShot,
|
|
31
|
+
buildInstinctFromChange,
|
|
32
|
+
} from "./analyze-single-shot.js";
|
|
31
33
|
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} from "../instinct-tools.js";
|
|
34
|
+
loadProjectInstincts,
|
|
35
|
+
loadGlobalInstincts,
|
|
36
|
+
saveInstinct,
|
|
37
|
+
} from "../instinct-store.js";
|
|
37
38
|
import { readAgentsMd } from "../agents-md.js";
|
|
38
39
|
import { homedir } from "node:os";
|
|
39
|
-
import type { InstalledSkill } from "../types.js";
|
|
40
40
|
import { AnalyzeLogger, type ProjectRunStats, type RunSummary } from "./analyze-logger.js";
|
|
41
41
|
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
@@ -59,7 +59,6 @@ function acquireLock(baseDir: string): boolean {
|
|
|
59
59
|
const lock = JSON.parse(content) as { pid: number; started_at: string };
|
|
60
60
|
const age = Date.now() - new Date(lock.started_at).getTime();
|
|
61
61
|
|
|
62
|
-
// Check if the owning process is still alive
|
|
63
62
|
try {
|
|
64
63
|
process.kill(lock.pid, 0); // signal 0 = existence check, no actual signal
|
|
65
64
|
if (age < LOCK_STALE_MS) {
|
|
@@ -104,72 +103,6 @@ function startGlobalTimeout(timeoutMs: number, logger: AnalyzeLogger): void {
|
|
|
104
103
|
}, timeoutMs).unref();
|
|
105
104
|
}
|
|
106
105
|
|
|
107
|
-
// ---------------------------------------------------------------------------
|
|
108
|
-
// Instinct operation tracking
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
|
|
111
|
-
interface InstinctOpCounts {
|
|
112
|
-
created: number;
|
|
113
|
-
updated: number;
|
|
114
|
-
deleted: number;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Wraps instinct tools to count create/update/delete operations.
|
|
119
|
-
* Returns new tool instances that increment the provided counts.
|
|
120
|
-
*/
|
|
121
|
-
function wrapInstinctToolsWithTracking(
|
|
122
|
-
projectId: string,
|
|
123
|
-
projectName: string,
|
|
124
|
-
baseDir: string,
|
|
125
|
-
counts: InstinctOpCounts
|
|
126
|
-
) {
|
|
127
|
-
const writeTool = createInstinctWriteTool(projectId, projectName, baseDir);
|
|
128
|
-
const deleteTool = createInstinctDeleteTool(projectId, baseDir);
|
|
129
|
-
|
|
130
|
-
const trackedWrite = {
|
|
131
|
-
...writeTool,
|
|
132
|
-
async execute(
|
|
133
|
-
toolCallId: string,
|
|
134
|
-
params: Parameters<typeof writeTool.execute>[1],
|
|
135
|
-
signal: AbortSignal | undefined,
|
|
136
|
-
onUpdate: unknown,
|
|
137
|
-
ctx: unknown
|
|
138
|
-
) {
|
|
139
|
-
const result = await writeTool.execute(toolCallId, params, signal, onUpdate, ctx);
|
|
140
|
-
const details = result.details as { action?: string } | undefined;
|
|
141
|
-
if (details?.action === "created") {
|
|
142
|
-
counts.created++;
|
|
143
|
-
} else {
|
|
144
|
-
counts.updated++;
|
|
145
|
-
}
|
|
146
|
-
return result;
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const trackedDelete = {
|
|
151
|
-
...deleteTool,
|
|
152
|
-
async execute(
|
|
153
|
-
toolCallId: string,
|
|
154
|
-
params: Parameters<typeof deleteTool.execute>[1],
|
|
155
|
-
signal: AbortSignal | undefined,
|
|
156
|
-
onUpdate: unknown,
|
|
157
|
-
ctx: unknown
|
|
158
|
-
) {
|
|
159
|
-
const result = await deleteTool.execute(toolCallId, params, signal, onUpdate, ctx);
|
|
160
|
-
counts.deleted++;
|
|
161
|
-
return result;
|
|
162
|
-
},
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
listTool: createInstinctListTool(projectId, baseDir),
|
|
167
|
-
readTool: createInstinctReadTool(projectId, baseDir),
|
|
168
|
-
writeTool: trackedWrite,
|
|
169
|
-
deleteTool: trackedDelete,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
106
|
// ---------------------------------------------------------------------------
|
|
174
107
|
// Per-project analysis
|
|
175
108
|
// ---------------------------------------------------------------------------
|
|
@@ -237,10 +170,13 @@ async function analyzeProject(
|
|
|
237
170
|
|
|
238
171
|
const obsPath = getObservationsPath(project.id, baseDir);
|
|
239
172
|
const sinceLineCount = meta.last_observation_line_count ?? 0;
|
|
240
|
-
const { lines: newObsLines, totalLineCount } = tailObservationsSince(
|
|
173
|
+
const { lines: newObsLines, totalLineCount, rawLineCount } = tailObservationsSince(
|
|
174
|
+
obsPath,
|
|
175
|
+
sinceLineCount
|
|
176
|
+
);
|
|
241
177
|
|
|
242
178
|
if (newObsLines.length === 0) {
|
|
243
|
-
return { ran: false, skippedReason: "no new observation lines" };
|
|
179
|
+
return { ran: false, skippedReason: "no new observation lines after preprocessing" };
|
|
244
180
|
}
|
|
245
181
|
|
|
246
182
|
const obsCount = countObservations(project.id, baseDir);
|
|
@@ -249,11 +185,15 @@ async function analyzeProject(
|
|
|
249
185
|
}
|
|
250
186
|
|
|
251
187
|
const startTime = Date.now();
|
|
252
|
-
logger.projectStart(project.id, project.name,
|
|
188
|
+
logger.projectStart(project.id, project.name, rawLineCount, obsCount);
|
|
253
189
|
|
|
190
|
+
runCleanupPass(project.id, config, baseDir);
|
|
254
191
|
runDecayPass(project.id, baseDir);
|
|
255
192
|
|
|
256
|
-
|
|
193
|
+
// Load current instincts inline - no tool calls needed
|
|
194
|
+
const projectInstincts = loadProjectInstincts(project.id, baseDir);
|
|
195
|
+
const globalInstincts = loadGlobalInstincts(baseDir);
|
|
196
|
+
const allInstincts = [...projectInstincts, ...globalInstincts];
|
|
257
197
|
|
|
258
198
|
const agentsMdProject = readAgentsMd(join(project.root, "AGENTS.md"));
|
|
259
199
|
const agentsMdGlobal = readAgentsMd(join(homedir(), ".pi", "agent", "AGENTS.md"));
|
|
@@ -270,68 +210,98 @@ async function analyzeProject(
|
|
|
270
210
|
// Skills loading is best-effort - continue without them
|
|
271
211
|
}
|
|
272
212
|
|
|
273
|
-
const userPrompt =
|
|
213
|
+
const userPrompt = buildSingleShotUserPrompt(project, allInstincts, newObsLines, {
|
|
274
214
|
agentsMdProject,
|
|
275
215
|
agentsMdGlobal,
|
|
276
216
|
installedSkills,
|
|
277
|
-
observationLines: newObsLines,
|
|
278
217
|
});
|
|
279
218
|
|
|
280
219
|
const authStorage = AuthStorage.create();
|
|
281
|
-
const modelRegistry = new ModelRegistry(authStorage);
|
|
282
220
|
const modelId = (config.model || DEFAULT_CONFIG.model) as Parameters<typeof getModel>[1];
|
|
283
221
|
const model = getModel("anthropic", modelId);
|
|
222
|
+
const apiKey = await authStorage.getApiKey("anthropic");
|
|
284
223
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
224
|
+
if (!apiKey) {
|
|
225
|
+
throw new Error("No Anthropic API key configured. Set via auth.json or ANTHROPIC_API_KEY.");
|
|
226
|
+
}
|
|
288
227
|
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
228
|
+
const context = {
|
|
229
|
+
systemPrompt: buildSingleShotSystemPrompt(),
|
|
230
|
+
messages: [
|
|
231
|
+
{ role: "user" as const, content: userPrompt, timestamp: Date.now() },
|
|
232
|
+
],
|
|
233
|
+
};
|
|
295
234
|
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
authStorage,
|
|
304
|
-
modelRegistry,
|
|
305
|
-
sessionManager: SessionManager.inMemory(),
|
|
306
|
-
customTools,
|
|
307
|
-
resourceLoader: loader,
|
|
308
|
-
});
|
|
235
|
+
const timeoutMs = (config.timeout_seconds ?? DEFAULT_CONFIG.timeout_seconds) * 1000;
|
|
236
|
+
const abortController = new AbortController();
|
|
237
|
+
const timeoutHandle = setTimeout(() => abortController.abort(), timeoutMs);
|
|
238
|
+
|
|
239
|
+
const instinctCounts = { created: 0, updated: 0, deleted: 0 };
|
|
240
|
+
const projectInstinctsDir = getProjectInstinctsDir(project.id, "personal", baseDir);
|
|
241
|
+
const globalInstinctsDir = getGlobalInstinctsDir("personal", baseDir);
|
|
309
242
|
|
|
243
|
+
let singleShotMessage;
|
|
310
244
|
try {
|
|
311
|
-
await
|
|
245
|
+
const result = await runSingleShot(context, model, apiKey, abortController.signal);
|
|
246
|
+
singleShotMessage = result.message;
|
|
247
|
+
|
|
248
|
+
// Enforce creation rate limit: only the first N create actions per run are applied.
|
|
249
|
+
const maxNewInstincts = config.max_new_instincts_per_run ?? DEFAULT_CONFIG.max_new_instincts_per_run;
|
|
250
|
+
let createsRemaining = maxNewInstincts;
|
|
251
|
+
|
|
252
|
+
for (const change of result.changes) {
|
|
253
|
+
if (change.action === "delete") {
|
|
254
|
+
const id = change.id;
|
|
255
|
+
if (!id) continue;
|
|
256
|
+
const dir = change.scope === "global" ? globalInstinctsDir : projectInstinctsDir;
|
|
257
|
+
const filePath = join(dir, `${id}.md`);
|
|
258
|
+
if (existsSync(filePath)) {
|
|
259
|
+
unlinkSync(filePath);
|
|
260
|
+
instinctCounts.deleted++;
|
|
261
|
+
}
|
|
262
|
+
} else if (change.action === "create") {
|
|
263
|
+
if (createsRemaining <= 0) continue; // rate limit reached
|
|
264
|
+
const existing = allInstincts.find((i) => i.id === change.instinct?.id) ?? null;
|
|
265
|
+
const instinct = buildInstinctFromChange(change, existing, project.id, allInstincts);
|
|
266
|
+
if (!instinct) continue;
|
|
267
|
+
|
|
268
|
+
const dir = instinct.scope === "global" ? globalInstinctsDir : projectInstinctsDir;
|
|
269
|
+
saveInstinct(instinct, dir);
|
|
270
|
+
instinctCounts.created++;
|
|
271
|
+
createsRemaining--;
|
|
272
|
+
} else {
|
|
273
|
+
// update
|
|
274
|
+
const existing = allInstincts.find((i) => i.id === change.instinct?.id) ?? null;
|
|
275
|
+
const instinct = buildInstinctFromChange(change, existing, project.id, allInstincts);
|
|
276
|
+
if (!instinct) continue;
|
|
277
|
+
|
|
278
|
+
const dir = instinct.scope === "global" ? globalInstinctsDir : projectInstinctsDir;
|
|
279
|
+
saveInstinct(instinct, dir);
|
|
280
|
+
instinctCounts.updated++;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
312
283
|
} finally {
|
|
313
|
-
|
|
284
|
+
clearTimeout(timeoutHandle);
|
|
314
285
|
}
|
|
315
286
|
|
|
316
|
-
|
|
317
|
-
const sessionStats = session.getSessionStats();
|
|
287
|
+
const usage = singleShotMessage!.usage;
|
|
318
288
|
const durationMs = Date.now() - startTime;
|
|
319
289
|
|
|
320
290
|
const stats: ProjectRunStats = {
|
|
321
291
|
project_id: project.id,
|
|
322
292
|
project_name: project.name,
|
|
323
293
|
duration_ms: durationMs,
|
|
324
|
-
observations_processed:
|
|
294
|
+
observations_processed: rawLineCount,
|
|
325
295
|
observations_total: obsCount,
|
|
326
296
|
instincts_created: instinctCounts.created,
|
|
327
297
|
instincts_updated: instinctCounts.updated,
|
|
328
298
|
instincts_deleted: instinctCounts.deleted,
|
|
329
|
-
tokens_input:
|
|
330
|
-
tokens_output:
|
|
331
|
-
tokens_cache_read:
|
|
332
|
-
tokens_cache_write:
|
|
333
|
-
tokens_total:
|
|
334
|
-
cost_usd:
|
|
299
|
+
tokens_input: usage.input,
|
|
300
|
+
tokens_output: usage.output,
|
|
301
|
+
tokens_cache_read: usage.cacheRead,
|
|
302
|
+
tokens_cache_write: usage.cacheWrite,
|
|
303
|
+
tokens_total: usage.totalTokens,
|
|
304
|
+
cost_usd: usage.cost.total,
|
|
335
305
|
model: modelId,
|
|
336
306
|
};
|
|
337
307
|
|
|
@@ -420,7 +390,6 @@ async function main(): Promise<void> {
|
|
|
420
390
|
|
|
421
391
|
main().catch((err) => {
|
|
422
392
|
releaseLock(getBaseDir());
|
|
423
|
-
// Last-resort logging - config may not have loaded
|
|
424
393
|
const logger = new AnalyzeLogger();
|
|
425
394
|
logger.error("Fatal error", err);
|
|
426
395
|
process.exit(1);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command scaffolding from instinct clusters.
|
|
3
|
+
*
|
|
4
|
+
* When 3+ related instincts in the same domain form an actionable workflow,
|
|
5
|
+
* generates a Pi slash command scaffold that codifies the pattern.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Instinct } from "./types.js";
|
|
9
|
+
import type { DomainCluster } from "./graduation.js";
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Types
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface CommandScaffold {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
domain: string;
|
|
19
|
+
content: string;
|
|
20
|
+
sourceInstinctIds: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Helpers
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
function toCommandName(domain: string): string {
|
|
28
|
+
return domain.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function formatInstinctAsStep(instinct: Instinct, index: number): string {
|
|
32
|
+
return [
|
|
33
|
+
`${index + 1}. **${instinct.title}**`,
|
|
34
|
+
` - Trigger: ${instinct.trigger}`,
|
|
35
|
+
` - Action: ${instinct.action}`,
|
|
36
|
+
"",
|
|
37
|
+
].join("\n");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Public API
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generates a command scaffold from a domain cluster of instincts.
|
|
46
|
+
* The scaffold describes a slash command that encodes the workflow
|
|
47
|
+
* distilled from the instinct cluster.
|
|
48
|
+
*/
|
|
49
|
+
export function generateCommandScaffold(cluster: DomainCluster): CommandScaffold {
|
|
50
|
+
const name = toCommandName(cluster.domain);
|
|
51
|
+
const sortedInstincts = [...cluster.instincts].sort(
|
|
52
|
+
(a, b) => b.confidence - a.confidence
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const description = `Learned ${cluster.domain} workflow from coding sessions. ` +
|
|
56
|
+
`Encodes ${sortedInstincts.length} steps distilled from instinct observations.`;
|
|
57
|
+
|
|
58
|
+
const steps = sortedInstincts.map((inst, i) => formatInstinctAsStep(inst, i));
|
|
59
|
+
|
|
60
|
+
const content = [
|
|
61
|
+
`# /${name} Command`,
|
|
62
|
+
"",
|
|
63
|
+
`> Auto-generated from ${sortedInstincts.length} graduated instincts in the "${cluster.domain}" domain.`,
|
|
64
|
+
"",
|
|
65
|
+
`## Description`,
|
|
66
|
+
"",
|
|
67
|
+
description,
|
|
68
|
+
"",
|
|
69
|
+
`## Command: \`/${name}\``,
|
|
70
|
+
"",
|
|
71
|
+
`When invoked, this command should guide the agent through these steps:`,
|
|
72
|
+
"",
|
|
73
|
+
...steps,
|
|
74
|
+
`## Implementation Notes`,
|
|
75
|
+
"",
|
|
76
|
+
`Register this command in your Pi extension's \`index.ts\`:`,
|
|
77
|
+
"",
|
|
78
|
+
"```typescript",
|
|
79
|
+
`pi.registerCommand("${name}", {`,
|
|
80
|
+
` description: "${description.replace(/"/g, '\\"')}",`,
|
|
81
|
+
` handler: async (args, ctx) => {`,
|
|
82
|
+
` // TODO: Implement ${name} workflow`,
|
|
83
|
+
` },`,
|
|
84
|
+
`});`,
|
|
85
|
+
"```",
|
|
86
|
+
"",
|
|
87
|
+
].join("\n");
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
name,
|
|
91
|
+
description,
|
|
92
|
+
domain: cluster.domain,
|
|
93
|
+
content,
|
|
94
|
+
sourceInstinctIds: sortedInstincts.map((i) => i.id),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Generates command scaffolds for all qualifying clusters.
|
|
100
|
+
*/
|
|
101
|
+
export function generateAllCommandScaffolds(
|
|
102
|
+
clusters: DomainCluster[]
|
|
103
|
+
): CommandScaffold[] {
|
|
104
|
+
return clusters.map(generateCommandScaffold);
|
|
105
|
+
}
|
package/src/confidence.ts
CHANGED
|
@@ -26,7 +26,8 @@ const DELTA_CONTRADICTED = -0.15;
|
|
|
26
26
|
const DELTA_INACTIVE = 0;
|
|
27
27
|
|
|
28
28
|
// applyPassiveDecay
|
|
29
|
-
|
|
29
|
+
// Increased from 0.02 to 0.05: at 0.5 confidence, reaches 0.1 in ~8 weeks instead of 20.
|
|
30
|
+
const DECAY_PER_WEEK = 0.05;
|
|
30
31
|
const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
|
|
31
32
|
|
|
32
33
|
// ---------------------------------------------------------------------------
|
package/src/config.ts
CHANGED
|
@@ -38,6 +38,34 @@ export const CONFIG_PATH = path.join(
|
|
|
38
38
|
"config.json"
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Graduation maturity criteria
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
/** Minimum age in days before an instinct is eligible for graduation. */
|
|
46
|
+
export const GRADUATION_MIN_AGE_DAYS = 7;
|
|
47
|
+
|
|
48
|
+
/** Minimum confidence to qualify for graduation. */
|
|
49
|
+
export const GRADUATION_MIN_CONFIDENCE = 0.75;
|
|
50
|
+
|
|
51
|
+
/** Minimum confirmed_count to qualify for graduation. */
|
|
52
|
+
export const GRADUATION_MIN_CONFIRMED = 3;
|
|
53
|
+
|
|
54
|
+
/** Maximum contradicted_count allowed for graduation. */
|
|
55
|
+
export const GRADUATION_MAX_CONTRADICTED = 1;
|
|
56
|
+
|
|
57
|
+
/** Minimum related instincts in same domain to propose a skill scaffold. */
|
|
58
|
+
export const GRADUATION_SKILL_CLUSTER_SIZE = 3;
|
|
59
|
+
|
|
60
|
+
/** Minimum related instincts in same domain to propose a command scaffold. */
|
|
61
|
+
export const GRADUATION_COMMAND_CLUSTER_SIZE = 3;
|
|
62
|
+
|
|
63
|
+
/** Maximum instinct age in days before TTL cull (aggressive decay / deletion). */
|
|
64
|
+
export const GRADUATION_TTL_MAX_DAYS = 28;
|
|
65
|
+
|
|
66
|
+
/** Confidence threshold below which TTL-expired instincts are deleted outright. */
|
|
67
|
+
export const GRADUATION_TTL_CULL_CONFIDENCE = 0.3;
|
|
68
|
+
|
|
41
69
|
export const DEFAULT_CONFIG: Config = {
|
|
42
70
|
run_interval_minutes: 5,
|
|
43
71
|
min_observations_to_analyze: 20,
|
|
@@ -49,6 +77,12 @@ export const DEFAULT_CONFIG: Config = {
|
|
|
49
77
|
active_hours_start: 8,
|
|
50
78
|
active_hours_end: 23,
|
|
51
79
|
max_idle_seconds: 1800,
|
|
80
|
+
// Volume control defaults
|
|
81
|
+
max_total_instincts_per_project: 30,
|
|
82
|
+
max_total_instincts_global: 20,
|
|
83
|
+
max_new_instincts_per_run: 3,
|
|
84
|
+
flagged_cleanup_days: 7,
|
|
85
|
+
instinct_ttl_days: 28,
|
|
52
86
|
};
|
|
53
87
|
|
|
54
88
|
// ---------------------------------------------------------------------------
|
|
@@ -68,6 +102,12 @@ const PartialConfigSchema = Type.Partial(
|
|
|
68
102
|
active_hours_end: Type.Number(),
|
|
69
103
|
max_idle_seconds: Type.Number(),
|
|
70
104
|
log_path: Type.String(),
|
|
105
|
+
// Volume control
|
|
106
|
+
max_total_instincts_per_project: Type.Number(),
|
|
107
|
+
max_total_instincts_global: Type.Number(),
|
|
108
|
+
max_new_instincts_per_run: Type.Number(),
|
|
109
|
+
flagged_cleanup_days: Type.Number(),
|
|
110
|
+
instinct_ttl_days: Type.Number(),
|
|
71
111
|
})
|
|
72
112
|
);
|
|
73
113
|
|