@evandu/super-pi 0.0.0-stage → 0.1.1
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 +79 -2
- package/agents/coder.md +10 -0
- package/agents/critic.md +20 -0
- package/agents/patcher.md +23 -0
- package/agents/planner.md +18 -0
- package/agents/reviewer.md +13 -0
- package/agents/scout.md +23 -0
- package/agents/super-pi-task/core.ts +485 -0
- package/agents/super-pi-task/index.ts +141 -0
- package/agents/verifier.md +21 -0
- package/bin/super-pi.js +17 -0
- package/dist/client/assets/index-BMQsEdio.js +24 -0
- package/dist/client/assets/index-CsbZzuMy.css +1 -0
- package/dist/client/index.html +14 -0
- package/dist/extension.d.ts +15 -0
- package/dist/extension.js +111 -0
- package/dist/server/agents.d.ts +177 -0
- package/dist/server/agents.js +484 -0
- package/dist/server/application/catalog-service.d.ts +44 -0
- package/dist/server/application/catalog-service.js +94 -0
- package/dist/server/application/conversation-service.d.ts +73 -0
- package/dist/server/application/conversation-service.js +202 -0
- package/dist/server/application/extension-ui-service.d.ts +28 -0
- package/dist/server/application/extension-ui-service.js +73 -0
- package/dist/server/application/run-service.d.ts +115 -0
- package/dist/server/application/run-service.js +341 -0
- package/dist/server/application/workspace-service.d.ts +45 -0
- package/dist/server/application/workspace-service.js +106 -0
- package/dist/server/command-handler.d.ts +22 -0
- package/dist/server/command-handler.js +137 -0
- package/dist/server/files.d.ts +202 -0
- package/dist/server/files.js +629 -0
- package/dist/server/http-server.d.ts +20 -0
- package/dist/server/http-server.js +313 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +103 -0
- package/dist/server/pi-command.d.ts +65 -0
- package/dist/server/pi-command.js +183 -0
- package/dist/server/runtime.d.ts +819 -0
- package/dist/server/runtime.js +1470 -0
- package/dist/server/server-context.d.ts +46 -0
- package/dist/server/server-context.js +1 -0
- package/dist/server/store.d.ts +424 -0
- package/dist/server/store.js +1121 -0
- package/dist/server/subagent-runs.d.ts +142 -0
- package/dist/server/subagent-runs.js +315 -0
- package/dist/server/subagents.d.ts +194 -0
- package/dist/server/subagents.js +542 -0
- package/dist/server/task-tool.d.ts +196 -0
- package/dist/server/task-tool.js +285 -0
- package/dist/server/tool-calls.d.ts +62 -0
- package/dist/server/tool-calls.js +141 -0
- package/dist/server/types.d.ts +920 -0
- package/dist/server/types.js +11 -0
- package/dist/server/upload.d.ts +37 -0
- package/dist/server/upload.js +169 -0
- package/dist/server/ws-server.d.ts +45 -0
- package/dist/server/ws-server.js +116 -0
- package/package.json +115 -4
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning one Pi tool call into something a human reads, and nothing more.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS ITS OWN MODULE. Two drain loops need exactly this derivation - the sub-agent supervisor
|
|
5
|
+
* (`subagents.ts`) and the PRIMARY agent's runtime (`runtime.ts`) - and `subagents.ts` already imports
|
|
6
|
+
* `runtime.ts` for `RpcChannel`, so the reverse import would be a cycle. One definition of "what does
|
|
7
|
+
* this call show" therefore has to live below both of them, or the two surfaces would drift: a `read`
|
|
8
|
+
* labelled by its path on a card and by its working directory on a call block is worse than either.
|
|
9
|
+
*
|
|
10
|
+
* The rule the whole module exists to enforce: DERIVED AND BOUNDED, NEVER COPIED. What Pi sends in
|
|
11
|
+
* `args` is an arbitrary object that may hold a file's contents, a multi-kilobyte patch or an entire
|
|
12
|
+
* shell script. What leaves here is short strings with a hard character cap, or a bare type word.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The longest label one tool call may contribute. See `SubagentToolCall.detail` and `ToolCallBlock.detail`
|
|
16
|
+
* for why the argument is summarised rather than carried: the cap is what makes the bound structural
|
|
17
|
+
* instead of aspirational, because nothing downstream can grow past it.
|
|
18
|
+
*/
|
|
19
|
+
export const TOOL_DETAIL_CAP = 120;
|
|
20
|
+
/**
|
|
21
|
+
* How many parameters one call block may list.
|
|
22
|
+
*
|
|
23
|
+
* A bound on the COUNT as well as on each value, for the same reason `TOOL_DETAIL_CAP` exists: without
|
|
24
|
+
* it, a tool that Pi sends a dozen arguments to would put twelve rows - and twelve times the cap - into a
|
|
25
|
+
* field that is rewritten on every text delta of the message it belongs to. Six covers every call shape
|
|
26
|
+
* this project has seen (`read`'s path/offset/limit, `bash`'s command/description/timeout) and truncating
|
|
27
|
+
* past it is announced by the caller through the row count rather than silently.
|
|
28
|
+
*/
|
|
29
|
+
export const TOOL_ARG_CAP = 6;
|
|
30
|
+
/** Argument fields that name a FILE, in the order the tools that read files tend to spell them. */
|
|
31
|
+
const PATH_KEYS = ["path", "file_path", "filePath", "target_file", "filename", "file"];
|
|
32
|
+
/** Argument fields that name a SEARCH, which is the thing a human wants to see on a `grep` row. */
|
|
33
|
+
const PATTERN_KEYS = ["pattern", "query", "regex", "search", "glob"];
|
|
34
|
+
/** Argument fields that name a COMMAND LINE. */
|
|
35
|
+
const COMMAND_KEYS = ["command", "cmd", "script"];
|
|
36
|
+
/**
|
|
37
|
+
* Which argument field names what a given tool was aimed at.
|
|
38
|
+
*
|
|
39
|
+
* A per-tool table rather than one generic scan, because the generic answer is wrong in a way a person
|
|
40
|
+
* would notice: scanning `path` before `command` would label a `bash` row with a working directory, and
|
|
41
|
+
* scanning `pattern` before `path` would label a `read` row with nothing at all. Unknown tools fall
|
|
42
|
+
* back to the union, which is imprecise by construction - and imprecise is acceptable here, because a
|
|
43
|
+
* missing label costs the reader one line and a WRONG one costs them trust in every other label.
|
|
44
|
+
*/
|
|
45
|
+
const TARGET_KEYS = {
|
|
46
|
+
read: PATH_KEYS, write: PATH_KEYS, edit: PATH_KEYS, multiedit: PATH_KEYS, notebookread: PATH_KEYS, notebookedit: PATH_KEYS,
|
|
47
|
+
glob: PATTERN_KEYS, grep: PATTERN_KEYS, search: PATTERN_KEYS,
|
|
48
|
+
bash: COMMAND_KEYS, shell: COMMAND_KEYS, run: COMMAND_KEYS,
|
|
49
|
+
};
|
|
50
|
+
const FALLBACK_KEYS = [...COMMAND_KEYS, ...PATH_KEYS, ...PATTERN_KEYS];
|
|
51
|
+
/** One line, whitespace collapsed, hard-capped. The ONLY way a value becomes text in this module. */
|
|
52
|
+
const oneLine = (value) => {
|
|
53
|
+
const collapsed = value.replace(/\s+/g, " ").trim();
|
|
54
|
+
if (!collapsed)
|
|
55
|
+
return "";
|
|
56
|
+
return collapsed.length > TOOL_DETAIL_CAP ? `${collapsed.slice(0, TOOL_DETAIL_CAP - 1)}…` : collapsed;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The one line that tells a reader what a tool call was FOR: the file it opened, the pattern it searched
|
|
60
|
+
* for, the command it ran.
|
|
61
|
+
*
|
|
62
|
+
* Returns `undefined` rather than a placeholder when nothing is recognised, so a row omits the column
|
|
63
|
+
* instead of rendering a column of emptiness.
|
|
64
|
+
*
|
|
65
|
+
* Exported so the mapping can be asserted without spawning a child, which is the only way a table this
|
|
66
|
+
* shape can be regression-tested at all.
|
|
67
|
+
*/
|
|
68
|
+
export function describeToolCall(name, args) {
|
|
69
|
+
if (args === null || typeof args !== "object" || Array.isArray(args))
|
|
70
|
+
return undefined;
|
|
71
|
+
const record = args;
|
|
72
|
+
for (const key of TARGET_KEYS[name.trim().toLowerCase()] ?? FALLBACK_KEYS) {
|
|
73
|
+
const value = record[key];
|
|
74
|
+
if (typeof value !== "string")
|
|
75
|
+
continue;
|
|
76
|
+
const line = oneLine(value);
|
|
77
|
+
if (line)
|
|
78
|
+
return line;
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* How one non-string argument value is NAMED without being read.
|
|
84
|
+
*
|
|
85
|
+
* THE MOST IMPORTANT LINE IN THIS FILE. An `edit` tool's arguments routinely carry the replacement text
|
|
86
|
+
* for a whole file, and a `bash` call's arguments can carry anything the model wrote. Rendering such a
|
|
87
|
+
* value - even truncated, even `JSON.stringify`d - would put file contents into a field that is
|
|
88
|
+
* persisted in `state.json` and broadcast to every browser, which is precisely the line
|
|
89
|
+
* `SubagentToolCall.detail` is documented as drawing. So a non-primitive contributes its KIND and
|
|
90
|
+
* nothing else: a reader learns that a patch was applied or an array was passed, and cannot learn what
|
|
91
|
+
* was in it.
|
|
92
|
+
*/
|
|
93
|
+
const describeShape = (value) => {
|
|
94
|
+
if (value === null)
|
|
95
|
+
return "null";
|
|
96
|
+
if (Array.isArray(value))
|
|
97
|
+
return `(数组 ${value.length} 项)`;
|
|
98
|
+
switch (typeof value) {
|
|
99
|
+
case "number": return Number.isFinite(value) ? String(value) : undefined;
|
|
100
|
+
case "boolean": return String(value);
|
|
101
|
+
case "object": return "(对象)";
|
|
102
|
+
default: return undefined;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Every parameter of one call, as a bounded list of `key`/`value` pairs a block can show when expanded.
|
|
107
|
+
*
|
|
108
|
+
* THIS IS THE SAME LINE `describeToolCall` DRAWS, APPLIED PER KEY. `describeToolCall` answers "what was
|
|
109
|
+
* this aimed at" with one label; this answers "what was this given" with the whole bounded list, which is
|
|
110
|
+
* the difference between a row that says `bash` and a block that says which command, plus its timeout
|
|
111
|
+
* and description. Both are derived: a string is whitespace-collapsed and capped at `TOOL_DETAIL_CAP`, and
|
|
112
|
+
* anything that is not a string or a number or a boolean becomes a type word (see `describeShape`).
|
|
113
|
+
*
|
|
114
|
+
* Order is Pi's own key order rather than this module's table order, because once every key is listed the
|
|
115
|
+
* per-tool table has said everything it knows - and a reader scanning a list wants the order the caller
|
|
116
|
+
* wrote it in, not one this file invented.
|
|
117
|
+
*
|
|
118
|
+
* Capped at `TOOL_ARG_CAP` ENTRIES, and the cap is applied by taking the first N rather than by sampling
|
|
119
|
+
* across the object: a truncated tail is a prefix of the real argument list, so what is shown is never
|
|
120
|
+
* a selection that implies the omitted keys did not exist.
|
|
121
|
+
*
|
|
122
|
+
* Returns `undefined` when there is nothing readable at all, so a call with no usable arguments renders
|
|
123
|
+
* no parameter section rather than an empty one.
|
|
124
|
+
*/
|
|
125
|
+
export function describeToolCallArgs(args) {
|
|
126
|
+
if (args === null || typeof args !== "object" || Array.isArray(args))
|
|
127
|
+
return undefined;
|
|
128
|
+
const listed = [];
|
|
129
|
+
// `Object.keys` rather than `for..in`: a key this file cannot render is skipped rather than emitted
|
|
130
|
+
// with an empty value, and an inherited key is not a parameter Pi sent.
|
|
131
|
+
for (const key of Object.keys(args)) {
|
|
132
|
+
if (listed.length >= TOOL_ARG_CAP)
|
|
133
|
+
break;
|
|
134
|
+
const raw = args[key];
|
|
135
|
+
const value = typeof raw === "string" ? oneLine(raw) : describeShape(raw);
|
|
136
|
+
if (value === undefined || value === "")
|
|
137
|
+
continue;
|
|
138
|
+
listed.push({ key, value });
|
|
139
|
+
}
|
|
140
|
+
return listed.length ? listed : undefined;
|
|
141
|
+
}
|