@vincemakes/kiso-code 0.32.2 → 0.34.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 +1 -1
- package/dist/chat.js +53 -6
- package/dist/index.js +3 -1
- package/dist/resume.js +4 -1
- package/package.json +15 -15
package/dist/chat.d.ts
CHANGED
|
@@ -183,7 +183,7 @@ export declare function parseSaferOptions(text: string): SaferOption[] | null;
|
|
|
183
183
|
* task file has none. 50 is named here; a finding moves it, never a stray
|
|
184
184
|
* edit. */
|
|
185
185
|
export declare const CHECKPOINT_TURNS = 50;
|
|
186
|
-
export declare function consumeRun(session: AgentSession, run: Run, input: LineInput, turnNo: number, faux: boolean, statusCb: ((usage: RunUsage, ctxRatio: number, costUsd?: number | null) => void) | null,
|
|
186
|
+
export declare function consumeRun(session: AgentSession, run: Run, input: LineInput, turnNo: number, faux: boolean, statusCb: ((usage: RunUsage, ctxRatio: number, costUsd?: number | null, tokPerSec?: number | null) => void) | null,
|
|
187
187
|
/** W21: the amend words ("Yes + feedback") ride the NEXT user turn —
|
|
188
188
|
* threaded from chat's submitTurn; absent in the recovery flow
|
|
189
189
|
* (resume) where a dropped amend is noticed instead. */
|
package/dist/chat.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* estimates. All bodies moved verbatim from index.ts.
|
|
6
6
|
*/
|
|
7
7
|
import { readFileSync, statSync } from "node:fs";
|
|
8
|
-
import { escapeTerminal, cacheHitPct, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, verifyOfferView, STATUS_GLYPHS, } from "@vincemakes/kiso-tui";
|
|
8
|
+
import { escapeTerminal, cacheHitPct, decodeRate, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, verifyOfferView, STATUS_GLYPHS, } from "@vincemakes/kiso-tui";
|
|
9
9
|
import { askView, deletionRiskHint, editFileDiff, writeFileDiff } from "@vincemakes/kiso-tui";
|
|
10
10
|
import { canonicalTargetPath, shellProgressPath } from "@vincemakes/kiso-tools-node";
|
|
11
11
|
import { echoText } from "@vincemakes/kiso-tui-cells/render";
|
|
@@ -148,8 +148,18 @@ endpoint) {
|
|
|
148
148
|
// backend's own words and keeps its 0 — the display's rule, not the
|
|
149
149
|
// record's.
|
|
150
150
|
const unobservable = model !== undefined && lookupModelMetadata(model, endpoint)?.capabilities.promptCaching === "unobservable";
|
|
151
|
+
// DF-0322-F2: the DISPLAY is handed the provider's own word, not the
|
|
152
|
+
// canonical one. `canonicalizeUsage` sets `cacheRead ?? 0` because
|
|
153
|
+
// accounting has to sum numbers — correct there, and pinned that way by
|
|
154
|
+
// the gate — but it erases the difference between "the backend answered
|
|
155
|
+
// zero" and "the backend said nothing about caching". Handing the row the
|
|
156
|
+
// canonical zero made it claim a measurement that never happened, which
|
|
157
|
+
// is the family OR-10 and DF-0311-F1 belong to. OR-10's own comment drew
|
|
158
|
+
// this line first: the ledger keeps the backend's 0, the display's rule
|
|
159
|
+
// is not the record's.
|
|
160
|
+
const reportedCache = ev.cacheRead === null ? null : c.cacheRead;
|
|
151
161
|
return {
|
|
152
|
-
usage: { in: c.input, out: c.output, cache: unobservable ? null :
|
|
162
|
+
usage: { in: c.input, out: c.output, cache: unobservable ? null : reportedCache, known: ev.known },
|
|
153
163
|
total,
|
|
154
164
|
missed: unobservable ? null : missed,
|
|
155
165
|
costUsd: c.costUsd,
|
|
@@ -581,6 +591,10 @@ export async function consumeRun(session, run, input, turnNo, faux, statusCb,
|
|
|
581
591
|
submitTurn) {
|
|
582
592
|
let last;
|
|
583
593
|
let usage = { in: null, out: null, cache: null, known: false };
|
|
594
|
+
// TPS-1: the decode clock, armed by the FIRST streamed event of a call
|
|
595
|
+
// and read at that call's usage event. Per CALL, not per turn — a turn
|
|
596
|
+
// with three model calls reports the third, and each one times itself.
|
|
597
|
+
let callFirstEventAt = null;
|
|
584
598
|
let prevTotal = null;
|
|
585
599
|
let missed = null;
|
|
586
600
|
// v3 §02: the recap line derives ENTIRELY from the local event stream
|
|
@@ -644,6 +658,7 @@ submitTurn) {
|
|
|
644
658
|
body.userLine(echoText(ev.content));
|
|
645
659
|
break;
|
|
646
660
|
case "thinking":
|
|
661
|
+
callFirstEventAt ??= Date.now(); // TPS-1: reasoning IS decoding
|
|
647
662
|
body.thinkingAppend(ev.text);
|
|
648
663
|
break;
|
|
649
664
|
case "tool_call_end":
|
|
@@ -694,6 +709,7 @@ submitTurn) {
|
|
|
694
709
|
break;
|
|
695
710
|
}
|
|
696
711
|
case "text_delta":
|
|
712
|
+
callFirstEventAt ??= Date.now(); // TPS-1
|
|
697
713
|
body.textAppend(ev.text);
|
|
698
714
|
break;
|
|
699
715
|
case "text_end":
|
|
@@ -715,7 +731,12 @@ submitTurn) {
|
|
|
715
731
|
missed = delta.missed;
|
|
716
732
|
// TUI2-R1 (E): the request's canonical cost rides the same
|
|
717
733
|
// callback the usage does — one settled request, one addition.
|
|
718
|
-
|
|
734
|
+
// TPS-1: the rate of the call that just settled. The clock is
|
|
735
|
+
// cleared here rather than at the turn boundary, so a turn's
|
|
736
|
+
// second call is timed from ITS own first event.
|
|
737
|
+
const tokPerSec = callFirstEventAt === null ? null : decodeRate(ev.outputTokens, Date.now() - callFirstEventAt);
|
|
738
|
+
callFirstEventAt = null;
|
|
739
|
+
statusCb?.(usage, displayCtxRatio(session), delta.costUsd, tokPerSec);
|
|
719
740
|
break;
|
|
720
741
|
}
|
|
721
742
|
case "uncertain_pending":
|
|
@@ -965,6 +986,7 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
965
986
|
// rotates every 200ms; the idle state returns after the run.
|
|
966
987
|
runStart = Date.now();
|
|
967
988
|
runUsage = { in: null, out: null, cache: null, known: false };
|
|
989
|
+
lastTokPerSec = null; // TPS-1: nothing has settled in THIS turn yet
|
|
968
990
|
const stopSpinner = startStatusSpinner((g) => {
|
|
969
991
|
runGlyph = g;
|
|
970
992
|
paintRunning();
|
|
@@ -1156,11 +1178,25 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1156
1178
|
let spentUsd = null;
|
|
1157
1179
|
let runGlyph = "▖";
|
|
1158
1180
|
let runStart = Date.now();
|
|
1181
|
+
// TPS-1: the decode rate of the last SETTLED call. One variable serves
|
|
1182
|
+
// both rows because they want the same number at different moments;
|
|
1183
|
+
// only the reset points differ, and they are all on the ENTRY side —
|
|
1184
|
+
// cleared when a turn starts (so the running row never shows the
|
|
1185
|
+
// previous turn's figure while a new one is in flight) and when the
|
|
1186
|
+
// binding changes (DF-0311-F1: a model that has not run has no
|
|
1187
|
+
// measurement), never at a turn's END, so the idle row can carry the
|
|
1188
|
+
// last call of the last turn.
|
|
1189
|
+
let lastTokPerSec = null;
|
|
1190
|
+
// DF-0330-F1: the terminal's own width, read at paint time so a resize
|
|
1191
|
+
// is honoured. winsize reports 0 columns in some hosts and 0 is not
|
|
1192
|
+
// nullish, so the guard is `> 0` rather than `??` (the same shape the
|
|
1193
|
+
// compositor's own width call uses).
|
|
1194
|
+
const rowWidth = () => (process.stdout.columns > 0 ? process.stdout.columns : 80);
|
|
1159
1195
|
// KC2 §5: the STATE (the glyph, the run's start, the usage, the dock)
|
|
1160
1196
|
// stays here; the ROW's text is the tui's status formatter.
|
|
1161
1197
|
const paintRunning = () => {
|
|
1162
1198
|
if (dock.active)
|
|
1163
|
-
dock.setStatus(runningStatus(runGlyph, runStart, runUsage.out, displayCtxRatio(session)));
|
|
1199
|
+
dock.setStatus(runningStatus(runGlyph, runStart, runUsage.out, displayCtxRatio(session), lastTokPerSec));
|
|
1164
1200
|
};
|
|
1165
1201
|
// W19: under plan the idle row makes the posture unmistakable — the W4
|
|
1166
1202
|
// parentheses idiom names the read-only constraint. The tier is the
|
|
@@ -1174,7 +1210,12 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1174
1210
|
dock.setStatus(idleStatus(getMode() === "plan" ? "plan (read-only)" : getMode(), statusModelLabel(session), displayCtxRatio(session), {
|
|
1175
1211
|
cacheHitPct: cacheHitPct(runUsage),
|
|
1176
1212
|
costUsd: spentUsd,
|
|
1177
|
-
|
|
1213
|
+
tokPerSec: lastTokPerSec,
|
|
1214
|
+
},
|
|
1215
|
+
// DF-0330-F1: the row's budget. Without it the row is composed
|
|
1216
|
+
// blind and invariant ① cuts whatever sits last — which is how
|
|
1217
|
+
// a measured rate went missing at 100 columns.
|
|
1218
|
+
rowWidth()));
|
|
1178
1219
|
};
|
|
1179
1220
|
// TUI2-R2 ⑥ — the BOOT status line. The row is the product's one
|
|
1180
1221
|
// persistent claim about itself (the tier, how to change it, the model,
|
|
@@ -1198,11 +1239,16 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1198
1239
|
// binding's, and the row does not render it anyway.
|
|
1199
1240
|
const modelSwitched = () => {
|
|
1200
1241
|
runUsage = { in: null, out: null, cache: null, known: false };
|
|
1242
|
+
lastTokPerSec = null; // TPS-1: the rate belonged to the old binding
|
|
1201
1243
|
paintIdle();
|
|
1202
1244
|
};
|
|
1203
|
-
const statusCb = (u, ctx, costUsd) => {
|
|
1245
|
+
const statusCb = (u, ctx, costUsd, tokPerSec) => {
|
|
1204
1246
|
runUsage = u;
|
|
1205
1247
|
addCost(costUsd ?? null);
|
|
1248
|
+
// TPS-1: a call that could not be measured leaves the row as it was
|
|
1249
|
+
// rather than blanking a figure the previous call earned.
|
|
1250
|
+
if (tokPerSec != null)
|
|
1251
|
+
lastTokPerSec = tokPerSec;
|
|
1206
1252
|
paintRunning();
|
|
1207
1253
|
};
|
|
1208
1254
|
// TUI2-R1 (E): the canonical cost of one settled request, added to the
|
|
@@ -1357,6 +1403,7 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1357
1403
|
// spent, reported as seconds it did.
|
|
1358
1404
|
runStart = Date.now();
|
|
1359
1405
|
runUsage = { in: null, out: null, cache: null, known: false };
|
|
1406
|
+
lastTokPerSec = null; // TPS-1: nothing has settled in THIS turn yet
|
|
1360
1407
|
const last = await consumeRun(session, recoveryRun, input, turnNo, faux, statusCb, submitTurn);
|
|
1361
1408
|
currentRun = null;
|
|
1362
1409
|
failOnFauxExhaustion(last, faux, input);
|
package/dist/index.js
CHANGED
|
@@ -834,7 +834,9 @@ async function pickSession(agent, input) {
|
|
|
834
834
|
function paintBootStatus(session) {
|
|
835
835
|
if (!dock.active)
|
|
836
836
|
return;
|
|
837
|
-
|
|
837
|
+
// DF-0330-F1: the BOOT row gets the budget too — it is the same row, and
|
|
838
|
+
// the opening screen is where a long model id is first seen.
|
|
839
|
+
dock.setStatus(idleStatus(getMode() === "plan" ? "plan (read-only)" : getMode(), statusModelLabel(session), displayCtxRatio(session), undefined, process.stdout.columns > 0 ? process.stdout.columns : 80));
|
|
838
840
|
}
|
|
839
841
|
/** PH-1a (finding PH-F12): a usage error raised from inside the TUI —
|
|
840
842
|
* main's finally still runs (dock teardown, agent close, temp cleanup)
|
package/dist/resume.js
CHANGED
|
@@ -33,8 +33,11 @@ export async function resume(session, prompt, faux, input) {
|
|
|
33
33
|
// the recovery flow prints the BARE mode (chat spells plan's posture) —
|
|
34
34
|
// the extraction keeps that difference, it was not asked to settle it.
|
|
35
35
|
const paintIdle = () => {
|
|
36
|
+
// DF-0330-F1: the recovery flow paints the same row, so it gets the
|
|
37
|
+
// same budget. It has no meter, so nothing here can be dropped that
|
|
38
|
+
// was not already at risk of being cut.
|
|
36
39
|
if (dock.active)
|
|
37
|
-
dock.setStatus(idleStatus(getMode(), agentModel, estimateCtxRatio(session)));
|
|
40
|
+
dock.setStatus(idleStatus(getMode(), agentModel, estimateCtxRatio(session), undefined, process.stdout.columns > 0 ? process.stdout.columns : 80));
|
|
38
41
|
};
|
|
39
42
|
const withRun = async (run) => {
|
|
40
43
|
currentRun = run;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "kiso-code — the coding agent on kiso, the durable runtime for AI agents: kiso chat / kiso resume / kiso sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,20 +18,20 @@
|
|
|
18
18
|
"test": "vitest run"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@vincemakes/kiso-ask-ext": "0.
|
|
22
|
-
"@vincemakes/kiso-core": "0.
|
|
23
|
-
"@vincemakes/kiso-evals": "0.
|
|
24
|
-
"@vincemakes/kiso-mcp-ext": "0.
|
|
25
|
-
"@vincemakes/kiso-provider-anthropic": "0.
|
|
26
|
-
"@vincemakes/kiso-provider-openai": "0.
|
|
27
|
-
"@vincemakes/kiso-provider-openai-responses": "0.
|
|
28
|
-
"@vincemakes/kiso-runtime": "0.
|
|
29
|
-
"@vincemakes/kiso-skills-ext": "0.
|
|
30
|
-
"@vincemakes/kiso-subagent-ext": "0.
|
|
31
|
-
"@vincemakes/kiso-task-ext": "0.
|
|
32
|
-
"@vincemakes/kiso-tools-node": "0.
|
|
33
|
-
"@vincemakes/kiso-tui": "0.
|
|
34
|
-
"@vincemakes/kiso-tui-cells": "0.
|
|
21
|
+
"@vincemakes/kiso-ask-ext": "0.34.0",
|
|
22
|
+
"@vincemakes/kiso-core": "0.34.0",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.34.0",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.34.0",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.34.0",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.34.0",
|
|
27
|
+
"@vincemakes/kiso-provider-openai-responses": "0.34.0",
|
|
28
|
+
"@vincemakes/kiso-runtime": "0.34.0",
|
|
29
|
+
"@vincemakes/kiso-skills-ext": "0.34.0",
|
|
30
|
+
"@vincemakes/kiso-subagent-ext": "0.34.0",
|
|
31
|
+
"@vincemakes/kiso-task-ext": "0.34.0",
|
|
32
|
+
"@vincemakes/kiso-tools-node": "0.34.0",
|
|
33
|
+
"@vincemakes/kiso-tui": "0.34.0",
|
|
34
|
+
"@vincemakes/kiso-tui-cells": "0.34.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^26.1.2",
|