koneck 2.41.0 → 2.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +169 -8
- package/dist/engine.js.map +1 -1
- package/dist/lean-mode.d.ts +31 -0
- package/dist/lean-mode.d.ts.map +1 -1
- package/dist/lean-mode.js +69 -0
- package/dist/lean-mode.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +9 -18
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/usage.d.ts +42 -2
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +75 -6
- package/dist/usage.js.map +1 -1
- package/package.json +1 -1
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAsB5B,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
CHANGED
|
@@ -18,7 +18,7 @@ import { resolveSandbox, describeSandbox } from './sandbox.js';
|
|
|
18
18
|
import { loadImages, buildUserContent, imageMime, looksLikeVisionUnsupported, visionUnsupportedNotice, } from './images.js';
|
|
19
19
|
import { parseTextToolCalls, paramTypesFrom, looksLikeTextToolCall, stripTemplateTokens, splitEmittable, parseCommandStyleCalls, toolShapesFrom } from './tool-call-text.js';
|
|
20
20
|
import { isIdentityQuestion, identityAnswer } from './identity.js';
|
|
21
|
-
import { leanTools,
|
|
21
|
+
import { leanTools, leanModeNotice, findToolsSchema, matchDeferred, deferredToolNotice, FIND_TOOLS } from './lean-mode.js';
|
|
22
22
|
import { findTailRepetition, trimTailRepetition, repetitionNotice, CHECK_EVERY } from './repetition.js';
|
|
23
23
|
import { loadMemory } from './memory.js';
|
|
24
24
|
import { detectProject, loadAgentInstructions, projectSummary } from './project.js';
|
|
@@ -37,6 +37,7 @@ import { readRouterFailure, readReroutedFailure } from './router-failure.js';
|
|
|
37
37
|
import { CheckpointRecorder, filesTouchedBy, snapshotTree, captureCommandEffects } from './checkpoint.js';
|
|
38
38
|
import { resolveMaxTurns } from './run-limits.js';
|
|
39
39
|
import { selfCritiqueSkippedNotice } from './completion-notices.js';
|
|
40
|
+
import { learnedWindow, noteRefusedAt, noteAcceptedAt } from './usage.js';
|
|
40
41
|
export { resolveMaxTurns } from './run-limits.js';
|
|
41
42
|
// ─── Provider error reporting ─────────────────────────────────────────────────
|
|
42
43
|
/**
|
|
@@ -82,7 +83,19 @@ export function describeProviderError(err, provider, model) {
|
|
|
82
83
|
: status === 404
|
|
83
84
|
? `${provider} does not recognise model "${model}". Use /models to pick one it offers.`
|
|
84
85
|
: status === 400
|
|
85
|
-
|
|
86
|
+
// A 400 that names a length is not a malformed request, and telling somebody to check their
|
|
87
|
+
// model or parameters sends them looking in the wrong place entirely. Measured: a gateway
|
|
88
|
+
// saying "maximum context length is 8192 tokens" was reported as "rejected the request as
|
|
89
|
+
// malformed — often an unsupported model or parameter".
|
|
90
|
+
? looksLikeContextOverflow(err)
|
|
91
|
+
? `${provider} refused the request for its length. The model serving it has a smaller `
|
|
92
|
+
+ `context window than the request needed`
|
|
93
|
+
+ (parseContextLimit(err) ? ` — it accepts ${parseContextLimit(err).toLocaleString()} `
|
|
94
|
+
+ `tokens` : '')
|
|
95
|
+
+ `. KONECK reduces the tool list and compacts the conversation and retries; if it still `
|
|
96
|
+
+ `does not fit, the conversation is too long for this model or the alias is routing to `
|
|
97
|
+
+ `one that is too small.`
|
|
98
|
+
: `${provider} rejected the request as malformed — often an unsupported model or parameter.`
|
|
86
99
|
: status && status >= 500
|
|
87
100
|
? `${provider} had a server error (${status}). Usually transient; retrying is reasonable.`
|
|
88
101
|
: undefined;
|
|
@@ -945,14 +958,50 @@ detectedContext = { current: 0 }) {
|
|
|
945
958
|
// Recomputed each turn rather than fixed at the start: the provider's answer arrives after the
|
|
946
959
|
// session is already running, and an overflow complaint can correct it later still.
|
|
947
960
|
let contextLimit = contextLimitFor(config.model, config.contextTokens);
|
|
948
|
-
|
|
949
|
-
|
|
961
|
+
/** Where this model is remembered from: provider and model together, since an alias differs per gateway. */
|
|
962
|
+
const windowKey = `${config.provider}:${config.model}`;
|
|
963
|
+
/*
|
|
964
|
+
* What has actually been proven about this model's window, from previous sessions.
|
|
965
|
+
*
|
|
966
|
+
* The reported number is not evidence. A gateway alias advertises the window of the largest model
|
|
967
|
+
* behind it — 1,048,576 for one that refuses at 4,096 — so believing it means discovering the
|
|
968
|
+
* truth by failing, once per session, for ever.
|
|
969
|
+
*/
|
|
970
|
+
const learned = learnedWindow(windowKey, config.stateHome);
|
|
971
|
+
let refusedAbove = learned.refusedAt;
|
|
972
|
+
/**
|
|
973
|
+
* The window to plan against.
|
|
974
|
+
*
|
|
975
|
+
* A proven refusal is a ceiling and outranks everything, including a bigger number the provider
|
|
976
|
+
* advertised — which is the bug this replaces: `Math.max(guess, detected)` meant a refusal that
|
|
977
|
+
* corrected the limit down to 4,096 was overridden by the alias's 1,048,576 on the very next
|
|
978
|
+
* turn, so the correction could never take effect and the same wall was hit again.
|
|
979
|
+
*/
|
|
980
|
+
const effectiveLimit = () => {
|
|
981
|
+
const optimistic = config.contextTokens ? contextLimit
|
|
982
|
+
: Math.max(contextLimit, detectedContext.current || 0);
|
|
983
|
+
return refusedAbove !== undefined ? Math.min(optimistic, refusedAbove) : optimistic;
|
|
984
|
+
};
|
|
985
|
+
if (refusedAbove !== undefined && !silent) {
|
|
986
|
+
tui.printThinking(`${config.model} refused ${refusedAbove.toLocaleString()} tokens before; planning under that.`);
|
|
987
|
+
}
|
|
950
988
|
let lastPromptTokens = 0;
|
|
951
989
|
/** Said once: the server's window is a property of the session, not of a turn. */
|
|
952
990
|
let truncationSeen = false;
|
|
953
991
|
/** Reported prompt counts against the history that produced them, for spotting a plateau. */
|
|
954
992
|
const promptSamples = [];
|
|
955
993
|
let forceCompact = false;
|
|
994
|
+
/** Whether the tool list has already been cut down after a refusal for length. Once only. */
|
|
995
|
+
let toolsReducedForSize = false;
|
|
996
|
+
/**
|
|
997
|
+
* Tools taken out of the list but kept reachable, by name.
|
|
998
|
+
*
|
|
999
|
+
* Dropping a tool is a real loss — the model cannot use what it cannot see, so a lean session
|
|
1000
|
+
* genuinely could not browse or ask the compiler. Deferring costs a name and a few words each
|
|
1001
|
+
* instead of a whole schema each, and loses nothing: anything here can be fetched the moment it
|
|
1002
|
+
* is wanted.
|
|
1003
|
+
*/
|
|
1004
|
+
let deferred = [];
|
|
956
1005
|
/**
|
|
957
1006
|
* True once any tool call has actually run in this session.
|
|
958
1007
|
*
|
|
@@ -994,10 +1043,14 @@ detectedContext = { current: 0 }) {
|
|
|
994
1043
|
if (config.leanTools !== false && overheadIsCrowded(fixed, effectiveLimit())) {
|
|
995
1044
|
const lean = leanTools(openaiTools);
|
|
996
1045
|
if (lean.dropped.length > 0) {
|
|
997
|
-
|
|
998
|
-
//
|
|
999
|
-
|
|
1000
|
-
|
|
1046
|
+
// Kept, not discarded: the full schemas go into the deferred pool and come back the moment
|
|
1047
|
+
// the model asks for one.
|
|
1048
|
+
deferred = openaiTools.filter(t => lean.dropped.includes(t.function.name));
|
|
1049
|
+
openaiTools = [
|
|
1050
|
+
...lean.tools,
|
|
1051
|
+
findToolsSchema(lean.dropped),
|
|
1052
|
+
];
|
|
1053
|
+
messages.push({ role: 'system', content: deferredToolNotice(lean.dropped) });
|
|
1001
1054
|
config.onLeanMode?.(lean.dropped, effectiveLimit(), leanModeNotice(lean, effectiveLimit()));
|
|
1002
1055
|
if (!silent)
|
|
1003
1056
|
tui.printWarning(leanModeNotice(lean, effectiveLimit()));
|
|
@@ -1197,6 +1250,24 @@ detectedContext = { current: 0 }) {
|
|
|
1197
1250
|
// against what was counted and reported truncation on servers that truncated nothing —
|
|
1198
1251
|
// estimating the sent size from characters carries far too much error to be one side of
|
|
1199
1252
|
// that comparison.
|
|
1253
|
+
if (chunk.usage.prompt_tokens) {
|
|
1254
|
+
/*
|
|
1255
|
+
* A prompt this size went through, so remember that too.
|
|
1256
|
+
*
|
|
1257
|
+
* Without it a remembered ceiling could only ever fall. A runtime restarted with a
|
|
1258
|
+
* bigger window, or an alias that stops routing to the small model, would keep getting
|
|
1259
|
+
* a needlessly lean prompt for ever because of one refusal weeks ago. A success is
|
|
1260
|
+
* evidence in the other direction and is worth exactly as much.
|
|
1261
|
+
*/
|
|
1262
|
+
noteAcceptedAt(windowKey, chunk.usage.prompt_tokens, config.stateHome);
|
|
1263
|
+
if (refusedAbove !== undefined && chunk.usage.prompt_tokens > refusedAbove) {
|
|
1264
|
+
refusedAbove = undefined;
|
|
1265
|
+
if (!silent) {
|
|
1266
|
+
tui.printThinking(`${config.model} accepted ${chunk.usage.prompt_tokens.toLocaleString()} tokens — `
|
|
1267
|
+
+ `the remembered limit was wrong and has been dropped.`);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1200
1271
|
if (!truncationSeen && chunk.usage.prompt_tokens) {
|
|
1201
1272
|
promptSamples.push({
|
|
1202
1273
|
sentChars: JSON.stringify(messages).length,
|
|
@@ -1354,6 +1425,56 @@ detectedContext = { current: 0 }) {
|
|
|
1354
1425
|
if (!silent)
|
|
1355
1426
|
tui.printThinking(`${config.model} accepts ${stated.toLocaleString()} tokens; noted.`);
|
|
1356
1427
|
}
|
|
1428
|
+
/*
|
|
1429
|
+
* Written down, so this is the last session that has to learn it.
|
|
1430
|
+
*
|
|
1431
|
+
* The ceiling is whichever is lower: the number the provider stated, or the size of the
|
|
1432
|
+
* request it just refused. Both are facts about this model; the smaller one is the safe
|
|
1433
|
+
* one to plan against.
|
|
1434
|
+
*/
|
|
1435
|
+
// Measured from what was actually assembled, since the provider's complaint does not
|
|
1436
|
+
// always carry a number and the request itself always does.
|
|
1437
|
+
const refusedSize = Math.max(1, Math.round((JSON.stringify(messages).length + JSON.stringify(openaiTools).length) / 4));
|
|
1438
|
+
const ceiling = stated ?? refusedSize;
|
|
1439
|
+
refusedAbove = refusedAbove === undefined ? ceiling : Math.min(refusedAbove, ceiling);
|
|
1440
|
+
noteRefusedAt(windowKey, refusedAbove, config.stateHome);
|
|
1441
|
+
/*
|
|
1442
|
+
* Compacting the conversation is not enough on its own, and on the first turn it does
|
|
1443
|
+
* nothing at all.
|
|
1444
|
+
*
|
|
1445
|
+
* Measured against a model that refuses at 8,192 tokens: the request was 22,597 characters,
|
|
1446
|
+
* of which 10,808 — forty-eight per cent — were the schemas for sixteen tools. Compaction
|
|
1447
|
+
* touches the messages and never the tools, so a refusal on the FIRST turn produced a retry
|
|
1448
|
+
* that was byte-for-byte identical to the request just refused, then a second, then the run
|
|
1449
|
+
* ended. Reported as "I always come across it and no task finishes", which is exactly what
|
|
1450
|
+
* an identical retry of a deterministic refusal looks like.
|
|
1451
|
+
*
|
|
1452
|
+
* So the tools come down too. This is not a limit KONECK is imposing: the endpoint has
|
|
1453
|
+
* already refused, and the choice is a smaller tool list or no answer at all.
|
|
1454
|
+
*/
|
|
1455
|
+
if (config.leanTools !== false && !toolsReducedForSize) {
|
|
1456
|
+
const lean = leanTools(openaiTools);
|
|
1457
|
+
if (lean.dropped.length > 0) {
|
|
1458
|
+
toolsReducedForSize = true;
|
|
1459
|
+
deferred = openaiTools.filter(t => lean.dropped.includes(t.function.name));
|
|
1460
|
+
openaiTools = [
|
|
1461
|
+
...lean.tools,
|
|
1462
|
+
findToolsSchema(lean.dropped),
|
|
1463
|
+
];
|
|
1464
|
+
messages.push({ role: 'system', content: deferredToolNotice(lean.dropped) });
|
|
1465
|
+
const saved = lean.beforeChars - lean.afterChars;
|
|
1466
|
+
const notice = `The model refused the prompt for its length`
|
|
1467
|
+
+ (stated ? ` (it accepts ${stated.toLocaleString()} tokens)` : '')
|
|
1468
|
+
+ `. Retrying with ${lean.tools.length} tools instead of `
|
|
1469
|
+
+ `${lean.tools.length + lean.dropped.length}, which is `
|
|
1470
|
+
+ `${Math.round(saved / 4).toLocaleString()} fewer tokens of schema.`;
|
|
1471
|
+
config.onLeanMode?.(lean.dropped, contextLimit ?? 0, notice);
|
|
1472
|
+
if (!silent)
|
|
1473
|
+
tui.printWarning(notice);
|
|
1474
|
+
turn--; // do this turn again
|
|
1475
|
+
continue;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1357
1478
|
if (!forceCompact) {
|
|
1358
1479
|
forceCompact = true;
|
|
1359
1480
|
if (!silent)
|
|
@@ -1817,6 +1938,46 @@ detectedContext = { current: 0 }) {
|
|
|
1817
1938
|
catch { /* use empty */ }
|
|
1818
1939
|
result = await callMCPTool(serverName, toolName, parsed, mcpClients);
|
|
1819
1940
|
}
|
|
1941
|
+
else if (effectiveName === FIND_TOOLS) {
|
|
1942
|
+
/*
|
|
1943
|
+
* Handled here rather than in tools.ts, because the answer is a change to the request
|
|
1944
|
+
* itself: the schemas have to enter the live list, which only this loop holds.
|
|
1945
|
+
*/
|
|
1946
|
+
let query = '';
|
|
1947
|
+
try {
|
|
1948
|
+
query = String(JSON.parse(tc.arguments).query ?? '');
|
|
1949
|
+
}
|
|
1950
|
+
catch {
|
|
1951
|
+
query = '';
|
|
1952
|
+
}
|
|
1953
|
+
const wanted = matchDeferred(query, deferred);
|
|
1954
|
+
const added = deferred.filter(t => wanted.includes(t.function.name));
|
|
1955
|
+
if (added.length === 0) {
|
|
1956
|
+
result = 'No further tools are available — everything is already in your list.';
|
|
1957
|
+
}
|
|
1958
|
+
else {
|
|
1959
|
+
deferred = deferred.filter(t => !wanted.includes(t.function.name));
|
|
1960
|
+
// Inserted before find_tools so the list stays readable, and find_tools stays last for
|
|
1961
|
+
// as long as anything is still deferred.
|
|
1962
|
+
const keepFinder = deferred.length > 0;
|
|
1963
|
+
openaiTools = [
|
|
1964
|
+
...openaiTools.filter(t => t.function.name !== FIND_TOOLS),
|
|
1965
|
+
...added,
|
|
1966
|
+
...(keepFinder
|
|
1967
|
+
? [findToolsSchema(deferred.map(t => t.function.name))]
|
|
1968
|
+
: []),
|
|
1969
|
+
];
|
|
1970
|
+
config.onToolsLoaded?.(added.map(t => t.function.name));
|
|
1971
|
+
if (!silent) {
|
|
1972
|
+
tui.printThinking(`Loaded ${added.map(t => t.function.name).join(', ')}.`);
|
|
1973
|
+
}
|
|
1974
|
+
result = `Now available: ${added.map(t => t.function.name).join(', ')}. `
|
|
1975
|
+
+ `Call them directly.`
|
|
1976
|
+
+ (deferred.length > 0
|
|
1977
|
+
? ` Still on request: ${deferred.map(t => t.function.name).join(', ')}.`
|
|
1978
|
+
: '');
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1820
1981
|
else if (effectiveName === 'plan') {
|
|
1821
1982
|
let parsedPlan = {};
|
|
1822
1983
|
try {
|