@apolloyh/apollo-agent 0.1.11 → 0.2.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/.env.example +7 -0
- package/dist/brand.d.ts +2 -2
- package/dist/brand.js +2 -2
- package/dist/config.d.ts +4 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +28 -15
- package/dist/coordinator/workflow.d.ts.map +1 -1
- package/dist/coordinator/workflow.js +6 -5
- package/dist/goal/goal-mode.d.ts +0 -4
- package/dist/goal/goal-mode.d.ts.map +1 -1
- package/dist/goal/goal-mode.js +6 -5
- package/dist/index.js +17 -12
- package/dist/llm/anthropic.d.ts +18 -11
- package/dist/llm/anthropic.d.ts.map +1 -1
- package/dist/llm/anthropic.js +6 -3
- package/dist/llm/openai.d.ts +8 -0
- package/dist/llm/openai.d.ts.map +1 -0
- package/dist/llm/openai.js +214 -0
- package/dist/runtime/permissions.d.ts.map +1 -1
- package/dist/runtime/permissions.js +5 -4
- package/dist/runtime/query-engine.d.ts +4 -1
- package/dist/runtime/query-engine.d.ts.map +1 -1
- package/dist/runtime/query-engine.js +20 -7
- package/dist/sdk.d.ts +6 -2
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +4 -1
- package/dist/status-ui.d.ts +1 -10
- package/dist/status-ui.d.ts.map +1 -1
- package/dist/status-ui.js +9 -7
- package/dist/terminal-theme.d.ts +45 -0
- package/dist/terminal-theme.d.ts.map +1 -0
- package/dist/terminal-theme.js +47 -0
- package/dist/thought-fold.d.ts.map +1 -1
- package/dist/thought-fold.js +3 -5
- package/dist/tools/builtin.js +1 -1
- package/dist/tools/registry.d.ts +1 -0
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +3 -0
- package/dist/trace.d.ts +2 -0
- package/dist/trace.d.ts.map +1 -1
- package/dist/trace.js +56 -30
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/guide.md +13 -2
- package/docs/sdk.md +48 -0
- package/package.json +2 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { ProviderApiError, MalformedStreamError, MalformedToolInputError, } from "./anthropic.js";
|
|
2
|
+
export class OpenAIClient {
|
|
3
|
+
config;
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
}
|
|
7
|
+
async createMessage(input) {
|
|
8
|
+
const response = await fetch(openAIEndpoint(this.config.baseUrl), {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${this.config.authToken}` },
|
|
11
|
+
body: JSON.stringify({
|
|
12
|
+
model: this.config.model,
|
|
13
|
+
messages: toOpenAIMessages(input.system, input.messages),
|
|
14
|
+
[this.config.openaiMaxTokensParam ?? "max_tokens"]: this.config.maxTokens,
|
|
15
|
+
...(input.tools.length ? { tools: input.tools.map(toOpenAITool), tool_choice: "auto" } : {}),
|
|
16
|
+
stream: input.stream ?? false,
|
|
17
|
+
...(input.stream ? { stream_options: { include_usage: true } } : {}),
|
|
18
|
+
}),
|
|
19
|
+
signal: input.signal
|
|
20
|
+
? AbortSignal.any([input.signal, AbortSignal.timeout(normalizeTimeout(this.config.timeoutMs))])
|
|
21
|
+
: AbortSignal.timeout(normalizeTimeout(this.config.timeoutMs)),
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok)
|
|
24
|
+
throw new ProviderApiError(response.status, await response.text(), response.headers);
|
|
25
|
+
return input.stream ? readOpenAIStream(response, input) : normalizeOpenAIResponse(await response.json());
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function openAIEndpoint(baseUrl) {
|
|
29
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
30
|
+
if (/\/chat\/completions$/i.test(base))
|
|
31
|
+
return base;
|
|
32
|
+
return `${base}${/\/v1$/i.test(base) ? "" : "/v1"}/chat/completions`;
|
|
33
|
+
}
|
|
34
|
+
function toOpenAITool(tool) {
|
|
35
|
+
return { type: "function", function: { name: tool.name, description: tool.description, parameters: tool.input_schema } };
|
|
36
|
+
}
|
|
37
|
+
function toOpenAIMessages(system, messages) {
|
|
38
|
+
const output = system ? [{ role: "system", content: system }] : [];
|
|
39
|
+
for (const message of messages) {
|
|
40
|
+
if (typeof message.content === "string") {
|
|
41
|
+
output.push({ role: message.role, content: message.content });
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (message.role === "assistant") {
|
|
45
|
+
const text = message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
46
|
+
const toolCalls = message.content.filter((block) => block.type === "tool_use").map((block) => ({
|
|
47
|
+
id: block.id,
|
|
48
|
+
type: "function",
|
|
49
|
+
function: { name: block.name, arguments: JSON.stringify(block.input) },
|
|
50
|
+
}));
|
|
51
|
+
output.push({ role: "assistant", content: text || null, ...(toolCalls.length ? { tool_calls: toolCalls } : {}) });
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const block of message.content) {
|
|
55
|
+
if (block.type === "tool_result")
|
|
56
|
+
output.push({ role: "tool", tool_call_id: block.tool_use_id, content: block.is_error ? `[error] ${block.content}` : block.content });
|
|
57
|
+
}
|
|
58
|
+
const text = message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
59
|
+
if (text)
|
|
60
|
+
output.push({ role: "user", content: text });
|
|
61
|
+
}
|
|
62
|
+
return output;
|
|
63
|
+
}
|
|
64
|
+
function normalizeOpenAIResponse(value) {
|
|
65
|
+
const source = value;
|
|
66
|
+
const choice = source.choices?.[0];
|
|
67
|
+
if (!choice?.message)
|
|
68
|
+
throw new MalformedStreamError("OpenAI API returned no assistant message.");
|
|
69
|
+
return {
|
|
70
|
+
id: source.id ?? "",
|
|
71
|
+
type: "message",
|
|
72
|
+
role: "assistant",
|
|
73
|
+
content: normalizeOpenAIContent(choice.message),
|
|
74
|
+
stop_reason: normalizeStopReason(choice.finish_reason),
|
|
75
|
+
usage: normalizeUsage(source.usage),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function readOpenAIStream(response, input) {
|
|
79
|
+
if (!response.body)
|
|
80
|
+
throw new MalformedStreamError("OpenAI API returned an empty stream body.");
|
|
81
|
+
const reader = response.body.getReader();
|
|
82
|
+
const decoder = new TextDecoder();
|
|
83
|
+
const tools = new Map();
|
|
84
|
+
let buffer = "", id = "", text = "", thinking = "", stopReason, usage, ended = false;
|
|
85
|
+
const apply = (data) => {
|
|
86
|
+
if (!data || data === "[DONE]")
|
|
87
|
+
return;
|
|
88
|
+
let event;
|
|
89
|
+
try {
|
|
90
|
+
event = JSON.parse(data);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new MalformedStreamError("OpenAI API returned malformed JSON in the event stream.", error);
|
|
94
|
+
}
|
|
95
|
+
id ||= event.id ?? "";
|
|
96
|
+
usage = normalizeUsage(event.usage) ?? usage;
|
|
97
|
+
const choice = event.choices?.[0];
|
|
98
|
+
const delta = choice?.delta;
|
|
99
|
+
if (choice?.finish_reason)
|
|
100
|
+
stopReason = normalizeStopReason(choice.finish_reason);
|
|
101
|
+
if (!delta)
|
|
102
|
+
return;
|
|
103
|
+
const reasoning = delta.reasoning_content ?? delta.reasoning;
|
|
104
|
+
if (reasoning) {
|
|
105
|
+
thinking += reasoning;
|
|
106
|
+
input.onThinkingDelta?.({ text: reasoning });
|
|
107
|
+
}
|
|
108
|
+
if (delta.content) {
|
|
109
|
+
text += delta.content;
|
|
110
|
+
input.onTextDelta?.(delta.content);
|
|
111
|
+
}
|
|
112
|
+
for (const part of delta.tool_calls ?? []) {
|
|
113
|
+
const index = part.index ?? 0;
|
|
114
|
+
const tool = tools.get(index) ?? { id: "", name: "", arguments: "" };
|
|
115
|
+
const wasUnnamed = !tool.name;
|
|
116
|
+
tool.id ||= part.id ?? "";
|
|
117
|
+
tool.name += part.function?.name ?? "";
|
|
118
|
+
tool.arguments += part.function?.arguments ?? "";
|
|
119
|
+
tools.set(index, tool);
|
|
120
|
+
if (wasUnnamed && tool.name)
|
|
121
|
+
input.onToolInputDelta?.({ bytes: 0, tool: tool.name });
|
|
122
|
+
if (part.function?.arguments)
|
|
123
|
+
input.onToolInputDelta?.({ bytes: tool.arguments.length, tool: tool.name || undefined, detail: partialToolDetail(tool.arguments) });
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
try {
|
|
127
|
+
for (;;) {
|
|
128
|
+
const chunk = await reader.read();
|
|
129
|
+
if (chunk.done) {
|
|
130
|
+
ended = true;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
134
|
+
let separator = buffer.match(/\r?\n\r?\n/);
|
|
135
|
+
while (separator?.index !== undefined) {
|
|
136
|
+
const raw = buffer.slice(0, separator.index);
|
|
137
|
+
buffer = buffer.slice(separator.index + separator[0].length);
|
|
138
|
+
apply(parseSseData(raw));
|
|
139
|
+
separator = buffer.match(/\r?\n\r?\n/);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
buffer += decoder.decode();
|
|
143
|
+
if (buffer.trim())
|
|
144
|
+
apply(parseSseData(buffer));
|
|
145
|
+
if (!text && !thinking && !tools.size)
|
|
146
|
+
throw new MalformedStreamError("OpenAI API returned an empty or incomplete event stream.");
|
|
147
|
+
const content = [];
|
|
148
|
+
if (thinking)
|
|
149
|
+
content.push({ type: "thinking", thinking });
|
|
150
|
+
if (text)
|
|
151
|
+
content.push({ type: "text", text });
|
|
152
|
+
for (const [, tool] of [...tools].sort(([a], [b]) => a - b))
|
|
153
|
+
content.push(toToolUse(tool));
|
|
154
|
+
return { id, type: "message", role: "assistant", content, stop_reason: stopReason, usage };
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
if (!ended)
|
|
158
|
+
await reader.cancel().catch(() => undefined);
|
|
159
|
+
reader.releaseLock();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function normalizeOpenAIContent(message) {
|
|
163
|
+
const content = [];
|
|
164
|
+
const reasoning = message.reasoning_content ?? message.reasoning;
|
|
165
|
+
if (reasoning)
|
|
166
|
+
content.push({ type: "thinking", thinking: reasoning });
|
|
167
|
+
if (message.content)
|
|
168
|
+
content.push({ type: "text", text: message.content });
|
|
169
|
+
for (const [index, call] of (message.tool_calls ?? []).entries())
|
|
170
|
+
content.push(toToolUse({ id: call.id ?? `call-${index}`, name: call.function?.name ?? "", arguments: call.function?.arguments ?? "" }));
|
|
171
|
+
return content;
|
|
172
|
+
}
|
|
173
|
+
function toToolUse(tool) {
|
|
174
|
+
try {
|
|
175
|
+
return { type: "tool_use", id: tool.id, name: tool.name, input: tool.arguments.trim() ? JSON.parse(tool.arguments) : {} };
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
throw new MalformedToolInputError(tool.name, tool.arguments.length, error);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function normalizeUsage(value) {
|
|
182
|
+
if (!value || typeof value !== "object")
|
|
183
|
+
return undefined;
|
|
184
|
+
const usage = value;
|
|
185
|
+
if (typeof usage.prompt_tokens !== "number" && typeof usage.completion_tokens !== "number")
|
|
186
|
+
return undefined;
|
|
187
|
+
return { input_tokens: usage.prompt_tokens ?? 0, output_tokens: usage.completion_tokens ?? 0, cache_creation_input_tokens: 0, cache_read_input_tokens: usage.prompt_tokens_details?.cached_tokens ?? 0 };
|
|
188
|
+
}
|
|
189
|
+
function normalizeStopReason(reason) {
|
|
190
|
+
if (reason === "tool_calls" || reason === "function_call")
|
|
191
|
+
return "tool_use";
|
|
192
|
+
if (reason === "length")
|
|
193
|
+
return "max_tokens";
|
|
194
|
+
if (reason === "stop")
|
|
195
|
+
return "end_turn";
|
|
196
|
+
return reason;
|
|
197
|
+
}
|
|
198
|
+
function parseSseData(raw) {
|
|
199
|
+
return raw.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n").trim();
|
|
200
|
+
}
|
|
201
|
+
function partialToolDetail(input) {
|
|
202
|
+
const match = input.slice(0, 8192).match(/"(?:path|file_path|command|query|url|description)"\s*:\s*"((?:\\.|[^"\\])*)"/);
|
|
203
|
+
if (!match?.[1])
|
|
204
|
+
return undefined;
|
|
205
|
+
try {
|
|
206
|
+
return JSON.parse(`"${match[1]}"`);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function normalizeTimeout(value) {
|
|
213
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 300000;
|
|
214
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/runtime/permissions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/runtime/permissions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7F,KAAK,kBAAkB,GAAG;IACxB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC5C,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,EACpC,OAAO,GAAE,kBAAuB,GAC/B,gBAAgB,CA8BlB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,UAAQ,GAAG,MAAM,CAa7G"}
|
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import readline from "node:readline/promises";
|
|
4
4
|
import { stdin as input, stderr as output } from "node:process";
|
|
5
|
+
import { TERMINAL_ANSI } from "../terminal-theme.js";
|
|
5
6
|
import { stringify } from "../utils.js";
|
|
6
7
|
export function createCliApprovalProvider(config, emit, assumeYes, options = {}) {
|
|
7
8
|
return async (request) => {
|
|
@@ -126,11 +127,11 @@ function paint(value, color, enabled) {
|
|
|
126
127
|
if (!enabled || color === "normal")
|
|
127
128
|
return value;
|
|
128
129
|
const code = color === "dim"
|
|
129
|
-
?
|
|
130
|
+
? TERMINAL_ANSI.inactive
|
|
130
131
|
: color === "yellow"
|
|
131
|
-
?
|
|
132
|
+
? TERMINAL_ANSI.warning
|
|
132
133
|
: color === "yellowBold"
|
|
133
|
-
?
|
|
134
|
-
:
|
|
134
|
+
? `\x1b[1m${TERMINAL_ANSI.warning}`
|
|
135
|
+
: `\x1b[1m${TERMINAL_ANSI.permission}`;
|
|
135
136
|
return `${code}${value}\x1b[0m`;
|
|
136
137
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentConfig, ApprovalProvider, AskUserFn, LlmConfig, Message, SubagentConfig, TraceSink } from "../types.js";
|
|
1
|
+
import type { AgentConfig, ApprovalProvider, AskUserFn, LlmConfig, Message, SubagentConfig, TraceSink, ToolDefinition } from "../types.js";
|
|
2
2
|
import { type AnthropicUsage } from "../llm/anthropic.js";
|
|
3
3
|
import { type PlanState } from "../plan/plan-mode.js";
|
|
4
4
|
import { type WorkflowState } from "../coordinator/workflow.js";
|
|
@@ -15,6 +15,8 @@ export type QueryEngineOptions = {
|
|
|
15
15
|
depth?: number;
|
|
16
16
|
askUser?: AskUserFn;
|
|
17
17
|
sessionId?: string;
|
|
18
|
+
extraTools?: ToolDefinition[];
|
|
19
|
+
memoryEnabled?: boolean;
|
|
18
20
|
};
|
|
19
21
|
export type UsageCategory = "main" | "task" | "compaction";
|
|
20
22
|
type UsageCounters = AnthropicUsage & {
|
|
@@ -83,6 +85,7 @@ export declare class QueryEngine {
|
|
|
83
85
|
model: string;
|
|
84
86
|
baseUrl: string;
|
|
85
87
|
maxTokens: number;
|
|
88
|
+
openaiMaxTokensParam: "max_tokens" | "max_completion_tokens" | undefined;
|
|
86
89
|
contextMaxChars: number;
|
|
87
90
|
workspaceRoot: string;
|
|
88
91
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-engine.d.ts","sourceRoot":"","sources":["../../src/runtime/query-engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EAEX,gBAAgB,EAChB,SAAS,EAET,SAAS,EACT,OAAO,EACP,cAAc,EAEd,SAAS,
|
|
1
|
+
{"version":3,"file":"query-engine.d.ts","sourceRoot":"","sources":["../../src/runtime/query-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { AnthropicClient, MalformedStreamError, ProviderApiError, } from "../llm/anthropic.js";
|
|
3
|
+
import { OpenAIClient } from "../llm/openai.js";
|
|
3
4
|
import { ContextManager, isContextSummary } from "./context.js";
|
|
4
5
|
import { buildCompactionTranscript, COMPACTION_SYSTEM_PROMPT, normalizeCompactionSummary, } from "./compaction.js";
|
|
5
6
|
import { createCliApprovalProvider } from "./permissions.js";
|
|
@@ -68,7 +69,9 @@ export class QueryEngine {
|
|
|
68
69
|
activeTurnAbort;
|
|
69
70
|
constructor(options) {
|
|
70
71
|
this.options = options;
|
|
71
|
-
this.client =
|
|
72
|
+
this.client = options.llmConfig.protocol === "openai"
|
|
73
|
+
? new OpenAIClient(options.llmConfig)
|
|
74
|
+
: new AnthropicClient(options.llmConfig);
|
|
72
75
|
this.contextManager = new ContextManager(options.agentConfig.context, options.emit);
|
|
73
76
|
this.skillManager = new SkillManager(options.agentConfig);
|
|
74
77
|
this.mcpManager = new McpManager(options.agentConfig);
|
|
@@ -138,6 +141,7 @@ export class QueryEngine {
|
|
|
138
141
|
model: this.options.llmConfig.model,
|
|
139
142
|
baseUrl: this.options.llmConfig.baseUrl,
|
|
140
143
|
maxTokens: this.options.llmConfig.maxTokens,
|
|
144
|
+
openaiMaxTokensParam: this.options.llmConfig.openaiMaxTokensParam,
|
|
141
145
|
contextMaxChars: this.options.agentConfig.context.maxChars,
|
|
142
146
|
workspaceRoot: this.options.agentConfig.workspaceRoot,
|
|
143
147
|
};
|
|
@@ -482,12 +486,19 @@ export class QueryEngine {
|
|
|
482
486
|
allowedTools: this.options.subagent?.tools,
|
|
483
487
|
runTask: isSubagent ? undefined : (agent, prompt, emit) => this.runTask(agent, prompt, emit),
|
|
484
488
|
});
|
|
489
|
+
if (this.options.memoryEnabled === false) {
|
|
490
|
+
registry.remove("memory_search");
|
|
491
|
+
registry.remove("memory_save");
|
|
492
|
+
registry.remove("memory_list");
|
|
493
|
+
}
|
|
494
|
+
for (const tool of this.options.extraTools ?? [])
|
|
495
|
+
registry.register(tool);
|
|
485
496
|
registry.setHooks(this.hooks);
|
|
486
497
|
registry.setPlanMode(this.mode === "plan");
|
|
487
498
|
const [availableSkills, matchedSkills, memBlock] = await Promise.all([
|
|
488
499
|
this.skillManager.metadata(),
|
|
489
500
|
this.matchedSkillsForPrompt(input),
|
|
490
|
-
isSubagent ? Promise.resolve("") : memoryContextBlock(this.options.agentConfig.workspaceRoot, input),
|
|
501
|
+
isSubagent || this.options.memoryEnabled === false ? Promise.resolve("") : memoryContextBlock(this.options.agentConfig.workspaceRoot, input),
|
|
491
502
|
]);
|
|
492
503
|
const modeExtra = this.runtimeModeContext();
|
|
493
504
|
const memoryExtra = this.takeMemoryContext(memBlock);
|
|
@@ -669,6 +680,7 @@ export class QueryEngine {
|
|
|
669
680
|
isError: result.isError,
|
|
670
681
|
content: truncate(result.content, 1000),
|
|
671
682
|
fileChange: result.fileChange,
|
|
683
|
+
artifacts: result.artifacts,
|
|
672
684
|
});
|
|
673
685
|
// refresh plan after write
|
|
674
686
|
if (toolUse.name === "write_file" && this.mode === "plan") {
|
|
@@ -942,6 +954,7 @@ export class QueryEngine {
|
|
|
942
954
|
}
|
|
943
955
|
configFingerprint() {
|
|
944
956
|
return fingerprint({
|
|
957
|
+
protocol: this.options.llmConfig.protocol ?? "anthropic",
|
|
945
958
|
baseUrl: this.options.llmConfig.baseUrl.replace(/\/$/, ""),
|
|
946
959
|
model: this.options.llmConfig.model,
|
|
947
960
|
maxTokens: this.options.llmConfig.maxTokens,
|
|
@@ -1101,7 +1114,7 @@ function fingerprint(value) {
|
|
|
1101
1114
|
return createHash("sha256").update(content).digest("hex").slice(0, 12);
|
|
1102
1115
|
}
|
|
1103
1116
|
function isTransientLlmError(error) {
|
|
1104
|
-
if (error instanceof
|
|
1117
|
+
if (error instanceof ProviderApiError) {
|
|
1105
1118
|
const shouldRetry = error.responseHeaders.get("x-should-retry");
|
|
1106
1119
|
if (shouldRetry === "false")
|
|
1107
1120
|
return false;
|
|
@@ -1122,7 +1135,7 @@ function isTransientLlmError(error) {
|
|
|
1122
1135
|
return ["ECONNRESET", "ECONNREFUSED", "EPIPE", "ETIMEDOUT", "ENETUNREACH", "EAI_AGAIN"].includes(code ?? "");
|
|
1123
1136
|
}
|
|
1124
1137
|
function isContextOverflowError(error) {
|
|
1125
|
-
if (!(error instanceof
|
|
1138
|
+
if (!(error instanceof ProviderApiError))
|
|
1126
1139
|
return false;
|
|
1127
1140
|
if (error.status === 413)
|
|
1128
1141
|
return true;
|
|
@@ -1132,7 +1145,7 @@ function isContextOverflowError(error) {
|
|
|
1132
1145
|
.test(error.responseBody);
|
|
1133
1146
|
}
|
|
1134
1147
|
function retryDelayMs(error, attempt) {
|
|
1135
|
-
if (error instanceof
|
|
1148
|
+
if (error instanceof ProviderApiError) {
|
|
1136
1149
|
const retryAfter = error.responseHeaders.get("retry-after");
|
|
1137
1150
|
if (retryAfter) {
|
|
1138
1151
|
const seconds = Number(retryAfter);
|
|
@@ -1149,7 +1162,7 @@ function retryDelayMs(error, attempt) {
|
|
|
1149
1162
|
return Math.round(base + Math.random() * base * 0.25);
|
|
1150
1163
|
}
|
|
1151
1164
|
function retryReason(error) {
|
|
1152
|
-
if (error instanceof
|
|
1165
|
+
if (error instanceof ProviderApiError)
|
|
1153
1166
|
return `provider API ${error.status}`;
|
|
1154
1167
|
if (error instanceof Error && error.name === "TimeoutError")
|
|
1155
1168
|
return "provider request timed out";
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { QueryEngine, type QueryEngineOptions } from "./runtime/query-engine.js";
|
|
2
|
-
import type { AgentConfig, ApprovalProvider, AskUserFn, LlmConfig, TraceSink } from "./types.js";
|
|
2
|
+
import type { AgentConfig, ApprovalProvider, AskUserFn, LlmConfig, ToolDefinition, TraceSink } from "./types.js";
|
|
3
3
|
export type CreateQueryEngineOptions = {
|
|
4
4
|
configPath?: string;
|
|
5
|
+
configMode?: "layered" | "isolated";
|
|
6
|
+
workspaceRoot?: string;
|
|
5
7
|
envPath?: string;
|
|
6
8
|
agentConfig?: AgentConfig;
|
|
7
9
|
llmConfig?: LlmConfig;
|
|
@@ -11,6 +13,8 @@ export type CreateQueryEngineOptions = {
|
|
|
11
13
|
onEvent?: TraceSink;
|
|
12
14
|
askUser?: AskUserFn;
|
|
13
15
|
sessionId?: string;
|
|
16
|
+
extraTools?: ToolDefinition[];
|
|
17
|
+
memoryEnabled?: boolean;
|
|
14
18
|
};
|
|
15
19
|
export type RunAgentTurnOptions = CreateQueryEngineOptions & {
|
|
16
20
|
input: string;
|
|
@@ -29,5 +33,5 @@ export { createWorkflow, workflowStatusBar } from "./coordinator/workflow.js";
|
|
|
29
33
|
export { skillifySession } from "./skillify/skillify.js";
|
|
30
34
|
export { saveMemory, searchMemories, listMemories } from "./memory/memdir.js";
|
|
31
35
|
export { listSessions, loadSession, loadLatestSession } from "./session/store.js";
|
|
32
|
-
export type { AgentConfig, AnthropicTool, ApprovalProvider, AskUserFn, FileChangeDisplay, LlmConfig, Message, SubagentConfig, ToolDefinition, ToolResult, TraceEvent, } from "./types.js";
|
|
36
|
+
export type { AgentConfig, AnthropicTool, ApprovalProvider, AskUserFn, FileChangeDisplay, LlmConfig, JsonObject, Message, SubagentConfig, ToolDefinition, ToolArtifact, ToolResult, TraceEvent, } from "./types.js";
|
|
33
37
|
//# sourceMappingURL=sdk.d.ts.map
|
package/dist/sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAc,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAc,SAAS,EAAE,MAAM,YAAY,CAAC;AAE7H,MAAM,MAAM,wBAAwB,GAAG;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,MAAM,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,GAAG;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,WAAW,CAAC,CAqBpG;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAO5F;AAID,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAClF,YAAY,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,OAAO,EACP,cAAc,EACd,cAAc,EACd,YAAY,EACZ,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/dist/sdk.js
CHANGED
|
@@ -3,7 +3,8 @@ import { QueryEngine } from "./runtime/query-engine.js";
|
|
|
3
3
|
export async function createQueryEngine(options = {}) {
|
|
4
4
|
if (options.envPath || !options.llmConfig)
|
|
5
5
|
loadEnvFile(options.envPath);
|
|
6
|
-
const
|
|
6
|
+
const loadedConfig = options.agentConfig ?? (await loadAgentConfig(options.configPath, { isolated: options.configMode === "isolated" }));
|
|
7
|
+
const agentConfig = options.workspaceRoot ? { ...loadedConfig, workspaceRoot: options.workspaceRoot } : loadedConfig;
|
|
7
8
|
const llmConfig = options.llmConfig ?? loadLlmConfig();
|
|
8
9
|
const engine = new QueryEngine({
|
|
9
10
|
agentConfig,
|
|
@@ -14,6 +15,8 @@ export async function createQueryEngine(options = {}) {
|
|
|
14
15
|
stream: options.stream,
|
|
15
16
|
askUser: options.askUser,
|
|
16
17
|
sessionId: options.sessionId,
|
|
18
|
+
extraTools: options.extraTools,
|
|
19
|
+
memoryEnabled: options.memoryEnabled,
|
|
17
20
|
});
|
|
18
21
|
if (options.sessionId) {
|
|
19
22
|
await engine.resumeSession(options.sessionId);
|
package/dist/status-ui.d.ts
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code–style waiting indicator + outcome dots.
|
|
3
|
-
*
|
|
4
|
-
* Running: morphing sparkle · ✢ ✳ ✶ ✻ ✽ + shimmer label
|
|
5
|
-
* Success: green ● (CC uses ● / ⏺ for completed status)
|
|
6
|
-
* Failure: red ●
|
|
7
|
-
*
|
|
8
|
-
* Refs: SpinnerGlyph (stalled→error red), figures BLACK_CIRCLE, BriefIdleStatus ●
|
|
9
|
-
*/
|
|
10
1
|
/** Filled circle — CC completed / idle status glyph. */
|
|
11
2
|
export declare const STATUS_DOT = "\u25CF";
|
|
12
3
|
export declare function spinnerGlyph(frame: number): string;
|
|
13
4
|
export declare function glimmerIndex(frame: number, messageWidth: number): number;
|
|
14
5
|
export declare function shimmerLabel(label: string, frame: number, useColor: boolean): string;
|
|
15
6
|
export declare function formatSpinnerGlyph(frame: number, useColor: boolean): string;
|
|
16
|
-
export declare const STATUS_TICK_MS =
|
|
7
|
+
export declare const STATUS_TICK_MS = 140;
|
|
17
8
|
export declare function formatWaitLine(options: {
|
|
18
9
|
frame: number;
|
|
19
10
|
label: string;
|
package/dist/status-ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-ui.d.ts","sourceRoot":"","sources":["../src/status-ui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status-ui.d.ts","sourceRoot":"","sources":["../src/status-ui.ts"],"names":[],"mappings":"AA6CA,wDAAwD;AACxD,eAAO,MAAM,UAAU,WAAM,CAAC;AAE9B,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAKxE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAkBpF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAO3E;AAED,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,CAKT;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC;IAC7B,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,CAcT;AAeD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAErE;AACD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjD"}
|
package/dist/status-ui.js
CHANGED
|
@@ -7,18 +7,20 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Refs: SpinnerGlyph (stalled→error red), figures BLACK_CIRCLE, BriefIdleStatus ●
|
|
9
9
|
*/
|
|
10
|
+
import { TERMINAL_DARK_RGB } from "./terminal-theme.js";
|
|
10
11
|
const SPINNER_CHARS = ["·", "✢", "✳", "✶", "✻", "✽"];
|
|
11
12
|
const SPINNER_FRAMES = [
|
|
12
13
|
...SPINNER_CHARS,
|
|
13
14
|
...[...SPINNER_CHARS].reverse(),
|
|
14
15
|
];
|
|
15
|
-
const GLYPH_EVERY =
|
|
16
|
+
const GLYPH_EVERY = 1;
|
|
16
17
|
const SHIMMER_EVERY = 4;
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
18
|
+
const asRgb = (value) => ({ r: value[0], g: value[1], b: value[2] });
|
|
19
|
+
const BASE_RGB = asRgb(TERMINAL_DARK_RGB.spinnerBase);
|
|
20
|
+
const SHIMMER_RGB = asRgb(TERMINAL_DARK_RGB.spinnerShimmer);
|
|
21
|
+
const GLYPH_RGB = asRgb(TERMINAL_DARK_RGB.spinnerBlue);
|
|
22
|
+
const GREEN_RGB = asRgb(TERMINAL_DARK_RGB.success);
|
|
23
|
+
const RED_RGB = asRgb(TERMINAL_DARK_RGB.error);
|
|
22
24
|
function lerp(a, b, t) {
|
|
23
25
|
return Math.round(a + (b - a) * t);
|
|
24
26
|
}
|
|
@@ -77,7 +79,7 @@ export function formatSpinnerGlyph(frame, useColor) {
|
|
|
77
79
|
const nearPeak = step === peak || step === SPINNER_FRAMES.length - peak - 1;
|
|
78
80
|
return `${rgbAnsi(nearPeak ? SHIMMER_RGB : GLYPH_RGB)}${ch}${RESET}`;
|
|
79
81
|
}
|
|
80
|
-
export const STATUS_TICK_MS =
|
|
82
|
+
export const STATUS_TICK_MS = 140;
|
|
81
83
|
export function formatWaitLine(options) {
|
|
82
84
|
const glyph = formatSpinnerGlyph(options.frame, options.useColor);
|
|
83
85
|
const label = shimmerLabel(options.label, options.frame, options.useColor);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type TerminalRgb = readonly [number, number, number];
|
|
2
|
+
/** Canonical brand colors. Terminal surfaces use the softer dark theme below. */
|
|
3
|
+
export declare const APOLLO_BRAND_PALETTE: {
|
|
4
|
+
readonly blue: "#4285F4";
|
|
5
|
+
readonly red: "#EA4335";
|
|
6
|
+
readonly yellow: "#FBBC05";
|
|
7
|
+
readonly green: "#34A853";
|
|
8
|
+
};
|
|
9
|
+
/** Dark terminal palette matched to cc-yh's theme and Monokai Extended syntax colors. */
|
|
10
|
+
export declare const TERMINAL_DARK_RGB: {
|
|
11
|
+
brandBlue: [number, number, number];
|
|
12
|
+
spinnerBase: [number, number, number];
|
|
13
|
+
spinnerBlue: [number, number, number];
|
|
14
|
+
spinnerShimmer: [number, number, number];
|
|
15
|
+
permission: [number, number, number];
|
|
16
|
+
permissionShimmer: [number, number, number];
|
|
17
|
+
success: [number, number, number];
|
|
18
|
+
error: [number, number, number];
|
|
19
|
+
warning: [number, number, number];
|
|
20
|
+
text: [number, number, number];
|
|
21
|
+
inactive: [number, number, number];
|
|
22
|
+
subtle: [number, number, number];
|
|
23
|
+
diffAdded: [number, number, number];
|
|
24
|
+
diffRemoved: [number, number, number];
|
|
25
|
+
keyword: [number, number, number];
|
|
26
|
+
storage: [number, number, number];
|
|
27
|
+
syntaxGreen: [number, number, number];
|
|
28
|
+
literal: [number, number, number];
|
|
29
|
+
string: [number, number, number];
|
|
30
|
+
params: [number, number, number];
|
|
31
|
+
comment: [number, number, number];
|
|
32
|
+
};
|
|
33
|
+
export declare function terminalForeground(rgb: TerminalRgb): string;
|
|
34
|
+
export declare function terminalBackground(rgb: TerminalRgb): string;
|
|
35
|
+
export declare const TERMINAL_ANSI: {
|
|
36
|
+
readonly brandBlue: string;
|
|
37
|
+
readonly permission: string;
|
|
38
|
+
readonly success: string;
|
|
39
|
+
readonly error: string;
|
|
40
|
+
readonly warning: string;
|
|
41
|
+
readonly text: string;
|
|
42
|
+
readonly inactive: string;
|
|
43
|
+
readonly subtle: string;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=terminal-theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-theme.d.ts","sourceRoot":"","sources":["../src/terminal-theme.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5D,iFAAiF;AACjF,eAAO,MAAM,oBAAoB;;;;;CAKvB,CAAC;AAEX,yFAAyF;AACzF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;CAsBS,CAAC;AAExC,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAE3D;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAE3D;AAED,eAAO,MAAM,aAAa;;;;;;;;;CAShB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Canonical brand colors. Terminal surfaces use the softer dark theme below. */
|
|
2
|
+
export const APOLLO_BRAND_PALETTE = {
|
|
3
|
+
blue: "#4285F4",
|
|
4
|
+
red: "#EA4335",
|
|
5
|
+
yellow: "#FBBC05",
|
|
6
|
+
green: "#34A853",
|
|
7
|
+
};
|
|
8
|
+
/** Dark terminal palette matched to cc-yh's theme and Monokai Extended syntax colors. */
|
|
9
|
+
export const TERMINAL_DARK_RGB = {
|
|
10
|
+
brandBlue: [66, 133, 244],
|
|
11
|
+
spinnerBase: [148, 163, 184],
|
|
12
|
+
spinnerBlue: [96, 165, 250],
|
|
13
|
+
spinnerShimmer: [147, 197, 253],
|
|
14
|
+
permission: [177, 185, 249],
|
|
15
|
+
permissionShimmer: [207, 215, 255],
|
|
16
|
+
success: [78, 186, 101],
|
|
17
|
+
error: [255, 107, 128],
|
|
18
|
+
warning: [255, 193, 7],
|
|
19
|
+
text: [248, 248, 242],
|
|
20
|
+
inactive: [153, 153, 153],
|
|
21
|
+
subtle: [80, 80, 80],
|
|
22
|
+
diffAdded: [34, 92, 43],
|
|
23
|
+
diffRemoved: [122, 41, 54],
|
|
24
|
+
keyword: [249, 38, 114],
|
|
25
|
+
storage: [102, 217, 239],
|
|
26
|
+
syntaxGreen: [166, 226, 46],
|
|
27
|
+
literal: [190, 132, 255],
|
|
28
|
+
string: [230, 219, 116],
|
|
29
|
+
params: [253, 151, 31],
|
|
30
|
+
comment: [117, 113, 94],
|
|
31
|
+
};
|
|
32
|
+
export function terminalForeground(rgb) {
|
|
33
|
+
return `\x1b[38;2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
|
|
34
|
+
}
|
|
35
|
+
export function terminalBackground(rgb) {
|
|
36
|
+
return `\x1b[48;2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
|
|
37
|
+
}
|
|
38
|
+
export const TERMINAL_ANSI = {
|
|
39
|
+
brandBlue: terminalForeground(TERMINAL_DARK_RGB.brandBlue),
|
|
40
|
+
permission: terminalForeground(TERMINAL_DARK_RGB.permission),
|
|
41
|
+
success: terminalForeground(TERMINAL_DARK_RGB.success),
|
|
42
|
+
error: terminalForeground(TERMINAL_DARK_RGB.error),
|
|
43
|
+
warning: terminalForeground(TERMINAL_DARK_RGB.warning),
|
|
44
|
+
text: terminalForeground(TERMINAL_DARK_RGB.text),
|
|
45
|
+
inactive: terminalForeground(TERMINAL_DARK_RGB.inactive),
|
|
46
|
+
subtle: terminalForeground(TERMINAL_DARK_RGB.subtle),
|
|
47
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thought-fold.d.ts","sourceRoot":"","sources":["../src/thought-fold.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"thought-fold.d.ts","sourceRoot":"","sources":["../src/thought-fold.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,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;AAIF,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
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* Bounded terminal preview for model thinking tokens.
|
|
3
3
|
*/
|
|
4
4
|
import { stripTerminalEscapes } from "./trace.js";
|
|
5
|
-
|
|
5
|
+
import { TERMINAL_ANSI } from "./terminal-theme.js";
|
|
6
6
|
const RESET = "\x1b[0m";
|
|
7
|
-
const GREEN = "\x1b[32m";
|
|
8
|
-
const RED = "\x1b[31m";
|
|
9
7
|
export class ThoughtFoldManager {
|
|
10
8
|
current = null;
|
|
11
9
|
options;
|
|
@@ -65,7 +63,7 @@ export class ThoughtFoldManager {
|
|
|
65
63
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
66
64
|
}
|
|
67
65
|
printHeader(block) {
|
|
68
|
-
const color = block.failed ?
|
|
66
|
+
const color = block.failed ? TERMINAL_ANSI.error : TERMINAL_ANSI.success;
|
|
69
67
|
const dot = this.options.color ? `${color}●${RESET}` : "●";
|
|
70
68
|
const label = block.failed
|
|
71
69
|
? `Failed · ${this.duration(block)}`
|
|
@@ -76,6 +74,6 @@ export class ThoughtFoldManager {
|
|
|
76
74
|
dim(text) {
|
|
77
75
|
if (!this.options.color)
|
|
78
76
|
return text;
|
|
79
|
-
return `${
|
|
77
|
+
return `${TERMINAL_ANSI.inactive}${text}${RESET}`;
|
|
80
78
|
}
|
|
81
79
|
}
|