ec-sim-mcp 0.1.0 → 0.2.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 +41 -17
- package/package.json +1 -1
- package/src/server.mjs +1 -1
- package/src/tools.mjs +53 -34
package/README.md
CHANGED
|
@@ -48,17 +48,17 @@ in the dialog. A badge in the menu bar shows the link and has a Disconnect butto
|
|
|
48
48
|
| Tool | Purpose |
|
|
49
49
|
|---|---|
|
|
50
50
|
| `open_editor` | Link to a tab (opens the pairing link, waits for Connect) |
|
|
51
|
-
| `list_component_types` | Part types, pins, parameters with SI units and defaults |
|
|
51
|
+
| `list_component_types` | Part types, pins, pin positions and outline for each rotation, spacing rule, parameters with SI units and defaults |
|
|
52
52
|
| `list_parts` | The editor's parts library (diodes, BJTs, MOSFETs, JFETs, op-amps): categories, or one category's table in SI, with limits on any column (`where`), sorting, word search and paging |
|
|
53
53
|
| `list_examples`, `load_example` | Built-in circuits |
|
|
54
54
|
| `get_circuit` | The circuit as a netlist (works for hand-drawn circuits), ERC result, revision |
|
|
55
|
-
| `place_part` | Place one part without wires, at a
|
|
55
|
+
| `place_part` | Place one part without wires, at a grid point or next to a pin of another part, rotated or mirrored; the reply gives its pin positions |
|
|
56
56
|
| `draw_wire`, `remove_wire` | Draw one wire along a stated path (pins, points, corners); remove a wire or one of its segments |
|
|
57
57
|
| `place_symbol`, `remove_symbol` | Ground symbols and net labels at a stated point |
|
|
58
58
|
| `move_label` | Move a part's designator and value text, a probe's badge, or a net label / ground symbol |
|
|
59
|
-
| `get_drawing` | The drawing with positions: parts, pin coordinates and nets, symbols, wires with ids |
|
|
59
|
+
| `get_drawing` | The drawing with positions: parts, pin coordinates and nets, symbols, wires with ids, and the layout numbers |
|
|
60
60
|
| `set_circuit` | Replace the circuit from a structured netlist or a SPICE deck; drawn and wired automatically |
|
|
61
|
-
| `edit_circuit` | Change values and parameters, swap in a library part, add and remove parts, move, turn or mirror a part, move a pin to another net (all or nothing) |
|
|
61
|
+
| `edit_circuit` | Change values and parameters, swap in a library part, add and remove parts, move, turn or mirror a part, move a pin to another net, rename a net and choose how its name is shown (all or nothing) |
|
|
62
62
|
| `set_probes` | Choose the signals in the waveform viewer |
|
|
63
63
|
| `set_design_notes` | Write the project's design notes (Edit > Design Notes in the editor); `get_circuit` returns them |
|
|
64
64
|
| `set_math_waveforms` | Named expressions drawn as traces in the viewer (`avg`, `rms`, `d/dt`, `integ`, arithmetic); the tool description carries the syntax |
|
|
@@ -109,10 +109,31 @@ time: `move_part` for a part in the wrong place or out of line, `remove_wire` an
|
|
|
109
109
|
a wire with a detour or a needless crossing, `move_label` for text in the way. You see the
|
|
110
110
|
circuit appear and then being cleaned up.
|
|
111
111
|
|
|
112
|
+
**Placement is by pins, on the 20 px grid.** The first part of a block gets `at: {x, y}` (its
|
|
113
|
+
centre in grid steps); every part around it gets `next_to: {pin, to, dx, dy}`, which puts one of
|
|
114
|
+
its pins a stated number of steps from a pin of another part. The editor works out the centre from
|
|
115
|
+
the rotation and the pin offsets, so the agent does no coordinate arithmetic and connected pins
|
|
116
|
+
end up exactly in line. `line_up` only straightens a part that already has a place.
|
|
117
|
+
|
|
118
|
+
- `list_component_types` gives, for every type and rotation, the pin offsets and the outline (the
|
|
119
|
+
body with its pins), where the text is written, and the spacing rule.
|
|
120
|
+
- A part that is too close is refused with the reason and the room both parts take. The check is
|
|
121
|
+
on what will be drawn: bodies need 1 free step between them; every connected pin gets a wire
|
|
122
|
+
2 steps straight out (a ground pin also its symbol), which needs 2 free steps to other parts and
|
|
123
|
+
1 to the lead-out wires of other nets. A part placed bare with `place_part` only needs the step
|
|
124
|
+
between bodies, since the agent draws its wires itself.
|
|
125
|
+
- Every reply that draws (`set_circuit`, `edit_circuit`, `get_drawing`) carries `layout`: size of
|
|
126
|
+
the drawing in grid steps, area and wire length per part, crossings, net labels, texts that lie
|
|
127
|
+
on another part, and the values to aim for (about 80 to 150 square steps per part).
|
|
128
|
+
- A whole-drawing screenshot that would be too small to read says so in `note` and points to
|
|
129
|
+
close-ups by block.
|
|
130
|
+
- `at: {col, row}` still names a cell of a coarse grid (16 x 12 steps), and a part given no place
|
|
131
|
+
goes to the next free cell. That is for a quick sketch: it is about three times too wide for a
|
|
132
|
+
finished drawing, which is why the instructions steer agents to pins and blocks.
|
|
133
|
+
|
|
112
134
|
The hand tools work like this:
|
|
113
135
|
|
|
114
|
-
- Positions are in grid steps of 20 px
|
|
115
|
-
cell (col, row) is centred at (10 + 16 col, 10 + 12 row).
|
|
136
|
+
- Positions are in grid steps of 20 px, x to the right and y downwards.
|
|
116
137
|
- A wire goes exactly where the agent says. Nothing is snapped: an off-grid point or a wire
|
|
117
138
|
through a part is refused. Two points that are not in line get one corner between them.
|
|
118
139
|
- Nothing is assumed about what a wire connects. The reply to `draw_wire` reports what the
|
|
@@ -129,8 +150,8 @@ The wording that steers the agent (workflow, layout and wire style) is `INSTRUCT
|
|
|
129
150
|
|
|
130
151
|
## How the automatic drawing works
|
|
131
152
|
|
|
132
|
-
Parts go
|
|
133
|
-
|
|
153
|
+
Parts go where the agent says (`at`, `next_to`, `rotation`); parts given no place go into free
|
|
154
|
+
cells of a 320 × 240 px grid below the placed ones, row by row in the order listed. Every connected pin is led out of its part
|
|
134
155
|
on a short stub. Then, per net (`web/src/agent/wireRouter.ts`):
|
|
135
156
|
|
|
136
157
|
- Pins are joined by orthogonal wires on the 20 px grid, nearest first, as short as the placement
|
|
@@ -143,8 +164,13 @@ on a short stub. Then, per net (`web/src/agent/wireRouter.ts`):
|
|
|
143
164
|
- A pin gets a **net label instead of a wire** only when no clear path exists within about
|
|
144
165
|
1800 px of wire (bends and crossings count extra). The reply to `set_circuit` / `edit_circuit`
|
|
145
166
|
then carries a `drawing` note naming those nets, so the agent can move parts closer.
|
|
146
|
-
- Each net
|
|
147
|
-
|
|
167
|
+
- Each net carries its name on its wires (what `V(name)` refers to), without showing it. The
|
|
168
|
+
agent chooses the names to show: `labels` in `set_circuit`, or the `name_net` operation of
|
|
169
|
+
`edit_circuit`, as text on a wire or as a net label. Ground pins get a ground symbol each.
|
|
170
|
+
- **Only names that are shown connect.** Nets that show the same name are one net; a name that
|
|
171
|
+
is not shown connects nothing. So where a pin has to be joined by a label, the rest of its net
|
|
172
|
+
gets a label too. Two separate nets that carry the same unshown name stay separate, and the
|
|
173
|
+
check warns about it.
|
|
148
174
|
- `add_part` puts the new part in the free cell nearest to the pins it connects to and wires it to
|
|
149
175
|
the existing net, including nets of a hand-drawn circuit that have no label.
|
|
150
176
|
- `remove_part` also removes the wires that were left leading nowhere.
|
|
@@ -164,13 +190,11 @@ instead and the reply says so.
|
|
|
164
190
|
## Limits
|
|
165
191
|
|
|
166
192
|
- Placement is the agent's job: there is no automatic placement. The server's instructions
|
|
167
|
-
(`LAYOUT` in `src/tools.mjs`) tell it
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
each rotation, and `line_up` (in `place_part`, `add_part` and `move_part`) shifts a part so one
|
|
173
|
-
of its pins is exactly in line with a pin of another part.
|
|
193
|
+
(`LAYOUT` in `src/tools.mjs`) tell it to work in functional blocks, place by pins, keep the
|
|
194
|
+
drawing about one and a half to two times as wide as it is high, check the layout numbers and
|
|
195
|
+
the screenshot, and fix with `move_part`.
|
|
196
|
+
- Text is not placed for the agent: a value can lie on a wire of its own part (a horizontal
|
|
197
|
+
capacitor), and `layout.text_overlaps` only reports text on other parts.
|
|
174
198
|
- `move_part` on a hand-wired part redraws that part's wires automatically.
|
|
175
199
|
- `list_parts` covers the built-in library only. Passives have no library entries.
|
|
176
200
|
- Design notes are not part of undo, and writing them does not change the circuit revision.
|
package/package.json
CHANGED
package/src/server.mjs
CHANGED
|
@@ -141,7 +141,7 @@ async function main() {
|
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
const server = new Server({ name: 'ec-sim', version: '0.
|
|
144
|
+
const server = new Server({ name: 'ec-sim', version: '0.2.0' }, { capabilities: { tools: {} }, instructions: INSTRUCTIONS });
|
|
145
145
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [...LOCAL_TOOLS, ...EDITOR_TOOLS] }));
|
|
146
146
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
147
147
|
const name = req.params.name;
|
package/src/tools.mjs
CHANGED
|
@@ -29,21 +29,27 @@ const PART = {
|
|
|
29
29
|
at: {
|
|
30
30
|
type: 'object',
|
|
31
31
|
description:
|
|
32
|
-
'Where
|
|
33
|
-
properties: { col: { type: 'integer', minimum: 0 }, row: { type: 'integer', minimum: 0 } },
|
|
34
|
-
|
|
32
|
+
'Where the centre of the part goes, in grid steps of 20 px: {"x": 30, "y": 20} (x to the right, y downwards). Use it for the first part of a block and place the parts around it with "next_to". {"col": 2, "row": 1} names a cell of a coarse layout grid instead (16 x 12 steps per cell): quick, but far too spread out for a finished drawing. Left out, with no "next_to": the next free cell.',
|
|
33
|
+
properties: { x: { type: 'integer', minimum: 0 }, y: { type: 'integer', minimum: 0 }, col: { type: 'integer', minimum: 0 }, row: { type: 'integer', minimum: 0 } },
|
|
34
|
+
},
|
|
35
|
+
next_to: {
|
|
36
|
+
type: 'object',
|
|
37
|
+
description:
|
|
38
|
+
'Place the part by one of its pins, relative to a pin of another part: {"pin": "p2", "to": "Q1.collector", "dx": 0, "dy": -4} puts this part so that its pin p2 is 4 grid steps above Q1\'s collector (dx steps to the right, dy steps down; left out = 0). The editor works out the centre from the rotation and the pin offsets, so no coordinate arithmetic is needed. The other part needs a place of its own ("at" or its own "next_to"); in set_circuit the order of the list does not matter. This is the normal way to place every part except the first of a block.',
|
|
39
|
+
properties: { pin: { type: 'string' }, to: { type: 'string' }, dx: { type: 'integer' }, dy: { type: 'integer' } },
|
|
40
|
+
required: ['pin', 'to'],
|
|
35
41
|
},
|
|
36
42
|
rotation: { type: 'number', enum: [0, 90, 180, 270], description: 'Rotation in degrees (default 0). Two-pin passives lie horizontal at 0; sources stand vertical.' },
|
|
37
43
|
line_up: {
|
|
38
44
|
type: 'object',
|
|
39
45
|
description:
|
|
40
|
-
'Shift
|
|
46
|
+
'Shift a part that has a place ("at") a few grid steps so that one of its pins is exactly in line with a pin of another part: {"pin": "p1", "with": "M1.drain"}. The shift is along one axis, the one that needs the smaller move (at most 4 steps). "next_to" does the same and sets the distance too; use line_up to straighten a part that is already about right.',
|
|
41
47
|
properties: { pin: { type: 'string' }, with: { type: 'string' } },
|
|
42
48
|
required: ['pin', 'with'],
|
|
43
49
|
},
|
|
44
50
|
centre: {
|
|
45
51
|
type: 'object',
|
|
46
|
-
description: '
|
|
52
|
+
description: 'The same as "at": {"x", "y"} (kept for older calls).',
|
|
47
53
|
properties: { x: { type: 'integer' }, y: { type: 'integer' } },
|
|
48
54
|
required: ['x', 'y'],
|
|
49
55
|
},
|
|
@@ -56,7 +62,7 @@ const PART = {
|
|
|
56
62
|
/** A part for place_part: as PART, placed without wires */
|
|
57
63
|
const PART_BARE = {
|
|
58
64
|
type: 'object',
|
|
59
|
-
description: 'The part to place: id, type, value or model, params, and where ("at", "rotation"). No "nets".',
|
|
65
|
+
description: 'The part to place: id, type, value or model, params, and where ("at" or "next_to", "rotation"). No "nets".',
|
|
60
66
|
properties: Object.fromEntries(Object.entries(PART.properties).filter(([key]) => key !== 'nets')),
|
|
61
67
|
required: ['id', 'type'],
|
|
62
68
|
};
|
|
@@ -138,7 +144,7 @@ export const INTERNAL_METHODS = ['waveform_rows'];
|
|
|
138
144
|
export const EDITOR_TOOLS = [
|
|
139
145
|
{
|
|
140
146
|
name: 'list_component_types',
|
|
141
|
-
description: 'Part types the simulator has, with their pin names, where each pin is relative to the part\'s centre for every rotation (pin_offsets, in grid steps), the unit of their main value, and their parameters (SI units and defaults).',
|
|
147
|
+
description: 'Part types the simulator has, with their pin names, where each pin is relative to the part\'s centre for every rotation (pin_offsets, in grid steps), the room the part takes (outline), where its text is written, how much space parts need between them (spacing), the unit of their main value, and their parameters (SI units and defaults).',
|
|
142
148
|
inputSchema: { type: 'object', properties: {} },
|
|
143
149
|
},
|
|
144
150
|
{
|
|
@@ -180,7 +186,7 @@ export const EDITOR_TOOLS = [
|
|
|
180
186
|
{
|
|
181
187
|
name: 'set_circuit',
|
|
182
188
|
description:
|
|
183
|
-
'Replace the circuit in the editor. Give either "parts" (structured netlist) or "spice" (a SPICE deck). The editor draws it as a schematic: you choose where each part goes ("at", "rotation") and the editor draws the wires, falling back to
|
|
189
|
+
'Replace the circuit in the editor. Give either "parts" (structured netlist) or "spice" (a SPICE deck). The editor draws it as a schematic: you choose where each part goes ("at" for the first part of a block, "next_to" for the parts around it, "rotation") and the editor draws the wires, falling back to net labels only where parts are far apart or the way is blocked. Every net keeps the name you give it (V(name) refers to it), carried on its wires without being shown; "labels" chooses the few names to show. Parts placed too close for their wires are refused with the reason and the room each one takes. Plan the placement before you call this (LAYOUT in the server instructions): a compact placement by blocks gives short straight wires, a spread-out one gives a drawing nobody can read on one screen. This is the first step of every new circuit; afterwards read "layout" in the reply, look at a screenshot and tidy single parts and wires by hand (move_part, remove_wire, draw_wire, move_label). Returns the electrical rule check, the new revision, "layout" (size of the drawing, area and wire length per part, crossings, text overlaps, with the values to aim for) and "drawing" notes naming any nets that needed labels. The user can undo it.',
|
|
184
190
|
inputSchema: {
|
|
185
191
|
type: 'object',
|
|
186
192
|
properties: {
|
|
@@ -189,13 +195,19 @@ export const EDITOR_TOOLS = [
|
|
|
189
195
|
spice: { type: 'string', description: 'SPICE deck text (R, C, L, V, I, D, Q, M, J, E, G, F, H, K, .model, .subckt, .tran/.ac/.op).' },
|
|
190
196
|
simulation: SIMULATION,
|
|
191
197
|
probes: PROBES,
|
|
198
|
+
labels: {
|
|
199
|
+
type: 'object',
|
|
200
|
+
description:
|
|
201
|
+
'Nets whose name is shown in the drawing, for example {"in": "flag", "out": "flag", "vcc": "text"}. "text" writes the name on a wire of the net; "flag" draws a net label on it. Every net keeps its name either way; nets not listed do not show it.',
|
|
202
|
+
additionalProperties: { type: 'string', enum: ['flag', 'text'] },
|
|
203
|
+
},
|
|
192
204
|
},
|
|
193
205
|
},
|
|
194
206
|
},
|
|
195
207
|
{
|
|
196
208
|
name: 'edit_circuit',
|
|
197
209
|
description:
|
|
198
|
-
'Change the circuit in place; all operations succeed or none is applied. Operations: {"op":"set_value","part":"R1","value":"2.2k"}, {"op":"set_params","part":"M1","params":{"rdsOn":0.02}} (null removes a parameter), {"op":"set_model","part":"M1","model":"IRLZ44N"} (a library part from list_parts), {"op":"add_part","part":{...}} (wired to its nets where a clear path exists), {"op":"remove_part","part":"C3"}, {"op":"move_part","part":"R2","
|
|
210
|
+
'Change the circuit in place; all operations succeed or none is applied. Operations: {"op":"set_value","part":"R1","value":"2.2k"}, {"op":"set_params","part":"M1","params":{"rdsOn":0.02}} (null removes a parameter), {"op":"set_model","part":"M1","model":"IRLZ44N"} (a library part from list_parts), {"op":"add_part","part":{...}} (wired to its nets where a clear path exists), {"op":"remove_part","part":"C3"}, {"op":"move_part","part":"R2","next_to":{"pin":"p1","to":"Q1.collector","dy":-4},"rotation":90} (any of at, next_to, line_up, rotation, mirrorX, mirrorY; its wires are drawn again. move_part and connect operations that follow each other are made together: places are checked as they end up, so parts can swap places or take the place another part of the same call leaves, with no need to park anything first; a "next_to" sees the parts moved earlier in the list at their new place), {"op":"connect","part":"R2","nets":{"p2":"out"}} (moves the listed pins to other nets; null disconnects a pin; other pins keep their nets), {"op":"name_net","net":"N3","name":"out","show":"text"} (renames a net and/or chooses how its name is shown: "text" on a wire, "flag" as a net label, "hidden" not at all; probes follow a new name; connections never change, so a name another net has is refused). Use move_part to tidy a layout after looking at the screenshot. When parts were drawn again the reply carries "layout" (see set_circuit).',
|
|
199
211
|
inputSchema: {
|
|
200
212
|
type: 'object',
|
|
201
213
|
properties: {
|
|
@@ -205,12 +217,16 @@ export const EDITOR_TOOLS = [
|
|
|
205
217
|
items: {
|
|
206
218
|
type: 'object',
|
|
207
219
|
properties: {
|
|
208
|
-
op: { type: 'string', enum: ['set_value', 'set_params', 'set_model', 'add_part', 'remove_part', 'move_part', 'connect'] },
|
|
209
|
-
part: { description: 'Part id (
|
|
220
|
+
op: { type: 'string', enum: ['set_value', 'set_params', 'set_model', 'add_part', 'remove_part', 'move_part', 'connect', 'name_net'] },
|
|
221
|
+
part: { description: 'Part id (all operations on a part) or a part object (add_part). Not used by name_net.' },
|
|
222
|
+
net: { type: 'string', description: 'name_net: the net, by its current name (get_circuit).' },
|
|
223
|
+
name: { type: 'string', description: 'name_net: the new name.' },
|
|
224
|
+
show: { type: 'string', enum: ['text', 'flag', 'hidden'], description: 'name_net: how the name is shown.' },
|
|
210
225
|
value: { type: ['number', 'string'] },
|
|
211
226
|
params: { type: 'object' },
|
|
212
227
|
model: { type: 'string' },
|
|
213
|
-
at: { type: 'object', properties: { col: { type: 'integer' }, row: { type: 'integer' } } },
|
|
228
|
+
at: { type: 'object', properties: { x: { type: 'integer' }, y: { type: 'integer' }, col: { type: 'integer' }, row: { type: 'integer' } } },
|
|
229
|
+
next_to: { type: 'object', properties: { pin: { type: 'string' }, to: { type: 'string' }, dx: { type: 'integer' }, dy: { type: 'integer' } } },
|
|
214
230
|
rotation: { type: 'number', enum: [0, 90, 180, 270] },
|
|
215
231
|
mirrorX: { type: 'boolean' },
|
|
216
232
|
mirrorY: { type: 'boolean' },
|
|
@@ -218,7 +234,7 @@ export const EDITOR_TOOLS = [
|
|
|
218
234
|
centre: { type: 'object', properties: { x: { type: 'integer' }, y: { type: 'integer' } } },
|
|
219
235
|
nets: { type: 'object', description: 'connect: pin name -> net name, or null to disconnect the pin.' },
|
|
220
236
|
},
|
|
221
|
-
required: ['op'
|
|
237
|
+
required: ['op'],
|
|
222
238
|
},
|
|
223
239
|
},
|
|
224
240
|
},
|
|
@@ -233,13 +249,13 @@ export const EDITOR_TOOLS = [
|
|
|
233
249
|
{
|
|
234
250
|
name: 'get_drawing',
|
|
235
251
|
description:
|
|
236
|
-
'The drawing with positions, for wiring by hand: every part with its
|
|
252
|
+
'The drawing with positions, for wiring by hand and for judging the layout: every part with its centre, rotation, and each pin\'s position and net (null = nothing drawn on the pin yet); every ground symbol and net label; every probe; every wire with its id, its corner points, its net and "name_shown" when the net name is written on it; and "layout": the size of the drawing, area and wire length per part, crossings and text overlaps, with the values to aim for. Positions are in grid steps of 20 px; x grows to the right, y downwards. Use get_circuit for the netlist itself.',
|
|
237
253
|
inputSchema: { type: 'object', properties: {} },
|
|
238
254
|
},
|
|
239
255
|
{
|
|
240
256
|
name: 'place_part',
|
|
241
257
|
description:
|
|
242
|
-
'Place one part on the schematic without wires, to wire it yourself with draw_wire (for adding to a circuit; a new circuit starts with set_circuit). Give "at" (
|
|
258
|
+
'Place one part on the schematic without wires, to wire it yourself with draw_wire (for adding to a circuit; a new circuit starts with set_circuit). Give "at" (centre in grid steps) or "next_to" (a pin of it a stated number of steps from a pin of another part) and, where needed, "rotation", "mirrorX" or "mirrorY"; the reply lists where its pins are, in grid steps, ready for draw_wire. "part" is as in set_circuit but without "nets". A part placed bare only needs 1 free grid step to the bodies around it, so parts you wire yourself can sit closer than parts the editor wires. Left-out place: the next free cell beside the drawing.',
|
|
243
259
|
inputSchema: { type: 'object', properties: { part: PART_BARE, revision: REVISION_OPTIONAL }, required: ['part'] },
|
|
244
260
|
},
|
|
245
261
|
{
|
|
@@ -271,7 +287,7 @@ export const EDITOR_TOOLS = [
|
|
|
271
287
|
{
|
|
272
288
|
name: 'place_symbol',
|
|
273
289
|
description:
|
|
274
|
-
'Place a ground symbol or a net label with its connection point exactly at "at" (a pin, or a point in grid steps; usually the end of a wire). A ground symbol hangs down from the point and makes the net ground ("0"). A net label
|
|
290
|
+
'Place a ground symbol or a net label with its connection point exactly at "at" (a pin, or a point in grid steps; usually the end of a wire). A ground symbol hangs down from the point and makes the net ground ("0"). A net label shows the name of the net ("name") and V(name) refers to it; nets that show the same name (by a label, or by a name written on a wire) are one net without a wire between them. "side" puts a label\'s text left or right of the point.',
|
|
275
291
|
inputSchema: {
|
|
276
292
|
type: 'object',
|
|
277
293
|
properties: {
|
|
@@ -391,7 +407,7 @@ export const EDITOR_TOOLS = [
|
|
|
391
407
|
{
|
|
392
408
|
name: 'screenshot',
|
|
393
409
|
description:
|
|
394
|
-
'A PNG picture of what the user sees. view "schematic" (default): the whole drawing with its probes, always fitted to the picture whatever the user\'s zoom; give "parts" to get a close-up of the area around those parts instead
|
|
410
|
+
'A PNG picture of what the user sees. view "schematic" (default): the whole drawing with its probes, always fitted to the picture whatever the user\'s zoom; give "parts" to get a close-up of the area around those parts instead. When the whole drawing would be too small to read, the reply says so in "note": then take close-ups, one block at a time. view "waveforms": the plot panes of the waveform viewer as shown now, with their zoom and cursors (needs a simulation result). Look at the schematic after every set_circuit and after adding parts: check that parts and labels do not overlap, that wires are short and readable, and that the signal flows left to right; if not, move the parts (move_part with "next_to"). For numbers use measure or get_waveform.',
|
|
395
411
|
inputSchema: {
|
|
396
412
|
type: 'object',
|
|
397
413
|
properties: {
|
|
@@ -413,33 +429,36 @@ export const INSTRUCTIONS = [
|
|
|
413
429
|
'Start with open_editor, then list_component_types (once). All numbers are SI. Ground is net "0". The user can edit the circuit too: if a call reports that the revision changed, call get_circuit and continue from what is there.',
|
|
414
430
|
'',
|
|
415
431
|
'HOW TO BUILD A CIRCUIT. Draw the whole circuit in one go, then tidy it by hand like an engineer cleaning up a sketch:',
|
|
416
|
-
'1. Plan the placement first (LAYOUT below):
|
|
417
|
-
'2. Draw it with one set_circuit call: every part with
|
|
418
|
-
'3.
|
|
419
|
-
'4. Fix what does not read cleanly, one change at a time, so the user can follow: move_part for a part in the wrong place or out of line ("
|
|
432
|
+
'1. Plan the placement first (LAYOUT below): split the circuit into blocks, and decide for every part its rotation and which pin of which neighbour it sits next to.',
|
|
433
|
+
'2. Draw it with one set_circuit call: every part with "at" or "next_to", its "rotation" and its nets. The editor places the parts and wires them. Check "check" for errors. A part refused as too close comes with the room both parts take: move it out by the missing steps and send the call again.',
|
|
434
|
+
'3. Read "layout" in the reply: it gives the size of the drawing, the area and wire length per part, crossings and text overlaps, and the values to aim for. Then call screenshot and look at the result critically, as the user will. If the screenshot reply says the drawing is too small to read, take close-ups of one block at a time ("parts").',
|
|
435
|
+
'4. Fix what does not read cleanly, one change at a time, so the user can follow: move_part for a part in the wrong place or out of line ("next_to" puts a pin a stated distance from the pin it connects to, "line_up" puts it exactly in line); remove_wire and draw_wire for a wire with a detour, a jog or a needless crossing; move_label for text or a net label that sits on something. After a few fixes take another screenshot. Stop when the drawing reads cleanly from left to right; do not redraw what is already good. To rearrange a whole block, put all its move_part operations in one edit_circuit call: they are applied together and the wires are drawn once.',
|
|
420
436
|
'5. After changing wires by hand, call get_circuit and compare the net on every pin with the circuit you intended: read every draw_wire reply too, it lists the pins the wire connected.',
|
|
421
437
|
'6. Then set_probes -> run_simulation -> measure. Change values with edit_circuit and run again.',
|
|
422
438
|
'To extend a circuit later, add parts one at a time: edit_circuit add_part wires the part for you, place_part places it bare for wiring with draw_wire. Building a whole circuit with place_part and draw_wire is possible and fine for a handful of parts, but slower; a SPICE deck or a large circuit always starts with set_circuit.',
|
|
423
439
|
'',
|
|
424
|
-
'LAYOUT. You place the parts
|
|
425
|
-
'-
|
|
426
|
-
'-
|
|
427
|
-
'-
|
|
428
|
-
'-
|
|
429
|
-
'-
|
|
430
|
-
'-
|
|
431
|
-
'-
|
|
432
|
-
'-
|
|
440
|
+
'LAYOUT. You place the parts. Positions are in grid steps of 20 px, x to the right, y downwards. A schematic is read on one screen: the aim is a compact drawing in which every block is recognisable, not parts spread evenly over a large sheet.',
|
|
441
|
+
'- Work in blocks. A block is one function with its helpers: a transistor or op-amp stage with its bias, feedback and decoupling parts; a rectifier with its reservoir capacitor; a reference; an output filter. Lay each block out compactly around its main part, with 4 to 6 grid steps between neighbouring parts.',
|
|
442
|
+
'- Arrange the blocks in signal order from left to right, sources and inputs at the left, the load or output at the right, with 6 to 10 steps between blocks. When the drawing gets wider than about 120 steps, start a second row of blocks below instead of going on to the right: aim for a drawing about one and a half to two times as wide as it is high. A circuit drawn as one long row is wrong.',
|
|
443
|
+
'- Place by pins, not by centres. Give the main part of a block "at": {"x", "y"}, and every part around it "next_to": {"pin": "<its pin>", "to": "Q1.collector", "dx": ..., "dy": ...}, which puts that pin dx steps right and dy steps down of the named pin. Connected pins then sit exactly in line and the wire between them is one straight piece. The editor does the arithmetic from the rotation and the pin offsets (list_component_types gives pin_offsets and the outline of every part for each rotation).',
|
|
444
|
+
'- Distances that work: a part in series with a pin goes 4 steps from it in the direction the pin points (dx: 4 or -4 for a pin pointing sideways, dy: 4 or -4 for one pointing up or down). A part hanging from a node to ground stands upright (rotation 90 or 270) with its top pin 4 steps below that pin. A ground pin needs 6 free steps below it for its wire and symbol. Two parts side by side need 1 free step between their bodies. A pin that faces the side of another part needs 4 steps to it, and a pin of another net opposite a pin needs 5.',
|
|
445
|
+
'- The editor refuses a part that is too close for the wires it has to draw and says which part is in the way and what room each takes; widen that one distance, do not spread everything out.',
|
|
446
|
+
'- Inside a block: parts in series with the signal lie in the signal row at rotation 0, in the order the signal meets them. Parts from a node to ground or to a rail stand upright below (to ground) or above (to a supply) the node. Feedback parts go above the stage they bridge. Decoupling capacitors stand next to the supply pin they serve.',
|
|
447
|
+
'- Rotate or mirror a part so its pins face what they connect to ("rotation"; "mirrorX" swaps left and right, "mirrorY" top and bottom).',
|
|
448
|
+
'- A source stands at the left with its negative pin to ground; a second supply stands above or below it.',
|
|
449
|
+
'- Check the numbers: after every drawing, "layout.area_per_part" should be about 80 to 150 square grid steps and "layout.wire_per_part" about 6 to 18 steps. Much more means the parts are too far apart: move them closer block by block. "layout.text_overlaps" lists texts that lie on another part: move the text with move_label or the part by a step or two.',
|
|
450
|
+
'- {"col", "row"} in "at" names a cell of a coarse grid (16 x 12 steps per cell) and a part given no place at all goes to the next free cell. That is for a quick sketch only: a drawing on that grid is three times too wide.',
|
|
433
451
|
'',
|
|
434
|
-
'WIRES. Positions are in grid steps of 20 px
|
|
435
|
-
'- Wires are horizontal and vertical only, as short as the placement allows, with as few corners as possible. Two pins on one line are joined by one straight wire. If a wire between neighbouring parts needs a jog of one or two steps, the parts are out of line: fix the part with move_part and "line_up" instead of drawing the jog.',
|
|
452
|
+
'WIRES. Positions are in grid steps of 20 px.',
|
|
453
|
+
'- Wires are horizontal and vertical only, as short as the placement allows, with as few corners as possible. Two pins on one line are joined by one straight wire. If a wire between neighbouring parts needs a jog of one or two steps, the parts are out of line: fix the part with move_part and "next_to" or "line_up" instead of drawing the jog.',
|
|
436
454
|
'- Lead a wire two grid steps straight out of a pin before it turns or meets another wire. Extend that only when other connections need the room.',
|
|
437
455
|
'- Avoid crossings. Where one cannot be avoided, both wires run straight for at least two grid steps on each side of it.',
|
|
438
456
|
'- Join a third pin to a net by ending its wire on the existing wire (a junction), two grid steps or more from the nearest pin or corner, not by a second wire into the same pin.',
|
|
439
457
|
'- Never run a wire over a part or along another wire. Go around, with "via" points.',
|
|
440
458
|
'- A ground symbol goes two grid steps below a pin that points down (draw the short wire, then place the symbol at its end). Prefer one ground symbol per ground pin over long ground wires.',
|
|
441
|
-
'-
|
|
442
|
-
'
|
|
459
|
+
'- Net names: every net has the name you gave it, on its wires, and V(name) works whether the name is shown or not. Show only the names a reader looks for: inputs, outputs, supply rails and the nodes you measure. "labels" in set_circuit or the name_net operation does it: "text" writes the name on a wire (good for a rail or a node inside a block), "flag" draws a net label (good for an input or output at the edge). Leave the names of internal nodes unshown.',
|
|
460
|
+
'- A name connects only where it is shown: two nets that show the same name are one net, and a name that is not shown connects nothing. Two separate nets must not carry the same name; the check reports it as a warning.',
|
|
461
|
+
'These are the rules to judge the automatic wiring by and to follow when you redraw a wire. In a screenshot: parts and text must not overlap, wires must be short and straight, blocks must be recognisable, and the drawing must read from left to right. Tidy what does not (remove_wire and redraw; move_part for a part; move_label for text or a net label that sits on a wire, a part or other text).',
|
|
443
462
|
'',
|
|
444
463
|
'For a real semiconductor or op-amp, select it with list_parts ("where" and "sort" pick by voltage, current, resistance and so on) and name it with "model" instead of typing datasheet values.',
|
|
445
464
|
'Keep the design notes current with set_design_notes (requirements, decisions, measured results). For data too large to read, export_waveforms writes a CSV file.',
|