@piagent/platform 1.35.1 → 1.36.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/CHANGELOG.md +17 -0
- package/README.md +1 -1
- package/README.vi.md +1 -1
- package/docs/command-reference-vietnamese.md +2 -2
- package/docs/distribution-standard.md +6 -6
- package/docs/languages.json +2 -2
- package/docs/operator-manual-vietnamese.md +7 -7
- package/docs/publishing-for-teams.md +1 -0
- package/docs/release-install-policy.md +2 -2
- package/docs/team-onboarding.md +2 -2
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/content/en/index.html +4 -4
- package/docs-site/content/en/whats-new.html +6 -0
- package/docs-site/content/index.html +4 -4
- package/docs-site/content/whats-new.html +6 -0
- package/docs-site/context-engine.html +1 -1
- package/docs-site/ecosystem.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +1 -1
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/ecosystem.html +1 -1
- package/docs-site/en/index.html +5 -5
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +1 -1
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/whats-new.html +7 -1
- package/docs-site/en/windows.html +1 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +5 -5
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +1 -1
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/whats-new.html +7 -1
- package/docs-site/windows.html +1 -1
- package/docs-site/workflows.html +1 -1
- package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
- package/package.json +1 -1
- package/packages/piagent-core/extensions/repository-memory.js +27 -2
- package/packages/piagent-core/managed/memory-lessons.mjs +34 -6
- package/packages/piagent-core/managed/memory-serves.mjs +17 -0
- package/packages/piagent-core/managed/memory.mjs +12 -10
- package/packages/piagent-core/managed/skill-feedback.mjs +79 -0
- package/packages/piagent-core/package.json +1 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Skill feedback (after Cognee's proposal-first skill improvement): which
|
|
2
|
+
// skills a round used, and whether the round ended badly (its last check
|
|
3
|
+
// failed, or a command failed the same way twice). A skill that keeps ending
|
|
4
|
+
// badly gets a proposal file to review under .pi/piagent-state/skill-proposals;
|
|
5
|
+
// Piagent never edits a skill itself and makes no model call for this.
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
const MIN_FAILURES = 3, MIN_SHARE = 0.5, KEEP = 10, REPROPOSE_MS = 7 * 86400_000;
|
|
10
|
+
const safeName = name => String(name).replace(/[^A-Za-z0-9_.-]/g, '_').slice(0, 80);
|
|
11
|
+
|
|
12
|
+
export class SkillFeedback {
|
|
13
|
+
// A managed round's tracker, when the conversation has skills.
|
|
14
|
+
static forRound(self, text) {
|
|
15
|
+
if (!self.resources?.skills?.length) return null;
|
|
16
|
+
const feedback = new SkillFeedback({ cwd: self.cwd, skills: self.resources.skills });
|
|
17
|
+
feedback.request(text);
|
|
18
|
+
return feedback;
|
|
19
|
+
}
|
|
20
|
+
constructor({ cwd, skills = [], now = Date.now }) {
|
|
21
|
+
this.cwd = cwd; this.now = now; this.used = new Set();
|
|
22
|
+
this.skills = skills.filter(s => s?.name && s?.filePath).map(s => ({ name: s.name, file: path.resolve(s.filePath) }));
|
|
23
|
+
}
|
|
24
|
+
// A member's /skill:name arrives expanded as a <skill name="..."> block.
|
|
25
|
+
request(text) {
|
|
26
|
+
for (const m of String(text ?? '').matchAll(/<skill name="([^"]{1,80})"/g)) if (this.skills.some(s => s.name === m[1])) this.used.add(m[1]);
|
|
27
|
+
}
|
|
28
|
+
// The model reading a skill's SKILL.md is the skill being used.
|
|
29
|
+
event(event) {
|
|
30
|
+
if (event?.type !== 'tool_execution_start' || event.toolName !== 'read' || typeof event.args?.path !== 'string') return;
|
|
31
|
+
const file = path.resolve(this.cwd, event.args.path);
|
|
32
|
+
for (const s of this.skills) if (s.file === file) this.used.add(s.name);
|
|
33
|
+
}
|
|
34
|
+
// The round's end: counts for every skill it used; returns the proposals written.
|
|
35
|
+
close({ checks = 'none', lessons = [] } = {}) {
|
|
36
|
+
if (!this.used.size || !this.cwd) return [];
|
|
37
|
+
const errors = lessons.filter(l => l.kind === 'tool_error');
|
|
38
|
+
const bad = checks === 'failed' || errors.length > 0;
|
|
39
|
+
const written = [];
|
|
40
|
+
let dir;
|
|
41
|
+
// Inside the project's own state folder only: never through a link.
|
|
42
|
+
try {
|
|
43
|
+
const state = path.join(fs.realpathSync(this.cwd), '.pi', 'piagent-state');
|
|
44
|
+
dir = path.join(state, 'skill-proposals');
|
|
45
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
46
|
+
if (fs.realpathSync(dir) !== dir || fs.lstatSync(dir).isSymbolicLink()) return [];
|
|
47
|
+
} catch { return []; }
|
|
48
|
+
for (const name of this.used) {
|
|
49
|
+
const file = path.join(dir, `${safeName(name)}.json`);
|
|
50
|
+
let state = { name, uses: 0, failures: [], proposed_at: null };
|
|
51
|
+
try { state = { ...state, ...JSON.parse(fs.readFileSync(file, 'utf8')) }; } catch { /* first use */ }
|
|
52
|
+
state.uses++;
|
|
53
|
+
if (bad) {
|
|
54
|
+
const detail = checks === 'failed' ? 'the round\'s last check failed' : errors[0].line;
|
|
55
|
+
state.failures = [...state.failures, { at: new Date(this.now()).toISOString(), detail: String(detail).slice(0, 400) }].slice(-KEEP);
|
|
56
|
+
}
|
|
57
|
+
const recent = state.failures.length, share = recent / Math.min(state.uses, KEEP);
|
|
58
|
+
const due = recent >= MIN_FAILURES && share >= MIN_SHARE && (!state.proposed_at || this.now() - Date.parse(state.proposed_at) > REPROPOSE_MS);
|
|
59
|
+
if (due) {
|
|
60
|
+
state.proposed_at = new Date(this.now()).toISOString();
|
|
61
|
+
const skill = this.skills.find(s => s.name === name);
|
|
62
|
+
const proposal = path.join(dir, `${safeName(name)}.md`);
|
|
63
|
+
fs.writeFileSync(proposal, [
|
|
64
|
+
`# Review the skill "${name}"`, '',
|
|
65
|
+
`Proposed ${state.proposed_at} by Piagent. Nothing was changed: read the evidence, then edit the skill yourself or delete this file.`, '',
|
|
66
|
+
`Skill file: ${skill ? path.relative(this.cwd, skill.file) || skill.file : 'unknown'}`, '',
|
|
67
|
+
`${recent} of the last ${Math.min(state.uses, KEEP)} rounds that used it ended badly:`, '',
|
|
68
|
+
...state.failures.map(f => `- ${f.at}: ${f.detail}`), '',
|
|
69
|
+
'Look for: a step the skill tells the agent to run that no longer works here (a command, flag, path or check),',
|
|
70
|
+
'instructions that contradict the repository\'s current conventions, or a missing prerequisite.', ''].join('\n'), { mode: 0o600 });
|
|
71
|
+
written.push(proposal);
|
|
72
|
+
state.failures = [];
|
|
73
|
+
}
|
|
74
|
+
fs.writeFileSync(file, JSON.stringify(state, null, 1), { mode: 0o600 });
|
|
75
|
+
}
|
|
76
|
+
this.used.clear();
|
|
77
|
+
return written;
|
|
78
|
+
}
|
|
79
|
+
}
|