@kernelonpanic/kitcode 1.4.2 → 1.4.5
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 +22 -2
- package/README.ru.md +22 -2
- package/dist/index.js +328 -62
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -81,6 +81,14 @@ var configSchema = z.object({
|
|
|
81
81
|
// Manual override for the model's context window. Unset means the window
|
|
82
82
|
// comes from the provider catalogue or the endpoint's model list.
|
|
83
83
|
contextWindow: z.number().int().min(1e3).max(1e7).optional(),
|
|
84
|
+
// Extra instructions appended to the built-in system prompt on every turn.
|
|
85
|
+
systemPrompt: z.string().max(2e4).optional(),
|
|
86
|
+
// When false, systemPrompt is kept in the config but not sent to the model.
|
|
87
|
+
systemPromptEnabled: z.boolean().default(true),
|
|
88
|
+
// Hard cap on model calls in one turn. Higher values let large refactors
|
|
89
|
+
// finish; 0 disables the cap entirely (use with care — a runaway loop will
|
|
90
|
+
// keep burning tokens until you press Esc).
|
|
91
|
+
maxTurnSteps: z.number().int().min(0).max(1e3).default(256),
|
|
84
92
|
maxTokens: z.number().int().positive().max(2e5).default(64e3),
|
|
85
93
|
budget: budgetSchema.default({
|
|
86
94
|
maxTokensPerTurn: 1e7,
|
|
@@ -170,7 +178,10 @@ function describeProviderFailure(error, providerId, knownSecrets = []) {
|
|
|
170
178
|
}
|
|
171
179
|
function statusOf(error) {
|
|
172
180
|
const value = prop(error, "status") ?? prop(error, "statusCode");
|
|
173
|
-
|
|
181
|
+
if (typeof value === "number" && value >= 100) return value;
|
|
182
|
+
const code = prop(error, "code") ?? prop(prop(error, "error"), "code");
|
|
183
|
+
const numeric = typeof code === "string" && /^\d{3}$/.test(code) ? Number(code) : code;
|
|
184
|
+
return typeof numeric === "number" && numeric >= 400 && numeric <= 599 ? numeric : void 0;
|
|
174
185
|
}
|
|
175
186
|
function isUserAbort(error, signal) {
|
|
176
187
|
return signal?.aborted === true || abortKind(error) === "user";
|
|
@@ -1440,13 +1451,20 @@ function resolveEffort(effort, messages) {
|
|
|
1440
1451
|
return text.length > 500 || HARD_TASK.test(text) ? "high" : "medium";
|
|
1441
1452
|
}
|
|
1442
1453
|
var rejected = /* @__PURE__ */ new Set();
|
|
1454
|
+
var capped = /* @__PURE__ */ new Map();
|
|
1455
|
+
var RANK = { low: 0, medium: 1, high: 2, xhigh: 3, max: 4 };
|
|
1443
1456
|
function markEffortRejected(providerId, model) {
|
|
1444
1457
|
rejected.add(`${providerId}/${model}`);
|
|
1445
1458
|
}
|
|
1459
|
+
function markEffortCapped(providerId, model, level) {
|
|
1460
|
+
capped.set(`${providerId}/${model}`, level);
|
|
1461
|
+
}
|
|
1446
1462
|
function effectiveEffort(kind, model, effort, messages, providerId) {
|
|
1447
1463
|
if (providerId !== void 0 && rejected.has(`${providerId}/${model}`)) return void 0;
|
|
1448
1464
|
const requested = resolveEffort(effort, messages);
|
|
1449
|
-
|
|
1465
|
+
const level = kind === "openai" ? openAiEffort(model, requested) : anthropicEffort(model, requested);
|
|
1466
|
+
const cap = providerId === void 0 ? void 0 : capped.get(`${providerId}/${model}`);
|
|
1467
|
+
return level && cap && RANK[level] > RANK[cap] ? cap : level;
|
|
1450
1468
|
}
|
|
1451
1469
|
function anthropicEffort(model, effort) {
|
|
1452
1470
|
if (!effort) return void 0;
|
|
@@ -1878,7 +1896,7 @@ function validSessionId(id) {
|
|
|
1878
1896
|
var MAX_PAUSE_RESUMES = 5;
|
|
1879
1897
|
var MAX_RETRIES2 = 3;
|
|
1880
1898
|
var INITIAL_BACKOFF_MS = 1e3;
|
|
1881
|
-
var
|
|
1899
|
+
var DEFAULT_MAX_TURN_STEPS = 256;
|
|
1882
1900
|
function createExecutionLane() {
|
|
1883
1901
|
let tail2 = Promise.resolve();
|
|
1884
1902
|
return {
|
|
@@ -1890,6 +1908,8 @@ function createExecutionLane() {
|
|
|
1890
1908
|
};
|
|
1891
1909
|
}
|
|
1892
1910
|
async function runTurn(cfg, history, hooks, signal) {
|
|
1911
|
+
const maxTurnSteps = cfg.maxTurnSteps ?? DEFAULT_MAX_TURN_STEPS;
|
|
1912
|
+
const hasStepCap = maxTurnSteps > 0;
|
|
1893
1913
|
const permissionLane = cfg.permissionLane ?? createExecutionLane();
|
|
1894
1914
|
const originalHooks = hooks;
|
|
1895
1915
|
hooks = {
|
|
@@ -1904,11 +1924,12 @@ async function runTurn(cfg, history, hooks, signal) {
|
|
|
1904
1924
|
hooks.onEvent({ type: "turn_end", stopReason: "aborted" });
|
|
1905
1925
|
return sanitizeHistory(messages);
|
|
1906
1926
|
}
|
|
1907
|
-
|
|
1927
|
+
steps += 1;
|
|
1928
|
+
if (hasStepCap && steps > maxTurnSteps) {
|
|
1908
1929
|
hooks.onEvent({
|
|
1909
1930
|
type: "notice",
|
|
1910
1931
|
level: "warn",
|
|
1911
|
-
text: `Stopped after ${
|
|
1932
|
+
text: `Stopped after ${maxTurnSteps} model calls without finishing, to avoid burning tokens in a loop. Ask again with a narrower request.`
|
|
1912
1933
|
});
|
|
1913
1934
|
hooks.onEvent({ type: "turn_end", stopReason: "max_tokens" });
|
|
1914
1935
|
return messages;
|
|
@@ -2137,18 +2158,18 @@ function sleep(ms, signal) {
|
|
|
2137
2158
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
2138
2159
|
});
|
|
2139
2160
|
}
|
|
2161
|
+
var CHARS_PER_TOKEN = 4;
|
|
2140
2162
|
function estimateRequestTokens(cfg, messages) {
|
|
2141
2163
|
let characters3 = cfg.system.length;
|
|
2142
2164
|
try {
|
|
2143
2165
|
characters3 += JSON.stringify(
|
|
2144
2166
|
messages,
|
|
2145
|
-
(_key, value) => typeof value === "object" && value !== null && value.type === "image" ? `[image:${"#".repeat(
|
|
2167
|
+
(_key, value) => typeof value === "object" && value !== null && value.type === "image" ? `[image:${"#".repeat(6e3)}]` : value
|
|
2146
2168
|
).length;
|
|
2147
2169
|
characters3 += JSON.stringify(cfg.tools.schemas()).length;
|
|
2148
2170
|
} catch {
|
|
2149
|
-
return Math.max(1, characters3);
|
|
2150
2171
|
}
|
|
2151
|
-
return Math.max(1, characters3);
|
|
2172
|
+
return Math.max(1, Math.ceil(characters3 / CHARS_PER_TOKEN));
|
|
2152
2173
|
}
|
|
2153
2174
|
async function runToolCalls(cfg, content, hooks, signal) {
|
|
2154
2175
|
const calls = content.filter((block) => block.type === "tool_use");
|
|
@@ -3789,6 +3810,7 @@ function withoutThinkingReplay(history) {
|
|
|
3789
3810
|
});
|
|
3790
3811
|
return changed ? out : history;
|
|
3791
3812
|
}
|
|
3813
|
+
var CHARS_PER_TOKEN2 = 4;
|
|
3792
3814
|
function estimateHistoryTokens(history) {
|
|
3793
3815
|
let chars = 0;
|
|
3794
3816
|
for (const message of history) {
|
|
@@ -3800,7 +3822,7 @@ function estimateHistoryTokens(history) {
|
|
|
3800
3822
|
else if (block.type === "image") chars += 6e3;
|
|
3801
3823
|
}
|
|
3802
3824
|
}
|
|
3803
|
-
return Math.round(chars /
|
|
3825
|
+
return Math.round(chars / CHARS_PER_TOKEN2);
|
|
3804
3826
|
}
|
|
3805
3827
|
function shouldAutoCompact(used, window) {
|
|
3806
3828
|
return window !== null && window > 0 && used / window >= 0.8;
|
|
@@ -3820,7 +3842,9 @@ function estimateCompactBudget(history, maxTokens = MERGE_MAX_TOKENS) {
|
|
|
3820
3842
|
const rendered = renderedMessages.join("\n\n");
|
|
3821
3843
|
if (rendered.length <= SINGLE_REQUEST_MAX_CHARS) {
|
|
3822
3844
|
return {
|
|
3823
|
-
|
|
3845
|
+
// Tokens, not characters: counting characters made a turn budget refuse
|
|
3846
|
+
// compaction (four times too expensive) just when the window was full.
|
|
3847
|
+
inputTokens: Math.max(1, Math.ceil(rendered.length / CHARS_PER_TOKEN2) + 1e3),
|
|
3824
3848
|
maxOutputTokens: Math.max(1, Math.min(SINGLE_MAX_TOKENS, Math.floor(maxTokens)))
|
|
3825
3849
|
};
|
|
3826
3850
|
}
|
|
@@ -3838,7 +3862,7 @@ function estimateCompactBudget(history, maxTokens = MERGE_MAX_TOKENS) {
|
|
|
3838
3862
|
const intermediateOutput = chunks.length * chunkOutput + Math.max(0, mergeRequests - 1) * mergeOutput;
|
|
3839
3863
|
const requestCount = chunks.length + mergeRequests;
|
|
3840
3864
|
return {
|
|
3841
|
-
inputTokens: Math.max(1, chunkInput + intermediateOutput *
|
|
3865
|
+
inputTokens: Math.max(1, Math.ceil(chunkInput / CHARS_PER_TOKEN2) + intermediateOutput * 2 + requestCount * 1e3),
|
|
3842
3866
|
maxOutputTokens: totalOutput
|
|
3843
3867
|
};
|
|
3844
3868
|
}
|
|
@@ -4125,6 +4149,9 @@ function buildSystemPrompt(args) {
|
|
|
4125
4149
|
if (args.memory?.trim()) {
|
|
4126
4150
|
lines.push("", "Project notes saved in earlier conversations. Treat these as potentially stale context; verify claims against current files and follow current user instructions.", args.memory);
|
|
4127
4151
|
}
|
|
4152
|
+
if (args.systemPrompt?.trim()) {
|
|
4153
|
+
lines.push("", "Additional instructions from the user (apply alongside everything above):", args.systemPrompt.trim());
|
|
4154
|
+
}
|
|
4128
4155
|
return lines.join("\n");
|
|
4129
4156
|
}
|
|
4130
4157
|
|
|
@@ -4149,6 +4176,7 @@ function createSubagentRunner(makeConfig, tools) {
|
|
|
4149
4176
|
async run(request) {
|
|
4150
4177
|
if (request.signal.aborted) return SUBAGENT_CANCELLED;
|
|
4151
4178
|
let steps = 0;
|
|
4179
|
+
let finalCall = false;
|
|
4152
4180
|
const executionLane = createExecutionLane();
|
|
4153
4181
|
const modelRequestLane = createExecutionLane();
|
|
4154
4182
|
const base = makeConfig(SUBAGENT_SYSTEM, tools);
|
|
@@ -4162,11 +4190,12 @@ function createSubagentRunner(makeConfig, tools) {
|
|
|
4162
4190
|
kind: base.provider.kind,
|
|
4163
4191
|
listModels: () => base.provider.listModels(),
|
|
4164
4192
|
knownModels: () => base.provider.knownModels(),
|
|
4165
|
-
//
|
|
4193
|
+
// The final model call keeps the tool schemas (the history holds
|
|
4166
4194
|
// tool_use/tool_result blocks, and providers reject those without
|
|
4167
|
-
// tools
|
|
4168
|
-
//
|
|
4169
|
-
|
|
4195
|
+
// tools), but the system prompt forbids more calls and tools.get
|
|
4196
|
+
// returns a stopped stub: a call made anyway ends the turn with a
|
|
4197
|
+
// tool_result, instead of aborting mid-request and losing the text.
|
|
4198
|
+
stream: (chat) => base.provider.stream(finalCall ? {
|
|
4170
4199
|
...chat,
|
|
4171
4200
|
system: `${chat.system}
|
|
4172
4201
|
|
|
@@ -4174,7 +4203,20 @@ This is your last model call. Do not call tools. Return your findings now, clear
|
|
|
4174
4203
|
} : chat)
|
|
4175
4204
|
},
|
|
4176
4205
|
tools: {
|
|
4177
|
-
get: (name) =>
|
|
4206
|
+
get: (name) => {
|
|
4207
|
+
if (name === TASK_TOOL_NAME) return void 0;
|
|
4208
|
+
const tool = base.tools.get(name);
|
|
4209
|
+
if (!tool) return void 0;
|
|
4210
|
+
if (!finalCall) return tool;
|
|
4211
|
+
return {
|
|
4212
|
+
...tool,
|
|
4213
|
+
permission: () => "allow",
|
|
4214
|
+
execute: () => Promise.resolve({
|
|
4215
|
+
content: "Tool budget exhausted: this was your last model call. Write the final answer now from what you already gathered.",
|
|
4216
|
+
isError: true
|
|
4217
|
+
})
|
|
4218
|
+
};
|
|
4219
|
+
},
|
|
4178
4220
|
schemas: () => base.tools.schemas().filter((schema) => schema.name !== TASK_TOOL_NAME)
|
|
4179
4221
|
},
|
|
4180
4222
|
system: `${SUBAGENT_SYSTEM}
|
|
@@ -4185,7 +4227,11 @@ Working directory: ${base.cwd}`
|
|
|
4185
4227
|
const signal = AbortSignal.any([request.signal, limit.signal]);
|
|
4186
4228
|
const hooks = {
|
|
4187
4229
|
onEvent(event) {
|
|
4188
|
-
if (event.type === "turn_start"
|
|
4230
|
+
if (event.type === "turn_start") {
|
|
4231
|
+
++steps;
|
|
4232
|
+
if (steps > MAX_SUBAGENT_STEPS + 1) limit.abort();
|
|
4233
|
+
else if (steps >= MAX_SUBAGENT_STEPS) finalCall = true;
|
|
4234
|
+
}
|
|
4189
4235
|
if (event.type === "tool_start") request.onProgress(brief(event.summary, 80));
|
|
4190
4236
|
if (event.type === "subagent_start" || event.type === "subagent_end" || event.type === "subagent_event") return;
|
|
4191
4237
|
request.onEvent?.(event);
|
|
@@ -4400,7 +4446,7 @@ function clip(value) {
|
|
|
4400
4446
|
// package.json
|
|
4401
4447
|
var package_default = {
|
|
4402
4448
|
name: "@kernelonpanic/kitcode",
|
|
4403
|
-
version: "1.4.
|
|
4449
|
+
version: "1.4.5",
|
|
4404
4450
|
description: "Terminal coding agent with a config you never have to write by hand",
|
|
4405
4451
|
type: "module",
|
|
4406
4452
|
license: "MIT",
|
|
@@ -4468,7 +4514,22 @@ var package_default = {
|
|
|
4468
4514
|
|
|
4469
4515
|
// src/version.ts
|
|
4470
4516
|
var KITCODE_VERSION = package_default.version;
|
|
4471
|
-
var KITCODE_COMMIT = true ? "
|
|
4517
|
+
var KITCODE_COMMIT = true ? "aac7d92efa29456e6757bdef12abafb489064dbe" : "development";
|
|
4518
|
+
function kitcodeUserAgent(sdkUserAgent2) {
|
|
4519
|
+
return `KitCode/${KITCODE_VERSION} ${sdkUserAgent2}`.trim();
|
|
4520
|
+
}
|
|
4521
|
+
function sdkUserAgent(client) {
|
|
4522
|
+
const read = client?.getUserAgent;
|
|
4523
|
+
try {
|
|
4524
|
+
return typeof read === "function" ? String(read.call(client)) : "";
|
|
4525
|
+
} catch {
|
|
4526
|
+
return "";
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
function withKitcodeUserAgent(sdkUserAgent2, configured = {}) {
|
|
4530
|
+
const overridden = Object.keys(configured).some((name) => name.toLowerCase() === "user-agent");
|
|
4531
|
+
return overridden ? { ...configured } : { "User-Agent": kitcodeUserAgent(sdkUserAgent2), ...configured };
|
|
4532
|
+
}
|
|
4472
4533
|
|
|
4473
4534
|
// src/mcp/client.ts
|
|
4474
4535
|
var clientInfo = { name: "kitcode", version: KITCODE_VERSION };
|
|
@@ -5047,13 +5108,14 @@ var KNOWN_MODELS = [
|
|
|
5047
5108
|
knownModel("claude-fable-5", "Claude Fable 5", 1e6, 128e3)
|
|
5048
5109
|
];
|
|
5049
5110
|
function createAnthropicProvider(args) {
|
|
5050
|
-
const
|
|
5111
|
+
const options = {
|
|
5051
5112
|
apiKey: args.apiKey,
|
|
5052
5113
|
baseURL: args.baseUrl,
|
|
5053
|
-
defaultHeaders: args.headers,
|
|
5054
5114
|
maxRetries: MAX_RETRIES,
|
|
5055
5115
|
timeout: args.timeoutMs ?? REQUEST_TIMEOUT_MS
|
|
5056
|
-
}
|
|
5116
|
+
};
|
|
5117
|
+
const userAgent = sdkUserAgent(new Anthropic2(options));
|
|
5118
|
+
const client = new Anthropic2({ ...options, defaultHeaders: withKitcodeUserAgent(userAgent, args.headers) });
|
|
5057
5119
|
return {
|
|
5058
5120
|
id: args.id,
|
|
5059
5121
|
kind: "anthropic",
|
|
@@ -5062,7 +5124,35 @@ function createAnthropicProvider(args) {
|
|
|
5062
5124
|
knownModels: () => KNOWN_MODELS
|
|
5063
5125
|
};
|
|
5064
5126
|
}
|
|
5127
|
+
var thinkingRejected = /* @__PURE__ */ new Set();
|
|
5065
5128
|
async function* streamTurn(client, providerId, apiKey2, req) {
|
|
5129
|
+
const key = `${providerId}/${req.model}`;
|
|
5130
|
+
let thinking = req.thinking === true && !thinkingRejected.has(key);
|
|
5131
|
+
for (; ; ) {
|
|
5132
|
+
let streamed = false;
|
|
5133
|
+
try {
|
|
5134
|
+
for await (const event of streamOnce(client, providerId, apiKey2, req, thinking)) {
|
|
5135
|
+
if (event.type !== "rate_limits" && event.type !== "usage") streamed = true;
|
|
5136
|
+
yield event;
|
|
5137
|
+
}
|
|
5138
|
+
return;
|
|
5139
|
+
} catch (error) {
|
|
5140
|
+
if (!streamed && thinking && refusesThinking(error)) {
|
|
5141
|
+
thinkingRejected.add(key);
|
|
5142
|
+
thinking = false;
|
|
5143
|
+
continue;
|
|
5144
|
+
}
|
|
5145
|
+
throw error;
|
|
5146
|
+
}
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
function refusesThinking(error) {
|
|
5150
|
+
if (!(error instanceof ProviderError)) return false;
|
|
5151
|
+
if (error.status !== void 0 && error.status !== 400 && error.status !== 422) return false;
|
|
5152
|
+
const cause = error.cause instanceof Error ? error.cause.message : "";
|
|
5153
|
+
return /thinking|budget_tokens|adaptive/i.test(`${error.message} ${cause}`);
|
|
5154
|
+
}
|
|
5155
|
+
async function* streamOnce(client, providerId, apiKey2, req, thinkingOn) {
|
|
5066
5156
|
const params = {
|
|
5067
5157
|
model: req.model,
|
|
5068
5158
|
max_tokens: req.maxTokens,
|
|
@@ -5070,7 +5160,7 @@ async function* streamTurn(client, providerId, apiKey2, req) {
|
|
|
5070
5160
|
messages: toMessageParams(req.messages),
|
|
5071
5161
|
tools: toToolParams(req.tools)
|
|
5072
5162
|
};
|
|
5073
|
-
if (
|
|
5163
|
+
if (thinkingOn) {
|
|
5074
5164
|
const thinking2 = thinkingParam(req.model, req.maxTokens);
|
|
5075
5165
|
if (thinking2) params.thinking = thinking2;
|
|
5076
5166
|
}
|
|
@@ -5232,7 +5322,7 @@ var THINKING_BUDGET = 16e3;
|
|
|
5232
5322
|
var MIN_THINKING_BUDGET = 1024;
|
|
5233
5323
|
function thinkingParam(model, maxTokens) {
|
|
5234
5324
|
const id = (model.split("/").at(-1) ?? model).replace(/^(?:[a-z]{2}\.)?anthropic\./, "");
|
|
5235
|
-
if (!BUDGET_THINKING.test(id)) return { type: "adaptive", display: "summarized" };
|
|
5325
|
+
if (id.startsWith("claude-") && !BUDGET_THINKING.test(id)) return { type: "adaptive", display: "summarized" };
|
|
5236
5326
|
const budget = Math.min(THINKING_BUDGET, maxTokens - 1);
|
|
5237
5327
|
return budget >= MIN_THINKING_BUDGET ? { type: "enabled", budget_tokens: budget } : void 0;
|
|
5238
5328
|
}
|
|
@@ -5252,13 +5342,14 @@ var FINISH_REASONS = {
|
|
|
5252
5342
|
content_filter: "refusal"
|
|
5253
5343
|
};
|
|
5254
5344
|
function createOpenAiProvider(args) {
|
|
5255
|
-
const
|
|
5345
|
+
const options = {
|
|
5256
5346
|
baseURL: args.baseUrl,
|
|
5257
5347
|
apiKey: args.apiKey,
|
|
5258
|
-
defaultHeaders: args.headers,
|
|
5259
5348
|
maxRetries: MAX_RETRIES,
|
|
5260
5349
|
timeout: args.timeoutMs ?? REQUEST_TIMEOUT_MS
|
|
5261
|
-
}
|
|
5350
|
+
};
|
|
5351
|
+
const userAgent = sdkUserAgent(new OpenAI2(options));
|
|
5352
|
+
const client = new OpenAI2({ ...options, defaultHeaders: withKitcodeUserAgent(userAgent, args.headers) });
|
|
5262
5353
|
return {
|
|
5263
5354
|
id: args.id,
|
|
5264
5355
|
kind: "openai",
|
|
@@ -5275,7 +5366,7 @@ async function* streamTurn2(client, providerId, apiKey2, req) {
|
|
|
5275
5366
|
for (; ; ) {
|
|
5276
5367
|
let streamed = false;
|
|
5277
5368
|
try {
|
|
5278
|
-
for await (const event of
|
|
5369
|
+
for await (const event of streamOnce2(client, providerId, apiKey2, req, effort, thinkingOff, tokenField)) {
|
|
5279
5370
|
if (event.type !== "rate_limits" && event.type !== "usage") streamed = true;
|
|
5280
5371
|
yield event;
|
|
5281
5372
|
}
|
|
@@ -5288,8 +5379,14 @@ async function* streamTurn2(client, providerId, apiKey2, req) {
|
|
|
5288
5379
|
continue;
|
|
5289
5380
|
}
|
|
5290
5381
|
if (effort && rejectsField(error, /reasoning|effort/i)) {
|
|
5291
|
-
|
|
5292
|
-
|
|
5382
|
+
const lower = effort === "xhigh" || effort === "max" ? "high" : effort === "high" ? "medium" : void 0;
|
|
5383
|
+
if (lower) {
|
|
5384
|
+
markEffortCapped(providerId, req.model, lower);
|
|
5385
|
+
effort = lower;
|
|
5386
|
+
} else {
|
|
5387
|
+
markEffortRejected(providerId, req.model);
|
|
5388
|
+
effort = void 0;
|
|
5389
|
+
}
|
|
5293
5390
|
continue;
|
|
5294
5391
|
}
|
|
5295
5392
|
if (thinkingOff && rejectsField(error, /thinking/i)) {
|
|
@@ -5314,11 +5411,12 @@ function thinkingOffParams(model) {
|
|
|
5314
5411
|
return void 0;
|
|
5315
5412
|
}
|
|
5316
5413
|
function rejectsField(error, field2) {
|
|
5317
|
-
if (!(error instanceof ProviderError)
|
|
5414
|
+
if (!(error instanceof ProviderError)) return false;
|
|
5415
|
+
if (error.status !== void 0 && error.status !== 400 && error.status !== 422) return false;
|
|
5318
5416
|
const cause = error.cause instanceof Error ? error.cause.message : "";
|
|
5319
5417
|
return field2.test(`${error.message} ${cause}`);
|
|
5320
5418
|
}
|
|
5321
|
-
async function*
|
|
5419
|
+
async function* streamOnce2(client, providerId, apiKey2, req, effort, thinkingOff, tokenField) {
|
|
5322
5420
|
let text = "";
|
|
5323
5421
|
let thinking = "";
|
|
5324
5422
|
let finishReason = null;
|
|
@@ -7227,7 +7325,8 @@ async function boot(options) {
|
|
|
7227
7325
|
cwd: options.cwd,
|
|
7228
7326
|
toolNames: tools.list().map((tool) => tool.name),
|
|
7229
7327
|
skills: skillCatalogue,
|
|
7230
|
-
memory: projectMemory
|
|
7328
|
+
memory: projectMemory,
|
|
7329
|
+
systemPrompt: config.systemPromptEnabled ? config.systemPrompt : void 0
|
|
7231
7330
|
});
|
|
7232
7331
|
let modelRef = session.model || config.model || "";
|
|
7233
7332
|
if (options.modelRef) modelRef = options.modelRef;
|
|
@@ -7297,6 +7396,7 @@ async function boot(options) {
|
|
|
7297
7396
|
maxTokens: config.maxTokens,
|
|
7298
7397
|
effort: config.effort,
|
|
7299
7398
|
thinking: config.thinking,
|
|
7399
|
+
maxTurnSteps: config.maxTurnSteps,
|
|
7300
7400
|
budget: activeBudget,
|
|
7301
7401
|
checkpoint: activeCheckpoint,
|
|
7302
7402
|
trimContext: (messages) => trimForWindow(resolved.provider.kind, messages)
|
|
@@ -7677,6 +7777,31 @@ async function boot(options) {
|
|
|
7677
7777
|
draft.lang = lang;
|
|
7678
7778
|
});
|
|
7679
7779
|
},
|
|
7780
|
+
getSystemPrompt: () => config.systemPrompt ?? "",
|
|
7781
|
+
isSystemPromptEnabled: () => config.systemPromptEnabled && config.systemPrompt !== void 0 && config.systemPrompt.trim() !== "",
|
|
7782
|
+
async setSystemPrompt(text) {
|
|
7783
|
+
const trimmed = text.trim();
|
|
7784
|
+
await persistConfig((draft) => {
|
|
7785
|
+
if (trimmed === "") delete draft.systemPrompt;
|
|
7786
|
+
else draft.systemPrompt = trimmed;
|
|
7787
|
+
});
|
|
7788
|
+
},
|
|
7789
|
+
async setSystemPromptEnabled(enabled) {
|
|
7790
|
+
await persistConfig((draft) => {
|
|
7791
|
+
draft.systemPromptEnabled = enabled;
|
|
7792
|
+
});
|
|
7793
|
+
},
|
|
7794
|
+
async loadSystemPromptFile(requestedPath) {
|
|
7795
|
+
const { readFile: readFile15 } = await import("fs/promises");
|
|
7796
|
+
const resolved = path15.resolve(options.cwd, requestedPath);
|
|
7797
|
+
return readFile15(resolved, "utf8");
|
|
7798
|
+
},
|
|
7799
|
+
getMaxTurnSteps: () => config.maxTurnSteps,
|
|
7800
|
+
async setMaxTurnSteps(steps) {
|
|
7801
|
+
await persistConfig((draft) => {
|
|
7802
|
+
draft.maxTurnSteps = steps;
|
|
7803
|
+
});
|
|
7804
|
+
},
|
|
7680
7805
|
getAccent: () => config.theme.accent,
|
|
7681
7806
|
async setAccent(value) {
|
|
7682
7807
|
await persistConfig((draft) => {
|
|
@@ -8041,7 +8166,7 @@ ${recovered.removed === 1 ? "The image was" : `${recovered.removed} images were`
|
|
|
8041
8166
|
}
|
|
8042
8167
|
function imageRejection(error, history) {
|
|
8043
8168
|
const status = error?.status;
|
|
8044
|
-
if (typeof status !== "number" || ![400, 413, 415, 422].includes(status)) return null;
|
|
8169
|
+
if (status !== void 0 && (typeof status !== "number" || ![400, 413, 415, 422].includes(status))) return null;
|
|
8045
8170
|
const message = error instanceof Error ? error.message : String(error);
|
|
8046
8171
|
if (status !== 413 && !/image|vision|multi-?modal/i.test(message)) return null;
|
|
8047
8172
|
const result = withoutImages(history);
|
|
@@ -8257,7 +8382,7 @@ function validateKey(value) {
|
|
|
8257
8382
|
import { render } from "ink";
|
|
8258
8383
|
|
|
8259
8384
|
// src/ui/App.tsx
|
|
8260
|
-
import { Box as Box14, Text as Text13, useApp, useInput as
|
|
8385
|
+
import { Box as Box14, Text as Text13, useApp, useInput as useInput4, useStdout as useStdout2 } from "ink";
|
|
8261
8386
|
import { useCallback, useEffect as useEffect4, useMemo as useMemo6, useRef as useRef5, useState as useState8 } from "react";
|
|
8262
8387
|
|
|
8263
8388
|
// src/ui/terminal-size.ts
|
|
@@ -8387,7 +8512,7 @@ function splitCommandLine(raw) {
|
|
|
8387
8512
|
}
|
|
8388
8513
|
|
|
8389
8514
|
// src/ui/speed.ts
|
|
8390
|
-
var
|
|
8515
|
+
var CHARS_PER_TOKEN3 = 4;
|
|
8391
8516
|
var MIN_LIVE_MS = 1e3;
|
|
8392
8517
|
function createSpeedMeter() {
|
|
8393
8518
|
return { streamedChars: 0, firstTokenAt: null, last: null };
|
|
@@ -8414,7 +8539,7 @@ function readSpeed(meter, busy, now = Date.now()) {
|
|
|
8414
8539
|
if (busy && meter.firstTokenAt !== null && meter.streamedChars > 0) {
|
|
8415
8540
|
const ms = now - meter.firstTokenAt;
|
|
8416
8541
|
if (ms >= MIN_LIVE_MS) {
|
|
8417
|
-
return { tokensPerSecond: meter.streamedChars /
|
|
8542
|
+
return { tokensPerSecond: meter.streamedChars / CHARS_PER_TOKEN3 / (ms / 1e3), live: true };
|
|
8418
8543
|
}
|
|
8419
8544
|
}
|
|
8420
8545
|
return meter.last === null || !Number.isFinite(meter.last) ? null : { tokensPerSecond: meter.last, live: false };
|
|
@@ -8443,6 +8568,8 @@ var COMMANDS = [
|
|
|
8443
8568
|
{ name: "mcp", args: "[add|list|delete|enable|disable]" },
|
|
8444
8569
|
{ name: "attach", args: "<path|clipboard|clear>" },
|
|
8445
8570
|
{ name: "memory", args: "[show|set <text>|clear]" },
|
|
8571
|
+
{ name: "systemp", args: "[set <text>|clear]", ...BUSY_SAFE },
|
|
8572
|
+
{ name: "steps", args: "[count]", ...BUSY_SAFE },
|
|
8446
8573
|
{ name: "compact" },
|
|
8447
8574
|
{ name: "update" },
|
|
8448
8575
|
{ name: "checker", ...BUSY_SAFE },
|
|
@@ -8816,6 +8943,17 @@ ${url}`,
|
|
|
8816
8943
|
memoryEmpty: "Project memory is empty.",
|
|
8817
8944
|
memoryClearAsk: "Clear project memory?",
|
|
8818
8945
|
memoryReplaceAsk: "Replace all project memory notes with this text?",
|
|
8946
|
+
systemPromptTitle: "System prompt addition",
|
|
8947
|
+
systemPromptUsage: "/systemp [show] \xB7 /systemp set <text> \xB7 /systemp clear",
|
|
8948
|
+
systemPromptEmpty: "No extra system prompt. Set one with /systemp set <text>.",
|
|
8949
|
+
systemPromptSet: "System prompt addition saved.",
|
|
8950
|
+
systemPromptCleared: "System prompt addition cleared.",
|
|
8951
|
+
systemPromptEnabled: "System prompt enabled.",
|
|
8952
|
+
systemPromptDisabled: "System prompt disabled (kept in config).",
|
|
8953
|
+
stepsCurrent: (n) => n === 0 ? "Model calls per turn: unlimited" : `Model calls per turn: ${n}`,
|
|
8954
|
+
stepsSet: (n) => `Model calls per turn set to ${n}`,
|
|
8955
|
+
stepsUnlimited: "Model calls per turn: unlimited (0). The turn budget still applies.",
|
|
8956
|
+
stepsInvalid: "Usage: /steps <0-1000> (0 = unlimited)",
|
|
8819
8957
|
promptDeleted: (name) => `Deleted prompt "${name}"`,
|
|
8820
8958
|
promptNotFound: (name) => `Prompt "${name}" not found.`,
|
|
8821
8959
|
promptsEmpty: "No saved prompts. Use /prompt save <name>.",
|
|
@@ -8858,6 +8996,8 @@ ${url}`,
|
|
|
8858
8996
|
theme: "change the accent colour",
|
|
8859
8997
|
lang: "change the interface language",
|
|
8860
8998
|
memory: "view, replace or clear project memory",
|
|
8999
|
+
systemp: "view, set, load from file, or toggle the extra system prompt",
|
|
9000
|
+
steps: "cap model calls per turn",
|
|
8861
9001
|
prompt: "insert or save a prompt",
|
|
8862
9002
|
"prompt save": "save the current or recent text as a prompt",
|
|
8863
9003
|
"prompt delete": "delete a saved prompt",
|
|
@@ -9053,6 +9193,17 @@ ${url}`,
|
|
|
9053
9193
|
memoryEmpty: "\u041F\u0430\u043C\u044F\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u043F\u0443\u0441\u0442\u0430.",
|
|
9054
9194
|
memoryClearAsk: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u043F\u0430\u043C\u044F\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0430?",
|
|
9055
9195
|
memoryReplaceAsk: "\u0417\u0430\u043C\u0435\u043D\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u0430\u043C\u0435\u0442\u043A\u0438 \u043F\u0430\u043C\u044F\u0442\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u044D\u0442\u0438\u043C \u0442\u0435\u043A\u0441\u0442\u043E\u043C?",
|
|
9196
|
+
systemPromptTitle: "\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u043A \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443",
|
|
9197
|
+
systemPromptUsage: "/systemp [show] \xB7 /systemp set <\u0442\u0435\u043A\u0441\u0442> \xB7 /systemp clear",
|
|
9198
|
+
systemPromptEmpty: "\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F \u043A \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443 \u043D\u0435\u0442. \u0417\u0430\u0434\u0430\u0439 \u0447\u0435\u0440\u0435\u0437 /systemp set <\u0442\u0435\u043A\u0441\u0442>.",
|
|
9199
|
+
systemPromptSet: "\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u043A \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043E.",
|
|
9200
|
+
systemPromptCleared: "\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u043A \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443 \u0443\u0434\u0430\u043B\u0435\u043D\u043E.",
|
|
9201
|
+
systemPromptEnabled: "\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u043A \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E.",
|
|
9202
|
+
systemPromptDisabled: "\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u043A \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443 \u0432\u044B\u043A\u043B\u044E\u0447\u0435\u043D\u043E (\u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043E \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0435).",
|
|
9203
|
+
stepsCurrent: (n) => n === 0 ? "\u0412\u044B\u0437\u043E\u0432\u043E\u0432 \u043C\u043E\u0434\u0435\u043B\u0438 \u0437\u0430 \u0445\u043E\u0434: \u0431\u0435\u0437 \u043B\u0438\u043C\u0438\u0442\u0430" : `\u0412\u044B\u0437\u043E\u0432\u043E\u0432 \u043C\u043E\u0434\u0435\u043B\u0438 \u0437\u0430 \u0445\u043E\u0434: ${n}`,
|
|
9204
|
+
stepsSet: (n) => `\u0412\u044B\u0437\u043E\u0432\u043E\u0432 \u043C\u043E\u0434\u0435\u043B\u0438 \u0437\u0430 \u0445\u043E\u0434 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E: ${n}`,
|
|
9205
|
+
stepsUnlimited: "\u0412\u044B\u0437\u043E\u0432\u043E\u0432 \u043C\u043E\u0434\u0435\u043B\u0438 \u0437\u0430 \u0445\u043E\u0434: \u0431\u0435\u0437 \u043B\u0438\u043C\u0438\u0442\u0430 (0). \u0411\u044E\u0434\u0436\u0435\u0442 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 \u0432\u0441\u0451 \u0435\u0449\u0451 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442.",
|
|
9206
|
+
stepsInvalid: "\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435: /steps <0-1000> (0 = \u0431\u0435\u0437 \u043B\u0438\u043C\u0438\u0442\u0430)",
|
|
9056
9207
|
promptDeleted: (name) => `\u041F\u0440\u043E\u043C\u0442 \xAB${name}\xBB \u0443\u0434\u0430\u043B\u0451\u043D`,
|
|
9057
9208
|
promptNotFound: (name) => `\u041F\u0440\u043E\u043C\u0442 \xAB${name}\xBB \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D.`,
|
|
9058
9209
|
promptsEmpty: "\u0421\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0445 \u043F\u0440\u043E\u043C\u0442\u043E\u0432 \u043D\u0435\u0442. \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 /prompt save <\u0438\u043C\u044F>.",
|
|
@@ -9095,6 +9246,8 @@ ${url}`,
|
|
|
9095
9246
|
theme: "\u0441\u043C\u0435\u043D\u0438\u0442\u044C \u0446\u0432\u0435\u0442 \u0430\u043A\u0446\u0435\u043D\u0442\u0430",
|
|
9096
9247
|
lang: "\u0441\u043C\u0435\u043D\u0438\u0442\u044C \u044F\u0437\u044B\u043A \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430",
|
|
9097
9248
|
memory: "\u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C, \u0437\u0430\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u043B\u0438 \u043E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u043F\u0430\u043C\u044F\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0430",
|
|
9249
|
+
systemp: "\u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C, \u0437\u0430\u0434\u0430\u0442\u044C, \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0438\u0437 \u0444\u0430\u0439\u043B\u0430 \u0438\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0438\u0442\u044C/\u0432\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0434\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u043A \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443",
|
|
9250
|
+
steps: "\u043B\u0438\u043C\u0438\u0442 \u0432\u044B\u0437\u043E\u0432\u043E\u0432 \u043C\u043E\u0434\u0435\u043B\u0438 \u0437\u0430 \u0445\u043E\u0434",
|
|
9098
9251
|
prompt: "\u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u043B\u0438 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043F\u0440\u043E\u043C\u0442",
|
|
9099
9252
|
skills: "\u0441\u043F\u0438\u0441\u043E\u043A \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u044B\u0445 \u0441\u043A\u0438\u043B\u043B\u043E\u0432",
|
|
9100
9253
|
"prompt delete": "\u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0439 \u043F\u0440\u043E\u043C\u0442",
|
|
@@ -9273,18 +9426,30 @@ function LanguagePicker({ onPick }) {
|
|
|
9273
9426
|
}
|
|
9274
9427
|
|
|
9275
9428
|
// src/ui/components/Onboarding.tsx
|
|
9276
|
-
import { Box as Box4, Text as Text4 } from "ink";
|
|
9429
|
+
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
9277
9430
|
import Spinner from "ink-spinner";
|
|
9278
9431
|
import TextInput from "ink-text-input";
|
|
9279
9432
|
import { useState as useState2 } from "react";
|
|
9280
9433
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
9281
|
-
function Onboarding({
|
|
9434
|
+
function Onboarding({
|
|
9435
|
+
onSubmit,
|
|
9436
|
+
onCancel
|
|
9437
|
+
}) {
|
|
9282
9438
|
const theme = useTheme();
|
|
9283
9439
|
const strings = useStrings();
|
|
9284
9440
|
const [step, setStep] = useState2("url");
|
|
9285
9441
|
const [url, setUrl] = useState2("");
|
|
9286
9442
|
const [key, setKey] = useState2("");
|
|
9287
9443
|
const [error, setError] = useState2("");
|
|
9444
|
+
useInput2((_input, inputKey) => {
|
|
9445
|
+
if (!inputKey.escape || step === "working") return;
|
|
9446
|
+
if (step === "key") {
|
|
9447
|
+
setError("");
|
|
9448
|
+
setStep("url");
|
|
9449
|
+
} else {
|
|
9450
|
+
onCancel?.();
|
|
9451
|
+
}
|
|
9452
|
+
});
|
|
9288
9453
|
const submitKey = async (value) => {
|
|
9289
9454
|
if (value.trim() === "") return;
|
|
9290
9455
|
setStep("working");
|
|
@@ -10290,13 +10455,12 @@ function ContextMeter({
|
|
|
10290
10455
|
}
|
|
10291
10456
|
|
|
10292
10457
|
// src/ui/components/SubagentChat.tsx
|
|
10293
|
-
import { Box as Box12, Text as Text12, useInput as
|
|
10458
|
+
import { Box as Box12, Text as Text12, useInput as useInput3 } from "ink";
|
|
10294
10459
|
import { useState as useState7 } from "react";
|
|
10295
10460
|
|
|
10296
10461
|
// src/ui/components/Transcript.tsx
|
|
10297
10462
|
import { Box as Box11, Static, Text as Text11 } from "ink";
|
|
10298
10463
|
import { memo as memo2, useEffect as useEffect3, useMemo as useMemo5, useRef as useRef4, useState as useState6 } from "react";
|
|
10299
|
-
import Spinner2 from "ink-spinner";
|
|
10300
10464
|
import stringWidth4 from "string-width";
|
|
10301
10465
|
|
|
10302
10466
|
// src/ui/markdown.tsx
|
|
@@ -11186,10 +11350,7 @@ function AssistantView({ bubble: source, maxRows }) {
|
|
|
11186
11350
|
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
|
|
11187
11351
|
frameThinking !== "" && /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", maxHeight: thinkingBudget, overflowY: "hidden", children: /* @__PURE__ */ jsx11(Markdown, { dim: true, children: frameThinking }) }),
|
|
11188
11352
|
bubble.streaming ? /* @__PURE__ */ jsx11(Text11, { children: frameText }) : /* @__PURE__ */ jsx11(Markdown, { children: bubble.text }),
|
|
11189
|
-
bubble.streaming && bubble.text === "" && /* @__PURE__ */
|
|
11190
|
-
/* @__PURE__ */ jsx11(Spinner2, { type: "dots" }),
|
|
11191
|
-
" thinking"
|
|
11192
|
-
] })
|
|
11353
|
+
bubble.streaming && bubble.text === "" && /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "thinking\u2026" })
|
|
11193
11354
|
] });
|
|
11194
11355
|
}
|
|
11195
11356
|
function clipTextToRows(text, maxRows, columns) {
|
|
@@ -11350,7 +11511,7 @@ function SubagentChat({
|
|
|
11350
11511
|
const strings = useStrings();
|
|
11351
11512
|
const [offset, setOffset] = useState7(0);
|
|
11352
11513
|
const total = bubble?.bubbles.length ?? 0;
|
|
11353
|
-
|
|
11514
|
+
useInput3((_input, key) => {
|
|
11354
11515
|
if (key.escape) onClose();
|
|
11355
11516
|
else if (key.upArrow) setOffset((value) => Math.min(Math.max(0, total - 1), value + 1));
|
|
11356
11517
|
else if (key.downArrow) setOffset((value) => Math.max(0, value - 1));
|
|
@@ -11399,25 +11560,44 @@ function SubagentChat({
|
|
|
11399
11560
|
|
|
11400
11561
|
// src/ui/components/TerminalViewport.tsx
|
|
11401
11562
|
import { Box as Box13 } from "ink";
|
|
11402
|
-
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
11403
|
-
var
|
|
11563
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
11564
|
+
var CHROME_ROWS = 16;
|
|
11404
11565
|
var MAX_LIVE_ROWS = 11;
|
|
11405
11566
|
var MIN_LIVE_ROWS = 4;
|
|
11406
|
-
|
|
11567
|
+
var BOTTOM_SLACK_ROWS = 3;
|
|
11568
|
+
function liveTranscriptRows(rows, chromeRows) {
|
|
11407
11569
|
if (!Number.isFinite(rows)) return MAX_LIVE_ROWS;
|
|
11408
|
-
|
|
11570
|
+
const chrome = chromeRows ?? CHROME_ROWS;
|
|
11571
|
+
const budget = Math.floor(rows) - chrome - BOTTOM_SLACK_ROWS - 1;
|
|
11572
|
+
return Math.max(MIN_LIVE_ROWS, Math.min(MAX_LIVE_ROWS, budget));
|
|
11409
11573
|
}
|
|
11410
11574
|
function TerminalViewport({ children, rows }) {
|
|
11411
11575
|
const { columns } = useTerminalSize();
|
|
11412
|
-
|
|
11576
|
+
const liveRows = liveTranscriptRows(rows);
|
|
11577
|
+
const items = Array.isArray(children) ? children : [children];
|
|
11578
|
+
const [transcript, ...chromeChildren] = items;
|
|
11579
|
+
return /* @__PURE__ */ jsxs13(
|
|
11413
11580
|
Box13,
|
|
11414
11581
|
{
|
|
11415
|
-
width: columns,
|
|
11582
|
+
width: columns - 1,
|
|
11416
11583
|
maxWidth: "100%",
|
|
11417
11584
|
flexDirection: "column",
|
|
11418
|
-
maxHeight:
|
|
11585
|
+
maxHeight: liveRows + CHROME_ROWS,
|
|
11419
11586
|
overflowY: "hidden",
|
|
11420
|
-
children
|
|
11587
|
+
children: [
|
|
11588
|
+
/* @__PURE__ */ jsx13(
|
|
11589
|
+
Box13,
|
|
11590
|
+
{
|
|
11591
|
+
flexDirection: "column",
|
|
11592
|
+
flexShrink: 1,
|
|
11593
|
+
minHeight: 0,
|
|
11594
|
+
maxHeight: liveRows,
|
|
11595
|
+
overflowY: "hidden",
|
|
11596
|
+
children: transcript
|
|
11597
|
+
}
|
|
11598
|
+
),
|
|
11599
|
+
/* @__PURE__ */ jsx13(Box13, { flexDirection: "column", flexShrink: 0, children: chromeChildren })
|
|
11600
|
+
]
|
|
11421
11601
|
}
|
|
11422
11602
|
);
|
|
11423
11603
|
}
|
|
@@ -11675,7 +11855,7 @@ function safeSummary(summarize, name, input) {
|
|
|
11675
11855
|
}
|
|
11676
11856
|
|
|
11677
11857
|
// src/ui/App.tsx
|
|
11678
|
-
import { jsx as jsx14, jsxs as
|
|
11858
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
11679
11859
|
var EFFORTS = ["auto", "low", "medium", "high", "xhigh", "max"];
|
|
11680
11860
|
var STREAM_FRAME_MS = 50;
|
|
11681
11861
|
var CUSTOM_ACCENT = "__custom__";
|
|
@@ -11957,6 +12137,7 @@ function App({
|
|
|
11957
12137
|
});
|
|
11958
12138
|
sessionStart.current = Date.now();
|
|
11959
12139
|
turns.current = 0;
|
|
12140
|
+
speedMeter.current = createSpeedMeter();
|
|
11960
12141
|
void runtime.persist([]).catch(
|
|
11961
12142
|
(error) => notice("error", error instanceof Error ? error.message : String(error))
|
|
11962
12143
|
);
|
|
@@ -12693,6 +12874,68 @@ ${strings.mcpAddUsage}`
|
|
|
12693
12874
|
notice("info", runtime.readMemory() || strings.memoryEmpty);
|
|
12694
12875
|
return;
|
|
12695
12876
|
}
|
|
12877
|
+
case "systemp": {
|
|
12878
|
+
const sub = rest[0]?.toLowerCase();
|
|
12879
|
+
if (sub === "set") {
|
|
12880
|
+
const text = rawRest.replace(/^\S+\s*/, "").trim();
|
|
12881
|
+
if (!text) {
|
|
12882
|
+
const typed = await promptInput(strings.systemPromptTitle);
|
|
12883
|
+
if (!typed || typed.trim() === "") return;
|
|
12884
|
+
await runtime.setSystemPrompt(typed);
|
|
12885
|
+
notice("info", strings.systemPromptSet);
|
|
12886
|
+
return;
|
|
12887
|
+
}
|
|
12888
|
+
await runtime.setSystemPrompt(text);
|
|
12889
|
+
notice("info", strings.systemPromptSet);
|
|
12890
|
+
return;
|
|
12891
|
+
}
|
|
12892
|
+
if (sub === "load") {
|
|
12893
|
+
const filePath = rawRest.replace(/^\S+\s*/, "").trim();
|
|
12894
|
+
if (!filePath) {
|
|
12895
|
+
notice("warn", strings.systemPromptUsage);
|
|
12896
|
+
return;
|
|
12897
|
+
}
|
|
12898
|
+
try {
|
|
12899
|
+
const text = await runtime.loadSystemPromptFile(filePath);
|
|
12900
|
+
await runtime.setSystemPrompt(text);
|
|
12901
|
+
notice("info", strings.systemPromptSet);
|
|
12902
|
+
} catch (error) {
|
|
12903
|
+
notice("error", error instanceof Error ? error.message : String(error));
|
|
12904
|
+
}
|
|
12905
|
+
return;
|
|
12906
|
+
}
|
|
12907
|
+
if (sub === "clear") {
|
|
12908
|
+
if (!runtime.getSystemPrompt()) {
|
|
12909
|
+
notice("info", strings.systemPromptEmpty);
|
|
12910
|
+
return;
|
|
12911
|
+
}
|
|
12912
|
+
await runtime.setSystemPrompt("");
|
|
12913
|
+
notice("info", strings.systemPromptCleared);
|
|
12914
|
+
return;
|
|
12915
|
+
}
|
|
12916
|
+
if (sub === "on") {
|
|
12917
|
+
await runtime.setSystemPromptEnabled(true);
|
|
12918
|
+
notice("info", strings.systemPromptEnabled);
|
|
12919
|
+
return;
|
|
12920
|
+
}
|
|
12921
|
+
if (sub === "off") {
|
|
12922
|
+
await runtime.setSystemPromptEnabled(false);
|
|
12923
|
+
notice("info", strings.systemPromptDisabled);
|
|
12924
|
+
return;
|
|
12925
|
+
}
|
|
12926
|
+
if (sub !== void 0 && sub !== "" && sub !== "show") {
|
|
12927
|
+
notice("warn", strings.systemPromptUsage);
|
|
12928
|
+
return;
|
|
12929
|
+
}
|
|
12930
|
+
const current = runtime.getSystemPrompt();
|
|
12931
|
+
if (!current) {
|
|
12932
|
+
notice("info", strings.systemPromptEmpty);
|
|
12933
|
+
return;
|
|
12934
|
+
}
|
|
12935
|
+
const enabled = runtime.isSystemPromptEnabled();
|
|
12936
|
+
notice("info", (enabled ? "" : "[disabled] ") + current);
|
|
12937
|
+
return;
|
|
12938
|
+
}
|
|
12696
12939
|
case "effort": {
|
|
12697
12940
|
notice("info", runtime.effortDescription(history.current));
|
|
12698
12941
|
const choice = EFFORTS.includes(rawRest) ? rawRest : await pick(
|
|
@@ -12705,6 +12948,21 @@ ${strings.mcpAddUsage}`
|
|
|
12705
12948
|
forceRender((n) => n + 1);
|
|
12706
12949
|
return;
|
|
12707
12950
|
}
|
|
12951
|
+
case "steps": {
|
|
12952
|
+
const current = runtime.getMaxTurnSteps();
|
|
12953
|
+
if (!rest[0]) {
|
|
12954
|
+
notice("info", strings.stepsCurrent(current));
|
|
12955
|
+
return;
|
|
12956
|
+
}
|
|
12957
|
+
const parsed = Number(rest[0]);
|
|
12958
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 1e3) {
|
|
12959
|
+
notice("warn", strings.stepsInvalid);
|
|
12960
|
+
return;
|
|
12961
|
+
}
|
|
12962
|
+
await runtime.setMaxTurnSteps(parsed);
|
|
12963
|
+
notice("info", parsed === 0 ? strings.stepsUnlimited : strings.stepsSet(parsed));
|
|
12964
|
+
return;
|
|
12965
|
+
}
|
|
12708
12966
|
case "budget": {
|
|
12709
12967
|
const current = runtime.getMaxTokensPerTurn();
|
|
12710
12968
|
if (rest[0]) {
|
|
@@ -13194,13 +13452,16 @@ ${strings.mcpAddUsage}`
|
|
|
13194
13452
|
notice("info", `${summary2}
|
|
13195
13453
|
${strings.configAt(runtime.configPath())}`);
|
|
13196
13454
|
return summary2;
|
|
13455
|
+
},
|
|
13456
|
+
onCancel: () => {
|
|
13457
|
+
if (!runtime.needsSetup()) setSetup(false);
|
|
13197
13458
|
}
|
|
13198
13459
|
}
|
|
13199
13460
|
)
|
|
13200
13461
|
);
|
|
13201
13462
|
}
|
|
13202
13463
|
return shell(
|
|
13203
|
-
/* @__PURE__ */
|
|
13464
|
+
/* @__PURE__ */ jsxs14(TerminalViewport, { rows, children: [
|
|
13204
13465
|
/* @__PURE__ */ jsx14(
|
|
13205
13466
|
Transcript,
|
|
13206
13467
|
{
|
|
@@ -13330,10 +13591,10 @@ function TextInputOverlay({
|
|
|
13330
13591
|
const submit = useCallback(() => {
|
|
13331
13592
|
onAnswer(value || null);
|
|
13332
13593
|
}, [value, onAnswer]);
|
|
13333
|
-
|
|
13594
|
+
useInput4((_input, key) => {
|
|
13334
13595
|
if (key.escape) onCancel();
|
|
13335
13596
|
});
|
|
13336
|
-
return /* @__PURE__ */
|
|
13597
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
13337
13598
|
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: title }),
|
|
13338
13599
|
/* @__PURE__ */ jsx14(
|
|
13339
13600
|
TextInput2,
|
|
@@ -13453,10 +13714,15 @@ function clearTerminal() {
|
|
|
13453
13714
|
if (process.stdout.isTTY) process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
13454
13715
|
}
|
|
13455
13716
|
var TUI_RENDER_OPTIONS = {
|
|
13456
|
-
//
|
|
13457
|
-
//
|
|
13458
|
-
|
|
13459
|
-
|
|
13717
|
+
// Incremental rendering is off: Ink's incremental diff races with its own
|
|
13718
|
+
// <Static> commits and leaves stale rows behind (the prompt frame appears
|
|
13719
|
+
// twice). Standard rendering clears the whole frame each time — a little
|
|
13720
|
+
// more work, but no stale lines.
|
|
13721
|
+
incrementalRendering: false,
|
|
13722
|
+
// Throttling defers writes; when a bubble closes into <Static> mid-stream,
|
|
13723
|
+
// the deferred frame and the static write race and leave stale rows behind.
|
|
13724
|
+
// Unthrottled renders cost a little CPU but keep every frame consistent.
|
|
13725
|
+
maxFps: 0
|
|
13460
13726
|
};
|
|
13461
13727
|
async function startTui(options) {
|
|
13462
13728
|
const { runtime, history, warnings, shutdown } = await boot({
|