@apolloyh/apollo-agent 0.1.9 → 0.1.11
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/.apollo/hooks.example.json +5 -0
- package/README.md +11 -4
- package/dist/brand.d.ts +1 -1
- package/dist/brand.js +1 -1
- package/dist/index.js +55 -23
- package/dist/llm/anthropic.d.ts +4 -0
- package/dist/llm/anthropic.d.ts.map +1 -1
- package/dist/llm/anthropic.js +32 -7
- package/dist/runtime/query-engine.d.ts +7 -0
- package/dist/runtime/query-engine.d.ts.map +1 -1
- package/dist/runtime/query-engine.js +15 -0
- package/dist/thought-fold.d.ts +6 -21
- package/dist/thought-fold.d.ts.map +1 -1
- package/dist/thought-fold.js +23 -98
- package/dist/trace.d.ts.map +1 -1
- package/dist/trace.js +19 -5
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/features-cc.md +133 -0
- package/docs/guide.md +250 -0
- package/docs/npm-release.md +251 -0
- package/docs/sdk.md +2 -10
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Terminal text wordmark (no icon / no triangle):
|
|
|
23
23
|
- Built-in `simplify`, `verify`, and `debug` workflows; workspace skills can override them
|
|
24
24
|
- Waiting UI: blinking `◆`
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## Install
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
npm install -g @apolloyh/apollo-agent
|
|
@@ -40,7 +40,7 @@ Apollo creates global defaults at `~/.apollo/config.json` and copies the complet
|
|
|
40
40
|
reference to `~/.apollo/config.example.json`. Project overrides live at
|
|
41
41
|
`.apollo/config.json`; Apollo also reads the legacy `agent.config.json` during migration.
|
|
42
42
|
Configuration layers as built-in defaults → user config → project config → `--config`.
|
|
43
|
-
Set `systemPrompt` in either config to
|
|
43
|
+
Set `systemPrompt` in either config to place stable custom instructions at the front of the system prompt; restart Apollo to reload them.
|
|
44
44
|
|
|
45
45
|
Apollo also loads `~/.apollo/APOLLO.md` followed by the project `APOLLO.md` (lowercase
|
|
46
46
|
`apollo.md` is accepted). If no project Apollo file exists, the standard `AGENTS.md` and
|
|
@@ -49,7 +49,14 @@ Apollo also loads `~/.apollo/APOLLO.md` followed by the project `APOLLO.md` (low
|
|
|
49
49
|
While Apollo is working, type and press Enter to queue another user message. Queued messages
|
|
50
50
|
run in FIFO order after the current turn; press Esc to interrupt the current turn safely.
|
|
51
51
|
|
|
52
|
-
Commands: `/help` · `/
|
|
52
|
+
Commands: `/help` · `/skill` · `/simplify` · `/verify` · `/debug` · `/agents` · `/status` · `/sessions` · `/resume` · `/plan` · `/goal` · `/workflow` · `/verbose` · `/stream` · `/clear` · `/exit`
|
|
53
|
+
|
|
54
|
+
## Documentation
|
|
55
|
+
|
|
56
|
+
- [完整使用指南](docs/guide.md)
|
|
57
|
+
- [SDK 接入指南](docs/sdk.md)
|
|
58
|
+
- [npm 打包与发布手册](docs/npm-release.md)
|
|
59
|
+
- [高级功能与恢复机制](docs/features-cc.md)
|
|
53
60
|
|
|
54
61
|
## SDK
|
|
55
62
|
|
|
@@ -69,4 +76,4 @@ try {
|
|
|
69
76
|
}
|
|
70
77
|
```
|
|
71
78
|
|
|
72
|
-
See the [
|
|
79
|
+
See the [full usage guide](docs/guide.md) and [SDK integration guide](docs/sdk.md).
|
package/dist/brand.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Product identity — single source of truth for display strings. */
|
|
2
2
|
export declare const PRODUCT: {
|
|
3
3
|
readonly name: "Apollo";
|
|
4
|
-
readonly version: "0.1.
|
|
4
|
+
readonly version: "0.1.11";
|
|
5
5
|
readonly tagline: "Your personal agent — answer first, act when needed.";
|
|
6
6
|
readonly packageName: "@apolloyh/apollo-agent";
|
|
7
7
|
readonly userAgent: "ApolloAgent/0.1";
|
package/dist/brand.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Product identity — single source of truth for display strings. */
|
|
2
2
|
export const PRODUCT = {
|
|
3
3
|
name: "Apollo",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.11",
|
|
5
5
|
tagline: "Your personal agent — answer first, act when needed.",
|
|
6
6
|
packageName: "@apolloyh/apollo-agent",
|
|
7
7
|
userAgent: "ApolloAgent/0.1",
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ let liveStatus;
|
|
|
21
21
|
let runningTaskCount = 0;
|
|
22
22
|
let activeVerb = "Thinking";
|
|
23
23
|
let assistantResponseStarted = false;
|
|
24
|
+
let liveThinkingPreview = "";
|
|
24
25
|
/** Prevent double green/red outcome lines in one user turn */
|
|
25
26
|
let outcomePrintedThisTurn = false;
|
|
26
27
|
let pastedTextSequence = 0;
|
|
@@ -97,31 +98,19 @@ async function main() {
|
|
|
97
98
|
// never reaches the interactive `runtime` binding). Also lets SIGINT close whichever is active.
|
|
98
99
|
let activeRuntime;
|
|
99
100
|
const traceSink = (event) => {
|
|
100
|
-
|
|
101
|
+
let completedThought = null;
|
|
102
|
+
// Collect only model thinking tokens into the collapsible Thought.
|
|
101
103
|
if (event.type === "llm_request") {
|
|
102
104
|
thoughtFold.beginTurn();
|
|
103
|
-
thoughtFold.note(`turn ${event.turn} · ${event.toolCount} tools available`);
|
|
104
105
|
}
|
|
105
|
-
else if (event.type === "
|
|
106
|
-
thoughtFold.
|
|
107
|
-
}
|
|
108
|
-
else if (event.type === "tool_call") {
|
|
109
|
-
thoughtFold.noteTool(event.tool);
|
|
110
|
-
}
|
|
111
|
-
else if (event.type === "tool_result") {
|
|
112
|
-
thoughtFold.note(`${event.tool} ${event.isError ? "failed" : "ok"}`);
|
|
113
|
-
}
|
|
114
|
-
else if (event.type === "task_start") {
|
|
115
|
-
thoughtFold.note(`Task(${event.subagentType}): ${event.description}`);
|
|
116
|
-
}
|
|
117
|
-
else if (event.type === "task_finish") {
|
|
118
|
-
thoughtFold.note(`Task(${event.subagentType}) finished`);
|
|
106
|
+
else if (event.type === "thinking_delta") {
|
|
107
|
+
thoughtFold.appendThinking(event.text);
|
|
119
108
|
}
|
|
120
109
|
else if (event.type === "assistant_delta") {
|
|
121
|
-
thoughtFold.finalizeAndPrint();
|
|
110
|
+
completedThought = thoughtFold.finalizeAndPrint();
|
|
122
111
|
}
|
|
123
112
|
else if (event.type === "llm_response" && event.stopReason !== "tool_use") {
|
|
124
|
-
thoughtFold.finalizeAndPrint();
|
|
113
|
+
completedThought = thoughtFold.finalizeAndPrint();
|
|
125
114
|
}
|
|
126
115
|
if (event.type === "workflow_status") {
|
|
127
116
|
const bar = workflowStatusBar({
|
|
@@ -166,6 +155,8 @@ async function main() {
|
|
|
166
155
|
if (renderBeforeStatus)
|
|
167
156
|
rendererSink(event);
|
|
168
157
|
updateLiveStatus(event, interactiveMode);
|
|
158
|
+
if (interactiveMode && completedThought)
|
|
159
|
+
thoughtFold.printPreview(completedThought);
|
|
169
160
|
taskActivity.record(event);
|
|
170
161
|
if (!renderBeforeStatus)
|
|
171
162
|
rendererSink(event);
|
|
@@ -513,10 +504,6 @@ async function main() {
|
|
|
513
504
|
stdout.write(notes.map((n) => `- ${n.id} ${n.title}\n ${n.content.slice(0, 120).replace(/\n/g, " ")}`).join("\n") + "\n");
|
|
514
505
|
continue;
|
|
515
506
|
}
|
|
516
|
-
if (text === "/thought" || text === "/think" || text === "/t") {
|
|
517
|
-
thoughtFold.toggle();
|
|
518
|
-
continue;
|
|
519
|
-
}
|
|
520
507
|
if (text.startsWith("/verbose")) {
|
|
521
508
|
const value = text.split(/\s+/)[1];
|
|
522
509
|
traceOptions.verbose = value === "on" ? true : value === "off" ? false : !traceOptions.verbose;
|
|
@@ -756,8 +743,19 @@ function updateLiveStatus(event, enabled) {
|
|
|
756
743
|
switch (event.type) {
|
|
757
744
|
case "llm_request":
|
|
758
745
|
assistantResponseStarted = false;
|
|
746
|
+
liveThinkingPreview = "";
|
|
759
747
|
startLiveStatus(runningTaskCount > 0 ? formatRunningTasks() : activeVerb);
|
|
760
748
|
break;
|
|
749
|
+
case "thinking_delta": {
|
|
750
|
+
liveThinkingPreview = stripTerminalEscapes(`${liveThinkingPreview}${event.text}`)
|
|
751
|
+
.replace(/\s+/g, " ")
|
|
752
|
+
.trimStart()
|
|
753
|
+
.slice(0, 1000);
|
|
754
|
+
if (liveStatus)
|
|
755
|
+
liveStatus.text = "Thinking";
|
|
756
|
+
paintLiveStatus();
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
761
759
|
case "llm_retry":
|
|
762
760
|
startLiveStatus(event.mode === "after-compaction"
|
|
763
761
|
? "Retrying after compaction"
|
|
@@ -1038,6 +1036,9 @@ async function readCliLine(options) {
|
|
|
1038
1036
|
const liveStatusLine = renderLiveStatusLine(options.color);
|
|
1039
1037
|
if (liveStatusLine)
|
|
1040
1038
|
lines.push(liveStatusLine);
|
|
1039
|
+
if (liveStatus?.text === "Thinking" && liveThinkingPreview) {
|
|
1040
|
+
lines.push(...renderLiveThinkingLines(liveThinkingPreview, options.color));
|
|
1041
|
+
}
|
|
1041
1042
|
lines.push(renderInputBorder("top", options.color));
|
|
1042
1043
|
const view = renderInputView(buffer, cursor, inputContentWidth(), pastedTextBlocks);
|
|
1043
1044
|
const idleQueue = options.queueMode && !buffer;
|
|
@@ -1614,6 +1615,37 @@ function renderLiveStatusLine(useColor) {
|
|
|
1614
1615
|
: `${liveStatus.text}...`;
|
|
1615
1616
|
return formatWaitLine({ frame: liveStatus.frame, label, elapsed, useColor });
|
|
1616
1617
|
}
|
|
1618
|
+
function renderLiveThinkingLines(value, useColor) {
|
|
1619
|
+
const prefixWidth = 4;
|
|
1620
|
+
const width = Math.max(24, Math.min((stdout.columns ?? 100) - prefixWidth, 96));
|
|
1621
|
+
const lines = [];
|
|
1622
|
+
let current = "";
|
|
1623
|
+
let currentWidth = 0;
|
|
1624
|
+
let consumed = 0;
|
|
1625
|
+
const characters = Array.from(value);
|
|
1626
|
+
for (const char of characters) {
|
|
1627
|
+
const charWidth = displayLength(char);
|
|
1628
|
+
if (current && currentWidth + charWidth > width) {
|
|
1629
|
+
lines.push(current);
|
|
1630
|
+
if (lines.length === 3)
|
|
1631
|
+
break;
|
|
1632
|
+
current = "";
|
|
1633
|
+
currentWidth = 0;
|
|
1634
|
+
}
|
|
1635
|
+
current += char;
|
|
1636
|
+
currentWidth += charWidth;
|
|
1637
|
+
consumed += 1;
|
|
1638
|
+
}
|
|
1639
|
+
if (lines.length < 3 && current)
|
|
1640
|
+
lines.push(current);
|
|
1641
|
+
if (consumed < characters.length && lines.length) {
|
|
1642
|
+
const last = truncateDisplay(lines[lines.length - 1], Math.max(1, width - 1)).replace(/…$/, "");
|
|
1643
|
+
lines[lines.length - 1] = `${last}…`;
|
|
1644
|
+
}
|
|
1645
|
+
const dim = useColor ? "\x1b[90m" : "";
|
|
1646
|
+
const reset = useColor ? "\x1b[0m" : "";
|
|
1647
|
+
return lines.map((line, index) => `${dim}${index === 0 ? " └ " : " "}${line}${reset}`);
|
|
1648
|
+
}
|
|
1617
1649
|
function renderInputBorder(position, useColor) {
|
|
1618
1650
|
const terminalWidth = Math.max(48, Math.min(stdout.columns ?? 100, 100));
|
|
1619
1651
|
const left = position === "top" ? "╭" : "╰";
|
|
@@ -1641,7 +1673,7 @@ function renderWelcomeBanner(options) {
|
|
|
1641
1673
|
`${dim}trace${reset} ${options.quiet ? "quiet" : "verbose"}`,
|
|
1642
1674
|
`${dim}approval${reset} ${options.yolo ? `${green}yolo${reset}` : "ask"}`,
|
|
1643
1675
|
"",
|
|
1644
|
-
`${dim}Type / to search · /
|
|
1676
|
+
`${dim}Type / to search · /help${reset}`,
|
|
1645
1677
|
"",
|
|
1646
1678
|
"",
|
|
1647
1679
|
].join("\n");
|
package/dist/llm/anthropic.d.ts
CHANGED
|
@@ -18,6 +18,9 @@ export type ToolInputDelta = {
|
|
|
18
18
|
tool?: string;
|
|
19
19
|
detail?: string;
|
|
20
20
|
};
|
|
21
|
+
export type ThinkingDelta = {
|
|
22
|
+
text: string;
|
|
23
|
+
};
|
|
21
24
|
export declare class MalformedStreamError extends Error {
|
|
22
25
|
constructor(message: string, cause?: unknown);
|
|
23
26
|
}
|
|
@@ -40,6 +43,7 @@ export declare class AnthropicClient {
|
|
|
40
43
|
stream?: boolean;
|
|
41
44
|
signal?: AbortSignal;
|
|
42
45
|
onTextDelta?: (text: string) => void;
|
|
46
|
+
onThinkingDelta?: (event: ThinkingDelta) => void;
|
|
43
47
|
onToolInputDelta?: (event: ToolInputDelta) => void;
|
|
44
48
|
}): Promise<AnthropicResponse>;
|
|
45
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/llm/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEnF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B,EAAE,MAAM,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/llm/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEnF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B,EAAE,MAAM,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;AAOF,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC/E,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAI7C;AAED,qBAAa,uBAAwB,SAAQ,oBAAoB;gBACnD,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAIxD;AAED,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,MAAM,EAAE,MAAM;aACd,YAAY,EAAE,MAAM;aACpB,eAAe,EAAE,OAAO;gBAFxB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,OAAO;CAK3C;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAExC,aAAa,CAAC,KAAK,EAAE;QACzB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,KAAK,EAAE,aAAa,EAAE,CAAC;QACvB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QACrC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;QACjD,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;KACpD,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAsC/B"}
|
package/dist/llm/anthropic.js
CHANGED
|
@@ -48,6 +48,7 @@ export class AnthropicClient {
|
|
|
48
48
|
cache_control: this.config.cacheTtl === "1h"
|
|
49
49
|
? { type: "ephemeral", ttl: "1h" }
|
|
50
50
|
: { type: "ephemeral" },
|
|
51
|
+
...(supportsThinking(this.config) ? { thinking: { type: "enabled" } } : {}),
|
|
51
52
|
stream: input.stream ?? false,
|
|
52
53
|
}),
|
|
53
54
|
signal: input.signal
|
|
@@ -59,12 +60,12 @@ export class AnthropicClient {
|
|
|
59
60
|
throw new AnthropicApiError(response.status, errorText, response.headers);
|
|
60
61
|
}
|
|
61
62
|
if (input.stream) {
|
|
62
|
-
return readStreamingResponse(response, input.onTextDelta, input.onToolInputDelta);
|
|
63
|
+
return readStreamingResponse(response, input.onTextDelta, input.onToolInputDelta, input.onThinkingDelta);
|
|
63
64
|
}
|
|
64
65
|
return (await response.json());
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
async function readStreamingResponse(response, onTextDelta, onToolInputDelta) {
|
|
68
|
+
async function readStreamingResponse(response, onTextDelta, onToolInputDelta, onThinkingDelta) {
|
|
68
69
|
if (!response.body)
|
|
69
70
|
throw new Error("Anthropic API returned an empty stream body.");
|
|
70
71
|
const reader = response.body.getReader();
|
|
@@ -100,7 +101,7 @@ async function readStreamingResponse(response, onTextDelta, onToolInputDelta) {
|
|
|
100
101
|
stopReason = reason;
|
|
101
102
|
}, (part) => {
|
|
102
103
|
usage = mergeUsage(usage, part);
|
|
103
|
-
}, onTextDelta, onToolInputDelta);
|
|
104
|
+
}, onTextDelta, onToolInputDelta, onThinkingDelta);
|
|
104
105
|
}
|
|
105
106
|
separator = buffer.match(/\r?\n\r?\n/);
|
|
106
107
|
}
|
|
@@ -119,7 +120,7 @@ async function readStreamingResponse(response, onTextDelta, onToolInputDelta) {
|
|
|
119
120
|
stopReason = reason;
|
|
120
121
|
}, (part) => {
|
|
121
122
|
usage = mergeUsage(usage, part);
|
|
122
|
-
}, onTextDelta, onToolInputDelta);
|
|
123
|
+
}, onTextDelta, onToolInputDelta, onThinkingDelta);
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
126
|
if (blocks.size === 0) {
|
|
@@ -161,7 +162,7 @@ function parseStreamEvent(data) {
|
|
|
161
162
|
throw new MalformedStreamError("Model returned malformed JSON in the event stream.", error);
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
|
-
function applyStreamEvent(event, blocks, setResponseId, setStopReason, setUsage, onTextDelta, onToolInputDelta) {
|
|
165
|
+
function applyStreamEvent(event, blocks, setResponseId, setStopReason, setUsage, onTextDelta, onToolInputDelta, onThinkingDelta) {
|
|
165
166
|
if (event.type === "message_start") {
|
|
166
167
|
const message = event.message;
|
|
167
168
|
if (message?.id)
|
|
@@ -186,6 +187,13 @@ function applyStreamEvent(event, blocks, setResponseId, setStopReason, setUsage,
|
|
|
186
187
|
if (contentBlock.type === "text") {
|
|
187
188
|
blocks.set(index, { type: "text", text: contentBlock.text ?? "" });
|
|
188
189
|
}
|
|
190
|
+
else if (contentBlock.type === "thinking") {
|
|
191
|
+
blocks.set(index, {
|
|
192
|
+
type: "thinking",
|
|
193
|
+
thinking: contentBlock.thinking ?? "",
|
|
194
|
+
signature: contentBlock.signature,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
189
197
|
else if (contentBlock.type === "tool_use") {
|
|
190
198
|
const block = {
|
|
191
199
|
type: "tool_use",
|
|
@@ -203,12 +211,26 @@ function applyStreamEvent(event, blocks, setResponseId, setStopReason, setUsage,
|
|
|
203
211
|
const index = Number(event.index);
|
|
204
212
|
const block = blocks.get(index);
|
|
205
213
|
const delta = event.delta;
|
|
206
|
-
if (!
|
|
214
|
+
if (!delta)
|
|
215
|
+
return;
|
|
216
|
+
const publicThinking = delta.type === "summary_delta"
|
|
217
|
+
? delta.summary
|
|
218
|
+
: delta.type === "reasoning_delta" || delta.type === "reasoning_summary_delta"
|
|
219
|
+
? (delta.reasoning_summary ?? delta.reasoning)
|
|
220
|
+
: delta.type === "thinking_delta"
|
|
221
|
+
? delta.thinking
|
|
222
|
+
: undefined;
|
|
223
|
+
if (publicThinking)
|
|
224
|
+
onThinkingDelta?.({ text: publicThinking });
|
|
225
|
+
if (!block)
|
|
207
226
|
return;
|
|
208
227
|
if (block.type === "text" && delta.type === "text_delta" && delta.text) {
|
|
209
228
|
block.text += delta.text;
|
|
210
229
|
onTextDelta?.(delta.text);
|
|
211
230
|
}
|
|
231
|
+
else if (block.type === "thinking" && delta.type === "thinking_delta" && delta.thinking) {
|
|
232
|
+
block.thinking += delta.thinking;
|
|
233
|
+
}
|
|
212
234
|
else if (block.type === "tool_use" && delta.type === "input_json_delta" && delta.partial_json) {
|
|
213
235
|
block.inputJson += delta.partial_json;
|
|
214
236
|
block.detail ??= partialToolDetail(block.inputJson);
|
|
@@ -258,7 +280,7 @@ function mergeUsage(current, part) {
|
|
|
258
280
|
}, { ...next });
|
|
259
281
|
}
|
|
260
282
|
function finalizeStreamBlock(block) {
|
|
261
|
-
if (block.type === "text")
|
|
283
|
+
if (block.type === "text" || block.type === "thinking")
|
|
262
284
|
return block;
|
|
263
285
|
let input = {};
|
|
264
286
|
if (block.inputJson.trim()) {
|
|
@@ -276,3 +298,6 @@ function finalizeStreamBlock(block) {
|
|
|
276
298
|
input,
|
|
277
299
|
};
|
|
278
300
|
}
|
|
301
|
+
function supportsThinking(config) {
|
|
302
|
+
return /(?:^glm-|bigmodel\.cn)/i.test(`${config.model} ${config.baseUrl}`);
|
|
303
|
+
}
|
|
@@ -79,6 +79,13 @@ export declare class QueryEngine {
|
|
|
79
79
|
conversationSize(): number;
|
|
80
80
|
getUsageStats(): UsageStats;
|
|
81
81
|
getCacheMode(): string;
|
|
82
|
+
getRuntimeInfo(): {
|
|
83
|
+
model: string;
|
|
84
|
+
baseUrl: string;
|
|
85
|
+
maxTokens: number;
|
|
86
|
+
contextMaxChars: number;
|
|
87
|
+
workspaceRoot: string;
|
|
88
|
+
};
|
|
82
89
|
close(): Promise<void>;
|
|
83
90
|
ensureSession(title?: string): Promise<SessionSnapshot>;
|
|
84
91
|
saveCurrentSession(): Promise<string | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-engine.d.ts","sourceRoot":"","sources":["../../src/runtime/query-engine.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"query-engine.d.ts","sourceRoot":"","sources":["../../src/runtime/query-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -133,6 +133,15 @@ export class QueryEngine {
|
|
|
133
133
|
}
|
|
134
134
|
return `Anthropic-compatible (${this.options.llmConfig.cacheTtl ?? "5m"} requested)`;
|
|
135
135
|
}
|
|
136
|
+
getRuntimeInfo() {
|
|
137
|
+
return {
|
|
138
|
+
model: this.options.llmConfig.model,
|
|
139
|
+
baseUrl: this.options.llmConfig.baseUrl,
|
|
140
|
+
maxTokens: this.options.llmConfig.maxTokens,
|
|
141
|
+
contextMaxChars: this.options.agentConfig.context.maxChars,
|
|
142
|
+
workspaceRoot: this.options.agentConfig.workspaceRoot,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
136
145
|
async close() {
|
|
137
146
|
await this.mcpManager.closeAll();
|
|
138
147
|
}
|
|
@@ -526,12 +535,18 @@ export class QueryEngine {
|
|
|
526
535
|
streamedText += text;
|
|
527
536
|
this.options.emit({ type: "assistant_delta", text });
|
|
528
537
|
};
|
|
538
|
+
const onThinkingDelta = isSubagent
|
|
539
|
+
? undefined
|
|
540
|
+
: (event) => {
|
|
541
|
+
this.options.emit({ type: "thinking_delta", text: event.text });
|
|
542
|
+
};
|
|
529
543
|
const buildRequest = (useStream) => ({
|
|
530
544
|
system: prompt,
|
|
531
545
|
messages: this.messages,
|
|
532
546
|
tools: toolDefinitions,
|
|
533
547
|
stream: useStream,
|
|
534
548
|
onTextDelta: useStream ? onTextDelta : undefined,
|
|
549
|
+
onThinkingDelta: useStream ? onThinkingDelta : undefined,
|
|
535
550
|
onToolInputDelta: useStream && !isSubagent
|
|
536
551
|
? (event) => {
|
|
537
552
|
const now = Date.now();
|
package/dist/thought-fold.d.ts
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Default: one line “◆ Thought for 0.5s ▸”
|
|
4
|
-
* Expand: /thought or key `t` → show detail lines under it.
|
|
2
|
+
* Bounded terminal preview for model thinking tokens.
|
|
5
3
|
*/
|
|
6
4
|
export type ThoughtBlock = {
|
|
7
|
-
id: string;
|
|
8
5
|
startedAt: number;
|
|
9
6
|
endedAt?: number;
|
|
10
|
-
|
|
11
|
-
lines: string[];
|
|
12
|
-
tools: string[];
|
|
13
|
-
expanded: boolean;
|
|
14
|
-
/** Printed to terminal already (collapsed header) */
|
|
15
|
-
printed: boolean;
|
|
16
|
-
/** true if turn failed */
|
|
7
|
+
thinking: string;
|
|
17
8
|
failed?: boolean;
|
|
18
9
|
};
|
|
19
10
|
export type ThoughtFoldOptions = {
|
|
@@ -21,28 +12,22 @@ export type ThoughtFoldOptions = {
|
|
|
21
12
|
out: (text: string) => void;
|
|
22
13
|
};
|
|
23
14
|
export declare class ThoughtFoldManager {
|
|
24
|
-
private blocks;
|
|
25
15
|
private current;
|
|
26
16
|
private options;
|
|
27
17
|
constructor(options: ThoughtFoldOptions);
|
|
28
18
|
setColor(color: boolean): void;
|
|
29
19
|
/** Start a new thought window for this user turn. */
|
|
30
20
|
beginTurn(): void;
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
appendThinking(text: string): void;
|
|
22
|
+
printPreview(block: ThoughtBlock, maxChars?: number): void;
|
|
33
23
|
/**
|
|
34
|
-
* Finalize current thought and print
|
|
24
|
+
* Finalize current thought and optionally print a failure header.
|
|
35
25
|
* Call before streaming the final answer, or at end of turn.
|
|
36
26
|
*/
|
|
37
|
-
finalizeAndPrint(
|
|
38
|
-
/** Toggle expand/collapse of the last thought (or by id). */
|
|
39
|
-
toggle(id?: string): void;
|
|
40
|
-
expandLast(): void;
|
|
41
|
-
lastSummary(): string | null;
|
|
27
|
+
finalizeAndPrint(_defaultDetail?: string, failed?: boolean, printHeader?: boolean): ThoughtBlock | null;
|
|
42
28
|
clear(): void;
|
|
43
29
|
private duration;
|
|
44
30
|
private printHeader;
|
|
45
|
-
private printExpanded;
|
|
46
31
|
private dim;
|
|
47
32
|
}
|
|
48
33
|
//# sourceMappingURL=thought-fold.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thought-fold.d.ts","sourceRoot":"","sources":["../src/thought-fold.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"thought-fold.d.ts","sourceRoot":"","sources":["../src/thought-fold.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B,CAAC;AAOF,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,EAAE,kBAAkB;IAIvC,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI9B,qDAAqD;IACrD,SAAS,IAAI,IAAI;IAQjB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKlC,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,SAAM,GAAG,IAAI;IAevD;;;OAGG;IACH,gBAAgB,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,MAAM,UAAQ,EAAE,WAAW,UAAQ,GAAG,YAAY,GAAG,IAAI;IAWnG,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,GAAG;CAIZ"}
|
package/dist/thought-fold.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Default: one line “◆ Thought for 0.5s ▸”
|
|
4
|
-
* Expand: /thought or key `t` → show detail lines under it.
|
|
2
|
+
* Bounded terminal preview for model thinking tokens.
|
|
5
3
|
*/
|
|
4
|
+
import { stripTerminalEscapes } from "./trace.js";
|
|
6
5
|
const DIM = "\x1b[90m";
|
|
7
6
|
const RESET = "\x1b[0m";
|
|
8
|
-
const AMBER = "\x1b[38;2;251;191;36m";
|
|
9
7
|
const GREEN = "\x1b[32m";
|
|
10
8
|
const RED = "\x1b[31m";
|
|
11
9
|
export class ThoughtFoldManager {
|
|
12
|
-
blocks = [];
|
|
13
10
|
current = null;
|
|
14
11
|
options;
|
|
15
12
|
constructor(options) {
|
|
@@ -20,103 +17,47 @@ export class ThoughtFoldManager {
|
|
|
20
17
|
}
|
|
21
18
|
/** Start a new thought window for this user turn. */
|
|
22
19
|
beginTurn() {
|
|
20
|
+
if (this.current)
|
|
21
|
+
return;
|
|
23
22
|
this.current = {
|
|
24
|
-
id: `th-${Date.now()}`,
|
|
25
23
|
startedAt: Date.now(),
|
|
26
|
-
|
|
27
|
-
tools: [],
|
|
28
|
-
expanded: false,
|
|
29
|
-
printed: false,
|
|
24
|
+
thinking: "",
|
|
30
25
|
};
|
|
31
26
|
}
|
|
32
|
-
|
|
33
|
-
if (!this.current)
|
|
34
|
-
return;
|
|
35
|
-
const t = line.trim();
|
|
36
|
-
if (!t)
|
|
37
|
-
return;
|
|
38
|
-
// de-dupe consecutive
|
|
39
|
-
if (this.current.lines[this.current.lines.length - 1] === t)
|
|
27
|
+
appendThinking(text) {
|
|
28
|
+
if (!this.current || !text)
|
|
40
29
|
return;
|
|
41
|
-
this.current.
|
|
30
|
+
this.current.thinking = `${this.current.thinking}${text}`.slice(-6000);
|
|
42
31
|
}
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
printPreview(block, maxChars = 300) {
|
|
33
|
+
const characters = Array.from(stripTerminalEscapes(block.thinking).replace(/\s+/g, " ").trim());
|
|
34
|
+
if (!characters.length)
|
|
45
35
|
return;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
const visible = characters.slice(0, maxChars);
|
|
37
|
+
for (let index = 0; index < visible.length; index += 100) {
|
|
38
|
+
const line = visible.slice(index, index + 100).join("");
|
|
39
|
+
this.options.out(this.dim(`${index === 0 ? " └ " : " "}${line}\n`));
|
|
40
|
+
}
|
|
41
|
+
if (characters.length > maxChars) {
|
|
42
|
+
this.options.out(this.dim(" … more hidden\n"));
|
|
43
|
+
}
|
|
49
44
|
}
|
|
50
45
|
/**
|
|
51
|
-
* Finalize current thought and print
|
|
46
|
+
* Finalize current thought and optionally print a failure header.
|
|
52
47
|
* Call before streaming the final answer, or at end of turn.
|
|
53
48
|
*/
|
|
54
|
-
finalizeAndPrint(
|
|
49
|
+
finalizeAndPrint(_defaultDetail, failed = false, printHeader = false) {
|
|
55
50
|
if (!this.current)
|
|
56
51
|
return null;
|
|
57
|
-
if (this.current.printed)
|
|
58
|
-
return this.current;
|
|
59
52
|
this.current.endedAt = Date.now();
|
|
60
53
|
this.current.failed = failed;
|
|
61
|
-
if (
|
|
62
|
-
this.current.lines.push(defaultDetail);
|
|
63
|
-
}
|
|
64
|
-
if (this.current.lines.length === 0) {
|
|
65
|
-
this.current.lines.push("Processed the request and prepared a reply.");
|
|
66
|
-
}
|
|
67
|
-
this.blocks.push(this.current);
|
|
68
|
-
// Only the most recent block is ever toggled/expanded; cap history so a long-lived
|
|
69
|
-
// interactive session doesn't grow this array (and its retained lines) without bound.
|
|
70
|
-
if (this.blocks.length > 50)
|
|
71
|
-
this.blocks.splice(0, this.blocks.length - 50);
|
|
72
|
-
if (printHeader) {
|
|
54
|
+
if (printHeader)
|
|
73
55
|
this.printHeader(this.current);
|
|
74
|
-
this.current.printed = true;
|
|
75
|
-
}
|
|
76
56
|
const done = this.current;
|
|
77
57
|
this.current = null;
|
|
78
58
|
return done;
|
|
79
59
|
}
|
|
80
|
-
/** Toggle expand/collapse of the last thought (or by id). */
|
|
81
|
-
toggle(id) {
|
|
82
|
-
const block = id
|
|
83
|
-
? this.blocks.find((b) => b.id === id)
|
|
84
|
-
: this.blocks[this.blocks.length - 1];
|
|
85
|
-
if (!block) {
|
|
86
|
-
this.options.out(this.dim("(no thought to expand yet)\n"));
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
block.expanded = !block.expanded;
|
|
90
|
-
if (block.expanded) {
|
|
91
|
-
this.printExpanded(block);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
this.options.out(this.dim(" (thought collapsed — /thought to expand again)\n"));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
expandLast() {
|
|
98
|
-
const block = this.blocks[this.blocks.length - 1];
|
|
99
|
-
if (!block) {
|
|
100
|
-
this.options.out(this.dim("(no thought to expand yet)\n"));
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (!block.expanded) {
|
|
104
|
-
block.expanded = true;
|
|
105
|
-
this.printExpanded(block);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
this.printExpanded(block); // re-print
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
lastSummary() {
|
|
112
|
-
const b = this.blocks[this.blocks.length - 1];
|
|
113
|
-
if (!b)
|
|
114
|
-
return null;
|
|
115
|
-
const sec = ((b.endedAt ?? Date.now()) - b.startedAt) / 1000;
|
|
116
|
-
return `Thought for ${sec.toFixed(1)}s · ${b.tools.length} tools · ${b.expanded ? "expanded" : "collapsed"}`;
|
|
117
|
-
}
|
|
118
60
|
clear() {
|
|
119
|
-
this.blocks = [];
|
|
120
61
|
this.current = null;
|
|
121
62
|
}
|
|
122
63
|
duration(block) {
|
|
@@ -124,29 +65,13 @@ export class ThoughtFoldManager {
|
|
|
124
65
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
125
66
|
}
|
|
126
67
|
printHeader(block) {
|
|
127
|
-
const arrow = block.expanded ? "▾" : "▸";
|
|
128
|
-
// CC style: green ● success, red ● failure (not amber while done)
|
|
129
68
|
const color = block.failed ? RED : GREEN;
|
|
130
69
|
const dot = this.options.color ? `${color}●${RESET}` : "●";
|
|
131
70
|
const label = block.failed
|
|
132
71
|
? `Failed · ${this.duration(block)}`
|
|
133
72
|
: `Thought for ${this.duration(block)}`;
|
|
134
73
|
const labelPainted = this.options.color ? `${color}${label}${RESET}` : label;
|
|
135
|
-
|
|
136
|
-
this.options.out(`\n${dot} ${labelPainted}${hint}\n`);
|
|
137
|
-
}
|
|
138
|
-
printExpanded(block) {
|
|
139
|
-
const color = block.failed ? RED : GREEN;
|
|
140
|
-
const dot = this.options.color ? `${color}●${RESET}` : "●";
|
|
141
|
-
const head = block.failed ? `Failed · ${this.duration(block)}` : `Thought for ${this.duration(block)}`;
|
|
142
|
-
this.options.out(`\n${dot} ${head} ▾\n`);
|
|
143
|
-
if (block.tools.length) {
|
|
144
|
-
this.options.out(this.dim(` tools: ${block.tools.join(", ")}\n`));
|
|
145
|
-
}
|
|
146
|
-
for (const line of block.lines) {
|
|
147
|
-
this.options.out(this.dim(` │ ${line}\n`));
|
|
148
|
-
}
|
|
149
|
-
this.options.out(this.dim(" └ /thought to collapse\n\n"));
|
|
74
|
+
this.options.out(`\n${dot} ${labelPainted}\n`);
|
|
150
75
|
}
|
|
151
76
|
dim(text) {
|
|
152
77
|
if (!this.options.color)
|