koneck 2.53.0 → 2.54.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/chat.d.ts.map +1 -1
- package/dist/chat.js +21 -2
- package/dist/chat.js.map +1 -1
- package/dist/config-store.d.ts +6 -0
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +2 -1
- package/dist/config-store.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +105 -2
- package/dist/engine.js.map +1 -1
- package/dist/failover.d.ts +95 -0
- package/dist/failover.d.ts.map +1 -0
- package/dist/failover.js +191 -0
- package/dist/failover.js.map +1 -0
- package/dist/ink-chat.d.ts.map +1 -1
- package/dist/ink-chat.js +37 -2
- package/dist/ink-chat.js.map +1 -1
- package/dist/tui.d.ts +8 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +12 -0
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/web/api.d.ts +1 -1
- package/dist/web/api.d.ts.map +1 -1
- package/dist/web/api.js +45 -1
- package/dist/web/api.js.map +1 -1
- package/dist/web/changes.d.ts.map +1 -1
- package/dist/web/changes.js +21 -2
- package/dist/web/changes.js.map +1 -1
- package/dist/web/sessions.d.ts +8 -0
- package/dist/web/sessions.d.ts.map +1 -1
- package/dist/web/sessions.js +36 -0
- package/dist/web/sessions.js.map +1 -1
- package/dist/web/ui-client.d.ts.map +1 -1
- package/dist/web/ui-client.js +117 -6
- package/dist/web/ui-client.js.map +1 -1
- package/dist/web/ui-css.d.ts.map +1 -1
- package/dist/web/ui-css.js +29 -0
- package/dist/web/ui-css.js.map +1 -1
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +42 -0
- package/dist/web/ui.js.map +1 -1
- package/package.json +1 -1
package/dist/failover.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What to do when the model you are on stops being usable.
|
|
3
|
+
*
|
|
4
|
+
* Three things end a run that did not have to end: the credit for a model runs out, a gateway's
|
|
5
|
+
* upstream starts failing, or a rate limit closes the door for a while. In every one of them there
|
|
6
|
+
* is usually another model on the same provider, or another provider entirely, that would have
|
|
7
|
+
* finished the work. KONECK stopped and reported the error, which is correct behaviour and a poor
|
|
8
|
+
* outcome — the user comes back to a dead run and does by hand what could have been done in a
|
|
9
|
+
* second.
|
|
10
|
+
*
|
|
11
|
+
* So this is a policy, and deliberately a policy rather than a cleverness. Switching model
|
|
12
|
+
* mid-task changes the thing doing the work: a different model may write in a different style,
|
|
13
|
+
* cost a different amount, or be worse. That is a decision about someone else's money and someone
|
|
14
|
+
* else's code, so the default is to ask, and everything about it is stated rather than inferred:
|
|
15
|
+
*
|
|
16
|
+
* - `on` which failures count. Out of credit is not the same as a bad gateway.
|
|
17
|
+
* - `scope` another model on this provider, another provider, or both.
|
|
18
|
+
* - `decide` ask, or go ahead and say so afterwards.
|
|
19
|
+
* - `order` the sequence given, or shuffled — a fixed order concentrates load on whatever is
|
|
20
|
+
* first, which is exactly what you do not want when the first one just failed.
|
|
21
|
+
* - `models` the candidates, in the order they should be tried.
|
|
22
|
+
* - `discover` when the list is empty, ask the provider what it serves rather than guessing.
|
|
23
|
+
*
|
|
24
|
+
* Nothing here is on by default. A tool that silently moves your work to a different model is not
|
|
25
|
+
* a tool that respects the user.
|
|
26
|
+
*/
|
|
27
|
+
export const TRIGGERS = ['exhausted', 'failing', 'limited', 'too-long'];
|
|
28
|
+
export const TRIGGER_BLURB = {
|
|
29
|
+
exhausted: 'Out of credit or quota on this model.',
|
|
30
|
+
failing: 'The provider says this model is unavailable or its upstream is failing.',
|
|
31
|
+
limited: 'Rate limited — it would work later, and later may be too late.',
|
|
32
|
+
'too-long': 'The conversation no longer fits this model’s context window.',
|
|
33
|
+
};
|
|
34
|
+
/** Off, and explicit about it. */
|
|
35
|
+
export const FAILOVER_OFF = {
|
|
36
|
+
enabled: false,
|
|
37
|
+
on: ['exhausted', 'failing'],
|
|
38
|
+
scope: 'model',
|
|
39
|
+
decide: 'ask',
|
|
40
|
+
order: 'sequence',
|
|
41
|
+
models: [],
|
|
42
|
+
discover: true,
|
|
43
|
+
limit: 3,
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* A candidate from a string.
|
|
47
|
+
*
|
|
48
|
+
* `provider/model` names both; anything else is a model on whichever provider is current. Model ids
|
|
49
|
+
* contain slashes of their own — `anthropic/claude-sonnet-4.5` is one model, not a provider and a
|
|
50
|
+
* model — so a prefix only counts when it is a provider that actually exists.
|
|
51
|
+
*/
|
|
52
|
+
export function candidateFrom(text, knownProvider) {
|
|
53
|
+
const trimmed = String(text ?? '').trim();
|
|
54
|
+
const cut = trimmed.indexOf('/');
|
|
55
|
+
if (cut > 0) {
|
|
56
|
+
const head = trimmed.slice(0, cut);
|
|
57
|
+
if (knownProvider(head))
|
|
58
|
+
return { provider: head, model: trimmed.slice(cut + 1) };
|
|
59
|
+
}
|
|
60
|
+
return { model: trimmed };
|
|
61
|
+
}
|
|
62
|
+
/** A policy from whatever a config file holds, with every field defaulted rather than assumed. */
|
|
63
|
+
export function policyFrom(raw, knownProvider = () => false) {
|
|
64
|
+
const held = (raw ?? {});
|
|
65
|
+
const on = Array.isArray(held['on'])
|
|
66
|
+
? held['on']
|
|
67
|
+
.map(v => String(v).trim().toLowerCase())
|
|
68
|
+
.filter((v) => TRIGGERS.includes(v))
|
|
69
|
+
: FAILOVER_OFF.on;
|
|
70
|
+
const scopeAsked = ['model', 'provider', 'both'].includes(String(held['scope']))
|
|
71
|
+
? held['scope'] : FAILOVER_OFF.scope;
|
|
72
|
+
/*
|
|
73
|
+
* A prefix is only a provider when moving provider is on the table.
|
|
74
|
+
*
|
|
75
|
+
* `anthropic/claude-sonnet-4.5` is genuinely ambiguous: it is a provider and a model, and it is
|
|
76
|
+
* also one model id on OpenRouter. Nothing in the string settles it — but the scope does. Somebody
|
|
77
|
+
* who has said "another model, same provider" has already said they mean model ids, so splitting
|
|
78
|
+
* their list on the first slash would send the run to a provider they excluded on purpose.
|
|
79
|
+
*/
|
|
80
|
+
const splitProviders = scopeAsked !== 'model';
|
|
81
|
+
const models = Array.isArray(held['models'])
|
|
82
|
+
? held['models']
|
|
83
|
+
.map(entry => typeof entry === 'string'
|
|
84
|
+
? candidateFrom(entry, splitProviders ? knownProvider : () => false)
|
|
85
|
+
: { provider: typeof entry?.provider === 'string'
|
|
86
|
+
? entry.provider : undefined,
|
|
87
|
+
model: String(entry?.model ?? '').trim() })
|
|
88
|
+
.filter(c => c.model !== '')
|
|
89
|
+
: [];
|
|
90
|
+
const decide = String(held['decide']) === 'auto' ? 'auto' : 'ask';
|
|
91
|
+
const order = String(held['order']) === 'random' ? 'random' : 'sequence';
|
|
92
|
+
const limit = Number.isFinite(Number(held['limit'])) && Number(held['limit']) > 0
|
|
93
|
+
? Math.min(Math.floor(Number(held['limit'])), 20) : FAILOVER_OFF.limit;
|
|
94
|
+
return {
|
|
95
|
+
enabled: held['enabled'] === true,
|
|
96
|
+
on: on.length > 0 ? on : FAILOVER_OFF.on,
|
|
97
|
+
scope: scopeAsked,
|
|
98
|
+
decide,
|
|
99
|
+
order,
|
|
100
|
+
models,
|
|
101
|
+
discover: held['discover'] !== false,
|
|
102
|
+
limit,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Which trigger a failure is, if it is one at all.
|
|
107
|
+
*
|
|
108
|
+
* Read from what the provider said rather than from a status code alone, because the codes are
|
|
109
|
+
* shared: a 400 is a context overflow and a malformed request and an unsupported parameter, and
|
|
110
|
+
* treating all of them as "move to another model" would move away from a model that was fine.
|
|
111
|
+
*/
|
|
112
|
+
export function triggerFor(err) {
|
|
113
|
+
const holder = err;
|
|
114
|
+
const text = [
|
|
115
|
+
typeof holder?.message === 'string' ? holder.message : '',
|
|
116
|
+
typeof holder?.error?.message === 'string' ? holder.error.message : '',
|
|
117
|
+
typeof holder?.error?.code === 'string' ? holder.error.code : '',
|
|
118
|
+
].join(' ').toLowerCase();
|
|
119
|
+
const status = typeof holder?.status === 'number' ? holder.status : undefined;
|
|
120
|
+
if (/insufficient_quota|out of credit|no credit|credit balance|billing|payment required|quota exceeded/
|
|
121
|
+
.test(text))
|
|
122
|
+
return 'exhausted';
|
|
123
|
+
if (status === 402)
|
|
124
|
+
return 'exhausted';
|
|
125
|
+
if (/context length|context window|too many tokens|maximum context|prompt is too long/
|
|
126
|
+
.test(text))
|
|
127
|
+
return 'too-long';
|
|
128
|
+
if (/rate limit|too many requests|slow down|try again in/.test(text))
|
|
129
|
+
return 'limited';
|
|
130
|
+
if (status === 429)
|
|
131
|
+
return 'limited';
|
|
132
|
+
if (/failing upstream|no active credentials for provider|upstream error|bad_gateway|model_not_found|no endpoints|unavailable|overloaded|service unavailable/
|
|
133
|
+
.test(text))
|
|
134
|
+
return 'failing';
|
|
135
|
+
if (status === 502 || status === 503)
|
|
136
|
+
return 'failing';
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The next place to try, or null when there is nowhere left.
|
|
141
|
+
*
|
|
142
|
+
* `tried` is every candidate already used this run, including the one started on — otherwise a
|
|
143
|
+
* shuffled order returns to a model that has just failed, and a fixed order can loop on it
|
|
144
|
+
* forever. Candidates outside the scope are filtered here rather than at the edges, so a policy
|
|
145
|
+
* that says "models only" cannot move provider by way of a candidate that named one.
|
|
146
|
+
*/
|
|
147
|
+
export function pickNext(policy, current, tried, discovered = [], random = Math.random) {
|
|
148
|
+
if (!policy.enabled)
|
|
149
|
+
return null;
|
|
150
|
+
const pool = policy.models.length > 0
|
|
151
|
+
? policy.models
|
|
152
|
+
: (policy.discover ? discovered : []);
|
|
153
|
+
const allowed = pool.filter(c => {
|
|
154
|
+
const movesProvider = !!c.provider
|
|
155
|
+
&& c.provider.toLowerCase() !== (current.provider ?? '').toLowerCase();
|
|
156
|
+
if (movesProvider && policy.scope === 'model')
|
|
157
|
+
return false;
|
|
158
|
+
if (!movesProvider && policy.scope === 'provider')
|
|
159
|
+
return false;
|
|
160
|
+
return true;
|
|
161
|
+
});
|
|
162
|
+
const seen = new Set(tried.map(k => k.toLowerCase()));
|
|
163
|
+
const fresh = allowed.filter(c => !seen.has(keyOf({
|
|
164
|
+
provider: c.provider ?? current.provider, model: c.model,
|
|
165
|
+
}).toLowerCase()));
|
|
166
|
+
if (fresh.length === 0)
|
|
167
|
+
return null;
|
|
168
|
+
if (policy.order === 'sequence')
|
|
169
|
+
return fresh[0] ?? null;
|
|
170
|
+
// Shuffled, so a failure does not send every session to the same second choice.
|
|
171
|
+
return fresh[Math.min(fresh.length - 1, Math.floor(random() * fresh.length))] ?? null;
|
|
172
|
+
}
|
|
173
|
+
/** The name a candidate is remembered under, so "already tried" survives a missing provider. */
|
|
174
|
+
export function keyOf(c) {
|
|
175
|
+
return `${c.provider ?? ''}/${c.model}`;
|
|
176
|
+
}
|
|
177
|
+
/** What to tell the user, in one line, whichever surface is asking. */
|
|
178
|
+
export function describeSwitch(from, to, trigger) {
|
|
179
|
+
const where = to.provider && to.provider !== from.provider
|
|
180
|
+
? `${to.model} on ${to.provider}`
|
|
181
|
+
: to.model;
|
|
182
|
+
return `${TRIGGER_BLURB[trigger]} Moving from ${from.model} to ${where}.`;
|
|
183
|
+
}
|
|
184
|
+
/** The same thing as a question, for a policy that asks first. */
|
|
185
|
+
export function askSwitch(from, to, trigger) {
|
|
186
|
+
const where = to.provider && to.provider !== from.provider
|
|
187
|
+
? `${to.model} on ${to.provider}`
|
|
188
|
+
: to.model;
|
|
189
|
+
return `${TRIGGER_BLURB[trigger]} Continue on ${where} instead of ${from.model}?`;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=failover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failover.js","sourceRoot":"","sources":["../src/failover.ts"],"names":[],"mappings":"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"}
|
package/dist/ink-chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ink-chat.d.ts","sourceRoot":"","sources":["../src/ink-chat.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ink-chat.d.ts","sourceRoot":"","sources":["../src/ink-chat.tsx"],"names":[],"mappings":"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"}
|
package/dist/ink-chat.js
CHANGED
|
@@ -12,6 +12,7 @@ import { normaliseEndpoint, withEndpoint, savedEndpoints, shortSource, resolveMo
|
|
|
12
12
|
import { loadProjectConfig, loadGlobalConfig, saveGlobalConfig, withoutStoredApiKey } from './config.js';
|
|
13
13
|
import { rememberKey, forgetAllKeys } from './credentials.js';
|
|
14
14
|
import { paceFrom } from './pace.js';
|
|
15
|
+
import { policyFrom, FAILOVER_OFF } from './failover.js';
|
|
15
16
|
import { listCheckpoints, revertCheckpoint, previewCheckpoint, snapshotTree, filesTouchedBy, createWorkspaceCheckpoint, checkpointScope } from './checkpoint.js';
|
|
16
17
|
import { fileDiff, diffSummary } from './diff-view.js';
|
|
17
18
|
import { untrackedPatches } from './git-diff.js';
|
|
@@ -1310,7 +1311,7 @@ function App({ config: initialConfig, clearFrame }) {
|
|
|
1310
1311
|
},
|
|
1311
1312
|
};
|
|
1312
1313
|
const activeSession = useState(() => ({
|
|
1313
|
-
p: createAgentSession({ ...initialConfig, pace: paceFrom(initialConfig.pace ?? savedEffort(undefined), 'medium'), silent: true, ...sessionOpts }),
|
|
1314
|
+
p: createAgentSession({ ...initialConfig, pace: paceFrom(initialConfig.pace ?? savedEffort(undefined), 'medium'), ...failoverHooks(), silent: true, ...sessionOpts }),
|
|
1314
1315
|
}))[0];
|
|
1315
1316
|
const [rows, setRows] = useState([{ role: 'header' }]);
|
|
1316
1317
|
const [draft, setDraft] = useState('');
|
|
@@ -1550,6 +1551,31 @@ function App({ config: initialConfig, clearFrame }) {
|
|
|
1550
1551
|
* session that is already running: rebuilding would throw the conversation away, and waiting for
|
|
1551
1552
|
* the next session is not what somebody who just chose "low" because they are waiting means.
|
|
1552
1553
|
*/
|
|
1554
|
+
/**
|
|
1555
|
+
* What a session is given so it can move to another model, and say so.
|
|
1556
|
+
*
|
|
1557
|
+
* The question goes through addSystem and the same confirm the tool prompts use, so there is one
|
|
1558
|
+
* place where a decision is made rather than a second kind of prompt to learn.
|
|
1559
|
+
*/
|
|
1560
|
+
const failoverHooks = () => ({
|
|
1561
|
+
failover: failoverRef.current,
|
|
1562
|
+
confirmFailover: async (question) => new Promise(resolve => {
|
|
1563
|
+
/*
|
|
1564
|
+
* Through the same queue the tool prompts use.
|
|
1565
|
+
*
|
|
1566
|
+
* Not a second kind of prompt to learn, and not a raw terminal confirm — inquirer writing
|
|
1567
|
+
* over an Ink render is how a UI ends up with two cursors. The queue also means a question
|
|
1568
|
+
* cannot be overwritten by another arriving at the same moment, which is what made an earlier
|
|
1569
|
+
* prompt's promise never settle.
|
|
1570
|
+
*/
|
|
1571
|
+
const isCurrent = askQueueRef.current.add({
|
|
1572
|
+
tool: 'continue on another model', args: question, prefix: '', resolve,
|
|
1573
|
+
});
|
|
1574
|
+
if (isCurrent)
|
|
1575
|
+
showNextAsk();
|
|
1576
|
+
}),
|
|
1577
|
+
onFailover: (message) => addSystem(message),
|
|
1578
|
+
});
|
|
1553
1579
|
const effortRef = useRef('medium');
|
|
1554
1580
|
useEffect(() => {
|
|
1555
1581
|
effortRef.current = effort;
|
|
@@ -1602,12 +1628,21 @@ function App({ config: initialConfig, clearFrame }) {
|
|
|
1602
1628
|
const [termRows, setTermRows] = useState(() => process.stdout.rows || 24);
|
|
1603
1629
|
/** Optional user cap on the UI width. Undefined means fill the terminal. */
|
|
1604
1630
|
const [configMaxWidth, setConfigMaxWidth] = useState(undefined);
|
|
1631
|
+
/*
|
|
1632
|
+
* The failover policy, from the same config file the browser writes.
|
|
1633
|
+
*
|
|
1634
|
+
* One policy per machine rather than one per surface: somebody who decides "move on
|
|
1635
|
+
* automatically" means it wherever they are working, and a setting that has to be made twice is
|
|
1636
|
+
* a setting that will disagree with itself.
|
|
1637
|
+
*/
|
|
1638
|
+
const failoverRef = useRef(FAILOVER_OFF);
|
|
1605
1639
|
useEffect(() => {
|
|
1606
1640
|
void loadKoneckConfig().then(c => {
|
|
1607
1641
|
setConfigMaxWidth(typeof c.maxWidth === 'number' && c.maxWidth >= 40 ? c.maxWidth : undefined);
|
|
1608
1642
|
const configuredEffort = savedEffort(c.effort);
|
|
1609
1643
|
if (configuredEffort)
|
|
1610
1644
|
setEffort(configuredEffort);
|
|
1645
|
+
failoverRef.current = policyFrom(c.failover, name => PROVIDERS[name] !== undefined);
|
|
1611
1646
|
});
|
|
1612
1647
|
}, []);
|
|
1613
1648
|
/**
|
|
@@ -1908,7 +1943,7 @@ function App({ config: initialConfig, clearFrame }) {
|
|
|
1908
1943
|
const c = newCfg ?? cfg;
|
|
1909
1944
|
cfgRef.current = c;
|
|
1910
1945
|
setDetectedContext(null);
|
|
1911
|
-
activeSession.p = createAgentSession({ ...c, pace: paceFrom(effortRef.current, 'medium'), silent: true, ...sessionOpts });
|
|
1946
|
+
activeSession.p = createAgentSession({ ...c, pace: paceFrom(effortRef.current, 'medium'), ...failoverHooks(), silent: true, ...sessionOpts });
|
|
1912
1947
|
if (newCfg)
|
|
1913
1948
|
setCfg(newCfg);
|
|
1914
1949
|
}
|