copperhead 0.3.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/LICENSE +201 -0
- package/README.md +87 -0
- package/dist/agent/filetools.js +118 -0
- package/dist/agent/filetools.js.map +1 -0
- package/dist/agent/ledger.js +43 -0
- package/dist/agent/ledger.js.map +1 -0
- package/dist/agent/loop.js +279 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/prompts.js +47 -0
- package/dist/agent/prompts.js.map +1 -0
- package/dist/agent/providers/anthropic.js +78 -0
- package/dist/agent/providers/anthropic.js.map +1 -0
- package/dist/agent/providers/openai.js +74 -0
- package/dist/agent/providers/openai.js.map +1 -0
- package/dist/agent/tools.js +439 -0
- package/dist/agent/tools.js.map +1 -0
- package/dist/agent/transcript.js +60 -0
- package/dist/agent/transcript.js.map +1 -0
- package/dist/agent/types.js +2 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli.js +185 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/check.js +64 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/create.js +91 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/sync.js +144 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/kicad/cli.js +91 -0
- package/dist/kicad/cli.js.map +1 -0
- package/dist/kicad/report.js +48 -0
- package/dist/kicad/report.js.map +1 -0
- package/dist/kicad/sexp.js +291 -0
- package/dist/kicad/sexp.js.map +1 -0
- package/dist/memory/constraints.js +43 -0
- package/dist/memory/constraints.js.map +1 -0
- package/dist/memory/drift.js +81 -0
- package/dist/memory/drift.js.map +1 -0
- package/dist/memory/scaffold.js +215 -0
- package/dist/memory/scaffold.js.map +1 -0
- package/dist/openspec/cli.js +31 -0
- package/dist/openspec/cli.js.map +1 -0
- package/dist/util/env.js +68 -0
- package/dist/util/env.js.map +1 -0
- package/dist/util/git.js +53 -0
- package/dist/util/git.js.map +1 -0
- package/dist/util/paths.js +25 -0
- package/dist/util/paths.js.map +1 -0
- package/dist/util/redact.js +21 -0
- package/dist/util/redact.js.map +1 -0
- package/dist/util/retry.js +27 -0
- package/dist/util/retry.js.map +1 -0
- package/package.json +73 -0
- package/src/agent/filetools.ts +136 -0
- package/src/agent/ledger.ts +71 -0
- package/src/agent/loop.ts +320 -0
- package/src/agent/prompts.ts +58 -0
- package/src/agent/providers/anthropic.ts +81 -0
- package/src/agent/providers/openai.ts +80 -0
- package/src/agent/tools.ts +481 -0
- package/src/agent/transcript.ts +78 -0
- package/src/agent/types.ts +32 -0
- package/src/cli.ts +188 -0
- package/src/commands/check.ts +85 -0
- package/src/commands/create.ts +125 -0
- package/src/commands/sync.ts +182 -0
- package/src/config.ts +77 -0
- package/src/kicad/cli.ts +106 -0
- package/src/kicad/report.ts +81 -0
- package/src/kicad/sexp.ts +327 -0
- package/src/memory/constraints.ts +73 -0
- package/src/memory/drift.ts +97 -0
- package/src/memory/scaffold.ts +241 -0
- package/src/openspec/cli.ts +43 -0
- package/src/util/env.ts +65 -0
- package/src/util/git.ts +63 -0
- package/src/util/paths.ts +25 -0
- package/src/util/redact.ts +20 -0
- package/src/util/retry.ts +33 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { execa } from 'execa';
|
|
4
|
+
import { availableTools, dispatchTool } from './tools.js';
|
|
5
|
+
import { buildSystemPrompt } from './prompts.js';
|
|
6
|
+
import { loadConstraints } from '../memory/constraints.js';
|
|
7
|
+
import { loadConfig } from '../config.js';
|
|
8
|
+
import { Transcript } from './transcript.js';
|
|
9
|
+
import { ObligationsLedger } from './ledger.js';
|
|
10
|
+
import { isDirty, isGitRepo, snapshot, restore, commitAll, changedFiles } from '../util/git.js';
|
|
11
|
+
import { withRetry, isRateLimit } from '../util/retry.js';
|
|
12
|
+
import { openspecArchive } from '../openspec/cli.js';
|
|
13
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import { OpenAIProvider } from './providers/openai.js';
|
|
15
|
+
import { AnthropicProvider } from './providers/anthropic.js';
|
|
16
|
+
export function makeProvider(model) {
|
|
17
|
+
if (model === 'claude' || model.startsWith('claude')) {
|
|
18
|
+
return new AnthropicProvider(model === 'claude' ? undefined : model);
|
|
19
|
+
}
|
|
20
|
+
return new OpenAIProvider(model === 'gpt-5' ? undefined : model);
|
|
21
|
+
}
|
|
22
|
+
function otherProvider(current) {
|
|
23
|
+
if (current.name === 'openai' && process.env.ANTHROPIC_API_KEY)
|
|
24
|
+
return new AnthropicProvider();
|
|
25
|
+
if (current.name === 'anthropic' && process.env.OPENAI_API_KEY)
|
|
26
|
+
return new OpenAIProvider();
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
async function appendChangelog(repoRoot, config, entry) {
|
|
30
|
+
const p = path.join(repoRoot, config.docs, 'CHANGELOG.md');
|
|
31
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
32
|
+
const block = [
|
|
33
|
+
``,
|
|
34
|
+
`## ${date} — ${entry.request}`,
|
|
35
|
+
``,
|
|
36
|
+
`- Change: ${entry.changeId ?? 'n/a'}`,
|
|
37
|
+
`- Files: ${entry.files.join(', ') || '(none)'}`,
|
|
38
|
+
`- Verification: ${entry.verification}`,
|
|
39
|
+
].join('\n');
|
|
40
|
+
let text;
|
|
41
|
+
try {
|
|
42
|
+
text = await readFile(p, 'utf8');
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
text = '# Design changelog\n\nAppend-only, newest first. One entry per committed copperhead run.\n';
|
|
46
|
+
}
|
|
47
|
+
// newest first: insert right after the header block (first blank line after content start)
|
|
48
|
+
const lines = text.split('\n');
|
|
49
|
+
let insertAt = lines.length;
|
|
50
|
+
for (let i = 0; i < lines.length; i++) {
|
|
51
|
+
if (lines[i].startsWith('## ')) {
|
|
52
|
+
insertAt = i;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
lines.splice(insertAt, 0, ...block.split('\n').slice(1), '');
|
|
57
|
+
await writeFile(p, lines.join('\n'), 'utf8');
|
|
58
|
+
}
|
|
59
|
+
export async function runAgentLoop(opts) {
|
|
60
|
+
const log = opts.log ?? ((l) => console.log(l));
|
|
61
|
+
const repoRoot = opts.repoRoot;
|
|
62
|
+
const config = await loadConfig(repoRoot);
|
|
63
|
+
const maxTurns = opts.maxTurns ?? config.maxTurns;
|
|
64
|
+
if (!(await isGitRepo(repoRoot))) {
|
|
65
|
+
throw new Error('not a git repository; copperhead requires git for snapshots and rollback');
|
|
66
|
+
}
|
|
67
|
+
if ((await isDirty(repoRoot)) && !opts.allowDirty) {
|
|
68
|
+
throw new Error('working tree is dirty; commit your changes or pass --allow-dirty (snapshots via git stash create)');
|
|
69
|
+
}
|
|
70
|
+
const snap = await snapshot(repoRoot);
|
|
71
|
+
const transcript = new Transcript(repoRoot);
|
|
72
|
+
await transcript.init();
|
|
73
|
+
const ctx = {
|
|
74
|
+
repoRoot,
|
|
75
|
+
config,
|
|
76
|
+
transcript,
|
|
77
|
+
ledger: new ObligationsLedger(),
|
|
78
|
+
runId: path.basename(transcript.dir),
|
|
79
|
+
interactive: opts.interactive ?? false,
|
|
80
|
+
confirm: opts.confirm ?? (async () => true),
|
|
81
|
+
editsUnlocked: false,
|
|
82
|
+
changeId: null,
|
|
83
|
+
proposalValidated: false,
|
|
84
|
+
filesTouched: new Set(),
|
|
85
|
+
decisions: [],
|
|
86
|
+
lastErc: null,
|
|
87
|
+
lastDrc: null,
|
|
88
|
+
repairCycles: 0,
|
|
89
|
+
finishRequest: null,
|
|
90
|
+
};
|
|
91
|
+
let provider = makeProvider(opts.model);
|
|
92
|
+
const constraints = await loadConstraints(repoRoot);
|
|
93
|
+
const system = await buildSystemPrompt(repoRoot, config, constraints);
|
|
94
|
+
const messages = [
|
|
95
|
+
{ role: 'system', content: system },
|
|
96
|
+
{ role: 'user', content: opts.stagePrompt ? `${opts.stagePrompt}\n\nRequest: ${opts.request}` : opts.request },
|
|
97
|
+
];
|
|
98
|
+
await transcript.event('run-start', { request: opts.request, model: opts.model, provider: provider.name });
|
|
99
|
+
let tokensIn = 0;
|
|
100
|
+
let tokensOut = 0;
|
|
101
|
+
let plan = null;
|
|
102
|
+
let nudges = 0;
|
|
103
|
+
const fail = async (reason) => {
|
|
104
|
+
await transcript.event('run-failed', { reason });
|
|
105
|
+
await restore(repoRoot, snap);
|
|
106
|
+
const summaryPath = await transcript.writeSummary({
|
|
107
|
+
request: opts.request,
|
|
108
|
+
changeId: ctx.changeId,
|
|
109
|
+
plan,
|
|
110
|
+
filesTouched: [...ctx.filesTouched],
|
|
111
|
+
ercResult: ctx.lastErc ? (ctx.lastErc.ok ? 'clean' : `${ctx.lastErc.violations.length} violations`) : null,
|
|
112
|
+
drcResult: ctx.lastDrc ? (ctx.lastDrc.ok ? 'clean' : `${ctx.lastDrc.violations.length} violations`) : null,
|
|
113
|
+
decisions: ctx.decisions,
|
|
114
|
+
tokensIn,
|
|
115
|
+
tokensOut,
|
|
116
|
+
outcome: 'failure',
|
|
117
|
+
openObligations: ctx.ledger.isClear ? null : ctx.ledger.describe(),
|
|
118
|
+
detail: reason,
|
|
119
|
+
});
|
|
120
|
+
log(`run failed: ${reason}`);
|
|
121
|
+
log(`working tree restored to pre-run snapshot`);
|
|
122
|
+
log(`transcript: ${transcript.jsonlPath}`);
|
|
123
|
+
log(`summary: ${summaryPath}`);
|
|
124
|
+
return {
|
|
125
|
+
outcome: 'failure',
|
|
126
|
+
summary: reason,
|
|
127
|
+
transcriptDir: transcript.dir,
|
|
128
|
+
filesTouched: [],
|
|
129
|
+
commit: null,
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
for (let turn = 0; turn < maxTurns; turn++) {
|
|
133
|
+
const tools = availableTools(ctx).map((t) => t.schema);
|
|
134
|
+
let res;
|
|
135
|
+
try {
|
|
136
|
+
res = await withRetry(() => provider.chat(messages, tools), {
|
|
137
|
+
onRetry: (attempt) => log(`rate limited; retry ${attempt}`),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
if (isRateLimit(err)) {
|
|
142
|
+
const fallback = otherProvider(provider);
|
|
143
|
+
if (fallback) {
|
|
144
|
+
log(`failing over ${provider.name} → ${fallback.name}`);
|
|
145
|
+
await transcript.event('provider-failover', { from: provider.name, to: fallback.name });
|
|
146
|
+
provider = fallback;
|
|
147
|
+
turn--;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return fail(`provider error: ${err.message}`);
|
|
152
|
+
}
|
|
153
|
+
tokensIn += res.usage.inputTokens;
|
|
154
|
+
tokensOut += res.usage.outputTokens;
|
|
155
|
+
await transcript.event('assistant', { text: res.text, toolCalls: res.toolCalls });
|
|
156
|
+
if (res.text) {
|
|
157
|
+
if (!plan)
|
|
158
|
+
plan = res.text;
|
|
159
|
+
log(res.text);
|
|
160
|
+
}
|
|
161
|
+
messages.push({ role: 'assistant', content: res.text, toolCalls: res.toolCalls });
|
|
162
|
+
if (!res.toolCalls.length) {
|
|
163
|
+
if (nudges++ >= 2)
|
|
164
|
+
return fail('model stopped calling tools without finishing');
|
|
165
|
+
messages.push({
|
|
166
|
+
role: 'user',
|
|
167
|
+
content: 'Continue using tools, or call finish({outcome, summary}) to end the run.',
|
|
168
|
+
});
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
for (const call of res.toolCalls) {
|
|
172
|
+
const result = await dispatchTool(ctx, call.name, call.args);
|
|
173
|
+
await transcript.event('tool', { name: call.name, args: call.args, result });
|
|
174
|
+
log(` [${call.name}] ${result.split('\n')[0]}`);
|
|
175
|
+
messages.push({ role: 'tool', toolCallId: call.id, content: result });
|
|
176
|
+
}
|
|
177
|
+
if (ctx.repairCycles > config.maxRepairCycles) {
|
|
178
|
+
return fail(`repair cycles exhausted (${config.maxRepairCycles}); violations persist`);
|
|
179
|
+
}
|
|
180
|
+
const remaining = maxTurns - turn - 1;
|
|
181
|
+
if (remaining === 5 && !ctx.finishRequest) {
|
|
182
|
+
messages.push({
|
|
183
|
+
role: 'user',
|
|
184
|
+
content: 'Only 5 turns remain. Converge now: finish the minimal correct edit set, run run_erc (and run_drc if the board changed), run check_drift, then call finish.',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (ctx.finishRequest) {
|
|
188
|
+
const { outcome, summary } = ctx.finishRequest;
|
|
189
|
+
const files = [...ctx.filesTouched];
|
|
190
|
+
if (outcome === 'refuse') {
|
|
191
|
+
await restore(repoRoot, snap);
|
|
192
|
+
await transcript.event('run-refused', { summary });
|
|
193
|
+
await transcript.writeSummary({
|
|
194
|
+
request: opts.request,
|
|
195
|
+
changeId: ctx.changeId,
|
|
196
|
+
plan,
|
|
197
|
+
filesTouched: [],
|
|
198
|
+
ercResult: null,
|
|
199
|
+
drcResult: null,
|
|
200
|
+
decisions: ctx.decisions,
|
|
201
|
+
tokensIn,
|
|
202
|
+
tokensOut,
|
|
203
|
+
outcome: 'aborted',
|
|
204
|
+
openObligations: null,
|
|
205
|
+
detail: `REFUSED: ${summary}`,
|
|
206
|
+
});
|
|
207
|
+
log(`refused: ${summary}`);
|
|
208
|
+
return { outcome: 'refused', summary, transcriptDir: transcript.dir, filesTouched: [], commit: null };
|
|
209
|
+
}
|
|
210
|
+
const verification = [
|
|
211
|
+
ctx.lastErc ? `ERC ${ctx.lastErc.ok ? 'clean' : 'FAILING'}` : 'ERC not required',
|
|
212
|
+
ctx.lastDrc ? `DRC ${ctx.lastDrc.ok ? 'clean' : 'FAILING'}` : null,
|
|
213
|
+
]
|
|
214
|
+
.filter(Boolean)
|
|
215
|
+
.join(', ');
|
|
216
|
+
if (opts.dryRun) {
|
|
217
|
+
const { stdout: diff } = await execa('git', ['diff'], { cwd: repoRoot });
|
|
218
|
+
const { stdout: untracked } = await execa('git', ['ls-files', '--others', '--exclude-standard'], {
|
|
219
|
+
cwd: repoRoot,
|
|
220
|
+
});
|
|
221
|
+
log('--- dry run: proposed diff ---');
|
|
222
|
+
log(diff || '(no diff)');
|
|
223
|
+
if (untracked)
|
|
224
|
+
log(`new files:\n${untracked}`);
|
|
225
|
+
await restore(repoRoot, snap);
|
|
226
|
+
await transcript.writeSummary({
|
|
227
|
+
request: opts.request,
|
|
228
|
+
changeId: ctx.changeId,
|
|
229
|
+
plan,
|
|
230
|
+
filesTouched: files,
|
|
231
|
+
ercResult: verification,
|
|
232
|
+
drcResult: null,
|
|
233
|
+
decisions: ctx.decisions,
|
|
234
|
+
tokensIn,
|
|
235
|
+
tokensOut,
|
|
236
|
+
outcome: 'success',
|
|
237
|
+
openObligations: null,
|
|
238
|
+
detail: 'dry run: changes reverted',
|
|
239
|
+
});
|
|
240
|
+
return { outcome: 'success', summary, transcriptDir: transcript.dir, filesTouched: files, commit: null };
|
|
241
|
+
}
|
|
242
|
+
await appendChangelog(repoRoot, config, {
|
|
243
|
+
changeId: ctx.changeId,
|
|
244
|
+
request: opts.request,
|
|
245
|
+
files,
|
|
246
|
+
verification,
|
|
247
|
+
});
|
|
248
|
+
ctx.ledger.clear('changelog');
|
|
249
|
+
const commitMsg = `copperhead: ${opts.request}\n\n${summary}\n\nVerification: ${verification}`;
|
|
250
|
+
const commit = await commitAll(repoRoot, commitMsg);
|
|
251
|
+
if (ctx.changeId && existsSync(path.join(repoRoot, 'openspec', 'config.yaml'))) {
|
|
252
|
+
const arch = await openspecArchive(repoRoot, ctx.changeId);
|
|
253
|
+
await transcript.event('openspec-archive', { changeId: ctx.changeId, ok: arch.ok });
|
|
254
|
+
if (arch.ok && (await isDirty(repoRoot))) {
|
|
255
|
+
await commitAll(repoRoot, `copperhead: archive change ${ctx.changeId}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
await transcript.event('run-committed', { commit, files });
|
|
259
|
+
await transcript.writeSummary({
|
|
260
|
+
request: opts.request,
|
|
261
|
+
changeId: ctx.changeId,
|
|
262
|
+
plan,
|
|
263
|
+
filesTouched: files,
|
|
264
|
+
ercResult: ctx.lastErc ? (ctx.lastErc.ok ? 'clean' : 'FAILING') : 'not run',
|
|
265
|
+
drcResult: ctx.lastDrc ? (ctx.lastDrc.ok ? 'clean' : 'FAILING') : 'not run',
|
|
266
|
+
decisions: ctx.decisions,
|
|
267
|
+
tokensIn,
|
|
268
|
+
tokensOut,
|
|
269
|
+
outcome: 'success',
|
|
270
|
+
openObligations: null,
|
|
271
|
+
});
|
|
272
|
+
log(`committed ${commit.slice(0, 10)} (${files.length} file(s))`);
|
|
273
|
+
return { outcome: 'success', summary, transcriptDir: transcript.dir, filesTouched: files, commit };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const filesAfter = await changedFiles(repoRoot, snap.head);
|
|
277
|
+
return fail(`turn budget exhausted (${maxTurns} turns, ${filesAfter.length} files touched but unverified)`);
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/** SPEC §4.3 — verbatim requirements. */
|
|
5
|
+
const SYSTEM_RULES = `You are a hardware design agent working on real KiCad source files. Edit s-expressions surgically; never regenerate a whole file.
|
|
6
|
+
You cannot edit any file until your change proposal validates. Write the proposal first; the edit tools appear only after it passes.
|
|
7
|
+
The design docs are the memory. Read them before proposing anything; update them with everything you change.
|
|
8
|
+
Hold ALL constraints simultaneously: electrical budgets (e.g. sleep current), voltage ranges, package availability, strapping pins, RTC-capability, antenna keepouts. A part that satisfies the obvious constraint but violates a budget is a bug.
|
|
9
|
+
Check the MCU strapping table before assigning any pin. Check quiescent/leakage current of every part against the power budget in SPEC.md.
|
|
10
|
+
Nothing is done until ERC (and DRC when applicable) passes. Read the violation report; do not guess.
|
|
11
|
+
Write a one-line rationale next to every decision. If you remove a part, record why the absence is intentional (a missing pullup can look like a mistake).
|
|
12
|
+
If a request would violate a documented budget or constraint, stop and say so — do not silently comply.`;
|
|
13
|
+
const WORKFLOW = `Workflow for every run:
|
|
14
|
+
1. The design docs are already loaded below. Plan: state in one short block what will change, which files are affected, which constraints are at risk.
|
|
15
|
+
2. Call propose_change with a change id (kebab-case), why, what changes, and tasks. Then call validate_change. Edit tools (edit_file, write_file) unlock only after validation passes.
|
|
16
|
+
3. Make the edits. Use the exact same net names and refdes everywhere. For .kicad_sch/.kicad_pcb use edit_file with unique anchors from the actual file text (read the file first). For renaming a net or refdes across a file, one edit_file call with replace_all: true beats many small edits.
|
|
17
|
+
4. Run run_erc after schematic edits (and run_drc after board edits). If violations: read them, fix, re-run.
|
|
18
|
+
5. Run check_drift; update any doc that references a changed value/part/pin in the same run.
|
|
19
|
+
6. Record every non-trivial decision with record_decision, and every stated/assumed/discovered constraint with record_constraint.
|
|
20
|
+
7. Call finish with outcome "done" when everything is verified, or outcome "refuse" (citing the violated budget/constraint) if the request should not be done. finish will list any unmet obligations; resolve them and call it again.`;
|
|
21
|
+
export async function buildSystemPrompt(repoRoot, config, constraints) {
|
|
22
|
+
const parts = [SYSTEM_RULES, '', WORKFLOW];
|
|
23
|
+
if (Object.keys(config.budgets).length) {
|
|
24
|
+
parts.push('', '## Hard budgets (from .copperhead/config.json — treat as constraints)', '');
|
|
25
|
+
for (const [k, v] of Object.entries(config.budgets))
|
|
26
|
+
parts.push(`- ${k}: ${v}`);
|
|
27
|
+
}
|
|
28
|
+
if (Object.keys(constraints).length) {
|
|
29
|
+
parts.push('', '## Constraint registry (.copperhead/constraints.json)', '', '```json');
|
|
30
|
+
parts.push(JSON.stringify(constraints, null, 2), '```');
|
|
31
|
+
}
|
|
32
|
+
const docsDir = path.join(repoRoot, config.docs);
|
|
33
|
+
if (existsSync(docsDir)) {
|
|
34
|
+
const files = (await readdir(docsDir)).filter((f) => f.endsWith('.md')).sort();
|
|
35
|
+
for (const f of files) {
|
|
36
|
+
const text = await readFile(path.join(docsDir, f), 'utf8');
|
|
37
|
+
parts.push('', `## docs/${f}`, '', text);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (config.schematic) {
|
|
41
|
+
parts.push('', `## KiCad files`, '', `- schematic: ${config.schematic}`);
|
|
42
|
+
if (config.board)
|
|
43
|
+
parts.push(`- board: ${config.board}`);
|
|
44
|
+
}
|
|
45
|
+
return parts.join('\n');
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/agent/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,yCAAyC;AACzC,MAAM,YAAY,GAAG;;;;;;;wGAOmF,CAAC;AAEzG,MAAM,QAAQ,GAAG;;;;;;;uOAOsN,CAAC;AAExO,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB,EAChB,MAAwB,EACxB,WAA+B;IAE/B,MAAM,KAAK,GAAG,CAAC,YAAY,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IAE3C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,uEAAuE,EAAE,EAAE,CAAC,CAAC;QAC5F,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,uDAAuD,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;QACvF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/E,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YAC3D,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,gBAAgB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACzE,IAAI,MAAM,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export class AnthropicProvider {
|
|
2
|
+
model;
|
|
3
|
+
apiKey;
|
|
4
|
+
name = 'anthropic';
|
|
5
|
+
constructor(model = 'claude-sonnet-5', apiKey = process.env.ANTHROPIC_API_KEY) {
|
|
6
|
+
this.model = model;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
if (!this.apiKey)
|
|
9
|
+
throw new Error('ANTHROPIC_API_KEY is not set');
|
|
10
|
+
}
|
|
11
|
+
async chat(messages, tools, opts = {}) {
|
|
12
|
+
const { default: Anthropic } = await import('@anthropic-ai/sdk');
|
|
13
|
+
const client = new Anthropic({ apiKey: this.apiKey });
|
|
14
|
+
const system = messages
|
|
15
|
+
.filter((m) => m.role === 'system')
|
|
16
|
+
.map((m) => m.content)
|
|
17
|
+
.join('\n\n');
|
|
18
|
+
const conv = [];
|
|
19
|
+
for (const m of messages) {
|
|
20
|
+
if (m.role === 'system')
|
|
21
|
+
continue;
|
|
22
|
+
if (m.role === 'user') {
|
|
23
|
+
conv.push({ role: 'user', content: m.content });
|
|
24
|
+
}
|
|
25
|
+
else if (m.role === 'assistant') {
|
|
26
|
+
const content = [];
|
|
27
|
+
if (m.content)
|
|
28
|
+
content.push({ type: 'text', text: m.content });
|
|
29
|
+
for (const t of m.toolCalls ?? []) {
|
|
30
|
+
content.push({ type: 'tool_use', id: t.id, name: t.name, input: t.args });
|
|
31
|
+
}
|
|
32
|
+
if (content.length)
|
|
33
|
+
conv.push({ role: 'assistant', content });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// tool results are user-role content blocks in the Anthropic API
|
|
37
|
+
const prev = conv[conv.length - 1];
|
|
38
|
+
const block = { type: 'tool_result', tool_use_id: m.toolCallId, content: m.content };
|
|
39
|
+
if (prev && prev.role === 'user' && Array.isArray(prev.content)) {
|
|
40
|
+
prev.content.push(block);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
conv.push({ role: 'user', content: [block] });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const res = await client.messages.create({
|
|
48
|
+
model: this.model,
|
|
49
|
+
max_tokens: opts.maxTokens ?? 8192,
|
|
50
|
+
...(system ? { system } : {}),
|
|
51
|
+
messages: conv,
|
|
52
|
+
...(tools.length
|
|
53
|
+
? {
|
|
54
|
+
tools: tools.map((t) => ({
|
|
55
|
+
name: t.name,
|
|
56
|
+
description: t.description,
|
|
57
|
+
input_schema: t.parameters,
|
|
58
|
+
})),
|
|
59
|
+
}
|
|
60
|
+
: {}),
|
|
61
|
+
});
|
|
62
|
+
let text = null;
|
|
63
|
+
const toolCalls = [];
|
|
64
|
+
for (const block of res.content) {
|
|
65
|
+
if (block.type === 'text')
|
|
66
|
+
text = (text ?? '') + block.text;
|
|
67
|
+
if (block.type === 'tool_use') {
|
|
68
|
+
toolCalls.push({ id: block.id, name: block.name, args: block.input });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
text,
|
|
73
|
+
toolCalls,
|
|
74
|
+
usage: { inputTokens: res.usage.input_tokens, outputTokens: res.usage.output_tokens },
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/agent/providers/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export class OpenAIProvider {
|
|
2
|
+
model;
|
|
3
|
+
apiKey;
|
|
4
|
+
name = 'openai';
|
|
5
|
+
constructor(model = 'gpt-5', apiKey = process.env.OPENAI_API_KEY) {
|
|
6
|
+
this.model = model;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
if (!this.apiKey)
|
|
9
|
+
throw new Error('OPENAI_API_KEY is not set');
|
|
10
|
+
}
|
|
11
|
+
async chat(messages, tools, opts = {}) {
|
|
12
|
+
const { default: OpenAI } = await import('openai');
|
|
13
|
+
const client = new OpenAI({ apiKey: this.apiKey });
|
|
14
|
+
const res = await client.chat.completions.create({
|
|
15
|
+
model: this.model,
|
|
16
|
+
max_completion_tokens: opts.maxTokens ?? 8192,
|
|
17
|
+
messages: messages.map((m) => {
|
|
18
|
+
switch (m.role) {
|
|
19
|
+
case 'system':
|
|
20
|
+
return { role: 'system', content: m.content };
|
|
21
|
+
case 'user':
|
|
22
|
+
return { role: 'user', content: m.content };
|
|
23
|
+
case 'assistant':
|
|
24
|
+
return {
|
|
25
|
+
role: 'assistant',
|
|
26
|
+
content: m.content,
|
|
27
|
+
...(m.toolCalls?.length
|
|
28
|
+
? {
|
|
29
|
+
tool_calls: m.toolCalls.map((t) => ({
|
|
30
|
+
id: t.id,
|
|
31
|
+
type: 'function',
|
|
32
|
+
function: { name: t.name, arguments: JSON.stringify(t.args) },
|
|
33
|
+
})),
|
|
34
|
+
}
|
|
35
|
+
: {}),
|
|
36
|
+
};
|
|
37
|
+
case 'tool':
|
|
38
|
+
return { role: 'tool', tool_call_id: m.toolCallId, content: m.content };
|
|
39
|
+
}
|
|
40
|
+
}),
|
|
41
|
+
...(tools.length
|
|
42
|
+
? {
|
|
43
|
+
tools: tools.map((t) => ({
|
|
44
|
+
type: 'function',
|
|
45
|
+
function: { name: t.name, description: t.description, parameters: t.parameters },
|
|
46
|
+
})),
|
|
47
|
+
}
|
|
48
|
+
: {}),
|
|
49
|
+
});
|
|
50
|
+
const choice = res.choices[0];
|
|
51
|
+
const toolCalls = (choice?.message.tool_calls ?? []).map((t) => ({
|
|
52
|
+
id: t.id,
|
|
53
|
+
name: t.function.name,
|
|
54
|
+
args: safeParse(t.function.arguments),
|
|
55
|
+
}));
|
|
56
|
+
return {
|
|
57
|
+
text: choice?.message.content ?? null,
|
|
58
|
+
toolCalls,
|
|
59
|
+
usage: {
|
|
60
|
+
inputTokens: res.usage?.prompt_tokens ?? 0,
|
|
61
|
+
outputTokens: res.usage?.completion_tokens ?? 0,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function safeParse(s) {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(s);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return { _raw: s };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/agent/providers/openai.ts"],"names":[],"mappings":"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"}
|