@vikrant82/opencode-cache-keepalive 0.1.6 → 0.2.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/MIGRATION.md +57 -0
- package/README.md +75 -51
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1093 -649
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +8 -25
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/control.d.ts +10 -37
- package/dist/lib/control.d.ts.map +1 -1
- package/dist/lib/paths.d.ts +5 -12
- package/dist/lib/paths.d.ts.map +1 -1
- package/dist/lib/replay-warmer.d.ts +95 -0
- package/dist/lib/replay-warmer.d.ts.map +1 -0
- package/dist/lib/state.d.ts +15 -117
- package/dist/lib/state.d.ts.map +1 -1
- package/dist/lib/tui/commands.d.ts +1 -6
- package/dist/lib/tui/commands.d.ts.map +1 -1
- package/dist/lib/tui/footer.d.ts +5 -5
- package/dist/lib/tui/footer.d.ts.map +1 -1
- package/dist/lib/tui/format.d.ts.map +1 -1
- package/dist/lib/types.d.ts +123 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/tui.d.ts +3 -0
- package/dist/tui.d.ts.map +1 -1
- package/lib/config.ts +106 -74
- package/lib/control.ts +50 -86
- package/lib/paths.ts +12 -14
- package/lib/replay-warmer.ts +1200 -0
- package/lib/state.ts +171 -181
- package/lib/tui/commands.tsx +36 -144
- package/lib/tui/footer.tsx +54 -156
- package/lib/tui/format.ts +4 -0
- package/lib/types.ts +130 -0
- package/package.json +3 -2
- package/tui.tsx +40 -0
- package/dist/lib/keepalive.d.ts +0 -88
- package/dist/lib/keepalive.d.ts.map +0 -1
- package/dist/lib/model.d.ts +0 -8
- package/dist/lib/model.d.ts.map +0 -1
- package/dist/lib/system.d.ts +0 -11
- package/dist/lib/system.d.ts.map +0 -1
- package/lib/keepalive.ts +0 -665
- package/lib/model.ts +0 -19
- package/lib/system.ts +0 -19
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { KeepaliveConfig } from "./config";
|
|
2
|
+
import type { Logger } from "./logger";
|
|
3
|
+
import type { SessionWarmEntry, WarmApi, WarmStateSink } from "./types";
|
|
4
|
+
type Recorded = {
|
|
5
|
+
url: string;
|
|
6
|
+
method: string;
|
|
7
|
+
headers: Headers;
|
|
8
|
+
body: string;
|
|
9
|
+
model: string;
|
|
10
|
+
api: WarmApi;
|
|
11
|
+
sentAt: number;
|
|
12
|
+
intervalMs: number;
|
|
13
|
+
};
|
|
14
|
+
type Session = {
|
|
15
|
+
request: Recorded;
|
|
16
|
+
entry: SessionWarmEntry;
|
|
17
|
+
timer?: ReturnType<typeof setTimeout>;
|
|
18
|
+
controller?: AbortController;
|
|
19
|
+
runningTools: Set<string>;
|
|
20
|
+
active: boolean;
|
|
21
|
+
busy: boolean;
|
|
22
|
+
realRequests: number;
|
|
23
|
+
previousPrompt?: number;
|
|
24
|
+
replayReadTokens: number;
|
|
25
|
+
pendingResume?: {
|
|
26
|
+
replays: number;
|
|
27
|
+
promptPrev: number;
|
|
28
|
+
replayReadTokens: number;
|
|
29
|
+
};
|
|
30
|
+
retries: number;
|
|
31
|
+
child: boolean;
|
|
32
|
+
stopLoggedGap?: number;
|
|
33
|
+
touchedAt: number;
|
|
34
|
+
};
|
|
35
|
+
type Runtime = {
|
|
36
|
+
originalFetch: typeof fetch;
|
|
37
|
+
sessions: Map<string, Session>;
|
|
38
|
+
owners: Map<string, ReplayWarmer>;
|
|
39
|
+
instancesSet: Set<ReplayWarmer>;
|
|
40
|
+
childSessions: Set<string>;
|
|
41
|
+
now: () => number;
|
|
42
|
+
loggedApis: Set<WarmApi>;
|
|
43
|
+
maxStoredBytes: number;
|
|
44
|
+
storedBytes: number;
|
|
45
|
+
hosts: Set<string>;
|
|
46
|
+
pruneTimer?: ReturnType<typeof setInterval>;
|
|
47
|
+
instances: Map<ReplayWarmer, {
|
|
48
|
+
enabled: boolean;
|
|
49
|
+
controls: Map<string, boolean>;
|
|
50
|
+
effective: Map<string, boolean>;
|
|
51
|
+
directory: string;
|
|
52
|
+
hosts: Set<string>;
|
|
53
|
+
config: KeepaliveConfig;
|
|
54
|
+
sink: WarmStateSink;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
/** Replays allowlisted model requests at cache-refresh deadlines without generating model output. */
|
|
58
|
+
export declare class ReplayWarmer {
|
|
59
|
+
private readonly client;
|
|
60
|
+
private readonly config;
|
|
61
|
+
private readonly sink;
|
|
62
|
+
private readonly logger;
|
|
63
|
+
private readonly directory;
|
|
64
|
+
private readonly now;
|
|
65
|
+
private runtime?;
|
|
66
|
+
private controlTimer?;
|
|
67
|
+
private enabled;
|
|
68
|
+
constructor(client: any, config: KeepaliveConfig, sink: WarmStateSink, logger: Logger, directory: string, now?: () => number);
|
|
69
|
+
start(): void;
|
|
70
|
+
dispose(): void;
|
|
71
|
+
onEvent(event: any): void;
|
|
72
|
+
private totals;
|
|
73
|
+
/** @internal Called asynchronously by the process-wide recorder. */
|
|
74
|
+
debugRecordRejected(reason: string): void;
|
|
75
|
+
/** @internal Called asynchronously by the process-wide recorder. */
|
|
76
|
+
recordRequest(runtime: Runtime, input: string | URL | Request, init?: RequestInit, bodySource?: Promise<string>, selectedBody?: string, selectedParsed?: any): Promise<void>;
|
|
77
|
+
private recordEligible;
|
|
78
|
+
private startGap;
|
|
79
|
+
private invalidateTarget;
|
|
80
|
+
private enforceStoredBudget;
|
|
81
|
+
private get cap();
|
|
82
|
+
private schedule;
|
|
83
|
+
private replay;
|
|
84
|
+
private retryOrLapse;
|
|
85
|
+
private stopSession;
|
|
86
|
+
private updateState;
|
|
87
|
+
private publish;
|
|
88
|
+
private clearTimer;
|
|
89
|
+
private clearTimerFrom;
|
|
90
|
+
private sessionEnabled;
|
|
91
|
+
private disableSession;
|
|
92
|
+
private syncControl;
|
|
93
|
+
}
|
|
94
|
+
export {};
|
|
95
|
+
//# sourceMappingURL=replay-warmer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-warmer.d.ts","sourceRoot":"","sources":["../../lib/replay-warmer.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/state.d.ts
CHANGED
|
@@ -1,121 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
cacheRead: number;
|
|
7
|
-
cacheWrite: number;
|
|
8
|
-
output: number;
|
|
1
|
+
import type { Logger } from "./logger";
|
|
2
|
+
import type { ProcessTotals, SessionWarmEntry, WarmStateSink } from "./types";
|
|
3
|
+
export type StateStoreOptions = {
|
|
4
|
+
logger?: Logger;
|
|
5
|
+
now?: () => number;
|
|
9
6
|
};
|
|
10
7
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* the session's persisted agent/model/variant.
|
|
8
|
+
* Create an isolated v2 snapshot writer. Mutations are debounced, dispose flushes
|
|
9
|
+
* the latest snapshot before removing it, and all filesystem failures stay
|
|
10
|
+
* best-effort so state reporting cannot disrupt replay execution.
|
|
15
11
|
*/
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export type InflightPing = {
|
|
24
|
-
/** Epoch ms the ping attempt began (before the pre-flight status check). */
|
|
25
|
-
startedAt: number;
|
|
26
|
-
/** The prompt request has been issued. */
|
|
27
|
-
sent: boolean;
|
|
28
|
-
/** The ping's own user message, identified by its ping-token text part. */
|
|
29
|
-
messageID?: string;
|
|
30
|
-
/**
|
|
31
|
-
* New user messages seen during the ping whose text has not yet been observed.
|
|
32
|
-
* Each is classified by its first text part: the ping token marks our own
|
|
33
|
-
* message, anything else a real turn.
|
|
34
|
-
*/
|
|
35
|
-
pending: Map<string, unknown>;
|
|
36
|
-
/**
|
|
37
|
-
* A real user message appeared while the ping was in flight. opencode joins such
|
|
38
|
-
* a prompt to the running ping loop, so the rest of the run is real work.
|
|
39
|
-
*/
|
|
40
|
-
interrupted: boolean;
|
|
41
|
-
};
|
|
42
|
-
/** Live per-session bookkeeping held by the server plugin. */
|
|
43
|
-
export type SessionKeepalive = {
|
|
44
|
-
sessionID: string;
|
|
45
|
-
/** Whether the session's provider/model pair supports cache warming. */
|
|
46
|
-
eligible: boolean;
|
|
47
|
-
modelLabel?: string;
|
|
48
|
-
/** Epoch ms of the last real assistant response (excludes ping replies). */
|
|
49
|
-
lastResponseAt: number;
|
|
50
|
-
/** Epoch ms the current idle stretch began. */
|
|
51
|
-
idleSince: number;
|
|
52
|
-
/** Epoch ms after which warming stops and the cache is allowed to go cold. */
|
|
53
|
-
windowEndsAt: number;
|
|
54
|
-
/** Epoch ms the next ping is due. */
|
|
55
|
-
nextPingAt: number;
|
|
56
|
-
/** Number of scheduled ping requests attempted during this warm window. */
|
|
57
|
-
pingsSent: number;
|
|
58
|
-
/** A real turn is currently running. */
|
|
59
|
-
busy: boolean;
|
|
60
|
-
/** A keepalive ping is currently in flight. */
|
|
61
|
-
warming: boolean;
|
|
62
|
-
/** The in-flight ping; set exactly while `warming` is true. */
|
|
63
|
-
ping?: InflightPing;
|
|
64
|
-
/** ID and creation time of the newest user message seen, to tell new turns from re-emitted old messages. */
|
|
65
|
-
lastUserID?: string;
|
|
66
|
-
lastUserAt?: number;
|
|
67
|
-
/** Settings of the last real user turn, replayed by pings. */
|
|
68
|
-
request?: PingRequest;
|
|
69
|
-
/** Within the warm window and actively scheduling pings. */
|
|
70
|
-
active: boolean;
|
|
71
|
-
/** True while `armWindow` is resolving session metadata (async guard). */
|
|
72
|
-
arming?: boolean;
|
|
73
|
-
/** Epoch ms the last sent ping finished; ignores its late events and marks the last cache touch. */
|
|
74
|
-
lastPingAt?: number;
|
|
75
|
-
lastPing?: PingRecord;
|
|
76
|
-
};
|
|
77
|
-
/** Lean projection persisted to disk for the TUI reader. */
|
|
78
|
-
export type PersistedSession = {
|
|
79
|
-
eligible: boolean;
|
|
80
|
-
modelLabel?: string;
|
|
81
|
-
lastResponseAt: number;
|
|
82
|
-
idleSince: number;
|
|
83
|
-
windowEndsAt: number;
|
|
84
|
-
nextPingAt: number;
|
|
85
|
-
intervalMs: number;
|
|
86
|
-
pingsSent: number;
|
|
87
|
-
busy: boolean;
|
|
88
|
-
warming: boolean;
|
|
89
|
-
active: boolean;
|
|
90
|
-
lastPing?: PingRecord;
|
|
91
|
-
};
|
|
92
|
-
export type PersistedState = {
|
|
93
|
-
version: 1;
|
|
94
|
-
updatedAt: number;
|
|
95
|
-
enabled: boolean;
|
|
96
|
-
intervalMs: number;
|
|
97
|
-
windowMs: number;
|
|
98
|
-
sessions: Record<string, PersistedSession>;
|
|
99
|
-
};
|
|
100
|
-
export declare class KeepaliveStore {
|
|
101
|
-
private readonly config;
|
|
102
|
-
private readonly directory;
|
|
103
|
-
private readonly sessions;
|
|
104
|
-
private writeQueue;
|
|
105
|
-
private enabled;
|
|
106
|
-
private intervalMs;
|
|
107
|
-
constructor(config: KeepaliveConfig, directory: string);
|
|
108
|
-
setEnabled(enabled: boolean): void;
|
|
109
|
-
/** Effective ping interval (runtime override or config) reported to the TUI. */
|
|
110
|
-
setIntervalMs(intervalMs: number): void;
|
|
111
|
-
get(sessionID: string): SessionKeepalive | undefined;
|
|
112
|
-
ensure(sessionID: string): SessionKeepalive;
|
|
113
|
-
remove(sessionID: string): void;
|
|
114
|
-
all(): SessionKeepalive[];
|
|
115
|
-
/**
|
|
116
|
-
* Atomically persist a lean snapshot for the TUI. Never throws or rejects; the
|
|
117
|
-
* returned promise resolves once this snapshot and every earlier one are written.
|
|
118
|
-
*/
|
|
119
|
-
persist(): Promise<void>;
|
|
120
|
-
}
|
|
12
|
+
export declare function createStateStore(directory: string, options?: StateStoreOptions): WarmStateSink;
|
|
13
|
+
/** Return the newest self-contained entry for a session across matching v2 files. */
|
|
14
|
+
export declare function readSessionEntry(directory: string, sessionID: string): SessionWarmEntry | undefined;
|
|
15
|
+
/** Sum process-level totals from live snapshots for this directory. */
|
|
16
|
+
export declare function readProcessTotals(directory: string): ProcessTotals;
|
|
17
|
+
/** Remove only v2 snapshots whose owner PID is confirmed dead. */
|
|
18
|
+
export declare function cleanupStateFiles(directory: string, logger?: Logger): void;
|
|
121
19
|
//# sourceMappingURL=state.d.ts.map
|
package/dist/lib/state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../lib/state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../lib/state.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEtC,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAc7E,MAAM,MAAM,iBAAiB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAE,CAAA;AAEvE;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,iBAAsB,GAChC,aAAa,CAoFf;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAClB,gBAAgB,GAAG,SAAS,CAO9B;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAgBlE;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAmB1E"}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import type { TuiPluginApi } from "@opencode-ai/plugin/tui";
|
|
3
|
-
/**
|
|
4
|
-
* Register the keepalive commands. The control file is scoped per directory, so
|
|
5
|
-
* toggling keepalive or changing its interval here only affects this project's
|
|
6
|
-
* server plugin — not other open opencode sessions. The server polls the file
|
|
7
|
-
* every second, so changes apply without a restart.
|
|
8
|
-
*/
|
|
3
|
+
/** Register runtime enable/disable commands for the current session only. */
|
|
9
4
|
export declare function registerKeepaliveCommands(api: TuiPluginApi): void;
|
|
10
5
|
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../lib/tui/commands.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../lib/tui/commands.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAG3D,6EAA6E;AAC7E,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAqEjE"}
|
package/dist/lib/tui/footer.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
import type { SessionWarmEntry } from "../types";
|
|
2
3
|
type Theme = Record<string, any>;
|
|
3
|
-
/**
|
|
4
|
-
* Persistent readout mounted in the `sidebar_footer` slot. Shows time since the
|
|
5
|
-
* last real agent response plus keepalive pings sent / left. Data comes from the
|
|
6
|
-
* server plugin's state file; the idle timer ticks locally every second.
|
|
7
|
-
*/
|
|
4
|
+
/** Display the persisted replay-warming state for the current session only. */
|
|
8
5
|
export declare function KeepaliveFooter(props: {
|
|
9
6
|
theme: Theme;
|
|
10
7
|
directory: string;
|
|
11
8
|
sessionID?: string;
|
|
12
9
|
}): any;
|
|
10
|
+
/** Pure formatter for the two-line footer's optional telemetry. */
|
|
11
|
+
export declare function formatDetails(entry: SessionWarmEntry, now?: number): string | undefined;
|
|
12
|
+
export declare function formatStatusLine(entry: SessionWarmEntry, remainingMs: number): string;
|
|
13
13
|
export {};
|
|
14
14
|
//# sourceMappingURL=footer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../lib/tui/footer.tsx"],"names":[],"mappings":"AAAA,sCAAsC;
|
|
1
|
+
{"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../lib/tui/footer.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AAItC,OAAO,KAAK,EAAE,gBAAgB,EAAa,MAAM,UAAU,CAAA;AAI3D,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAEhC,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,OAkD7F;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,SAAa,GAAG,MAAM,GAAG,SAAS,CAE3F;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAYrF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../lib/tui/format.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKvC;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../lib/tui/format.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKvC;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAStC;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAa/D;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAWjD"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared contracts between the server-side replay engine and the state/TUI layer.
|
|
3
|
+
*
|
|
4
|
+
* The engine produces one self-contained {@link SessionWarmEntry} per tracked root
|
|
5
|
+
* session and hands it to a {@link WarmStateSink}; the TUI reads persisted entries
|
|
6
|
+
* back per session. Entries never contain request URLs with queries, headers,
|
|
7
|
+
* bodies, credentials, or conversation text.
|
|
8
|
+
*/
|
|
9
|
+
/** Wire API family of a recorded request, derived from the request pathname. */
|
|
10
|
+
export type WarmApi = "messages" | "responses" | "chat";
|
|
11
|
+
/**
|
|
12
|
+
* Display/lifecycle state of a session's cache warming.
|
|
13
|
+
* - `active`: a real model request/step is in flight; no replay is sent.
|
|
14
|
+
* - `busy`: the session is blocked on a running tool; replays are scheduled.
|
|
15
|
+
* - `idle`: the session is idle between turns; replays are scheduled.
|
|
16
|
+
* - `stopped`: warming ended for the current gap; see {@link StopReason}.
|
|
17
|
+
* - `off`: warming is disabled by config or runtime control.
|
|
18
|
+
*/
|
|
19
|
+
export type WarmState = "active" | "busy" | "idle" | "stopped" | "off";
|
|
20
|
+
/**
|
|
21
|
+
* Why warming stopped for the current gap.
|
|
22
|
+
* - `cap`: the per-gap replay cap was reached.
|
|
23
|
+
* - `lapsed`: the cache is believed expired (failed retry, or a replay reported a cache write instead of a read).
|
|
24
|
+
* - `rejected-4xx`: the provider rejected the replay with 400/401/403.
|
|
25
|
+
* - `disabled`: runtime control or config turned warming off.
|
|
26
|
+
*/
|
|
27
|
+
export type StopReason = "cap" | "lapsed" | "rejected-4xx" | "disabled";
|
|
28
|
+
/** Outcome of the most recent replay attempt. */
|
|
29
|
+
export interface ReplayResult {
|
|
30
|
+
/** Replay send time, epoch ms. */
|
|
31
|
+
at: number;
|
|
32
|
+
/** HTTP status; 0 for network error or timeout. */
|
|
33
|
+
status: number;
|
|
34
|
+
/** Milliseconds from issuing the replay fetch to the API-specific abort point. */
|
|
35
|
+
latencyMs: number;
|
|
36
|
+
/** Cached prompt tokens reported by the provider, when parseable before abort (messages API). */
|
|
37
|
+
cacheRead?: number;
|
|
38
|
+
/** Cache-write prompt tokens reported by the provider, when parseable before abort (messages API). */
|
|
39
|
+
cacheWrite?: number;
|
|
40
|
+
}
|
|
41
|
+
/** Result of the first real model call after a gap that had at least one successful replay. */
|
|
42
|
+
export interface ResumeResult {
|
|
43
|
+
/** step-finish time, epoch ms. */
|
|
44
|
+
at: number;
|
|
45
|
+
/** cache.read tokens of that call. */
|
|
46
|
+
read: number;
|
|
47
|
+
/** Prompt tokens (input + cache.read + cache.write) of the last call before the gap. */
|
|
48
|
+
promptPrev: number;
|
|
49
|
+
/** True when read >= 0.9 * promptPrev. */
|
|
50
|
+
hit: boolean;
|
|
51
|
+
/** Successful replays spent in the gap. */
|
|
52
|
+
replays: number;
|
|
53
|
+
/**
|
|
54
|
+
* Cache-write tokens avoided for the gap: `promptPrev` on a hit, 0 on a miss.
|
|
55
|
+
* Gross figure shown to users as "saved"; replay cost is reported separately.
|
|
56
|
+
*/
|
|
57
|
+
avoidedTokens: number;
|
|
58
|
+
/**
|
|
59
|
+
* Cached-read tokens spent by the gap's successful replays (sum of each replay's
|
|
60
|
+
* reported cacheRead, falling back to promptPrev when not parsed). Logged only.
|
|
61
|
+
*/
|
|
62
|
+
replayReadTokens: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Complete, self-contained display state for one root session. Every field the TUI
|
|
66
|
+
* needs is here so readers never depend on file-level or process-level fields.
|
|
67
|
+
*/
|
|
68
|
+
export interface SessionWarmEntry {
|
|
69
|
+
sessionID: string;
|
|
70
|
+
/** Last time this entry changed, epoch ms; readers pick the freshest entry per session. */
|
|
71
|
+
updatedAt: number;
|
|
72
|
+
/** Effective enablement (config AND runtime control). */
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
/** Model id from the recorded request body. */
|
|
75
|
+
model: string;
|
|
76
|
+
api: WarmApi;
|
|
77
|
+
state: WarmState;
|
|
78
|
+
stopReason?: StopReason;
|
|
79
|
+
/** HTTP status that caused `rejected-4xx`. */
|
|
80
|
+
stopStatus?: number;
|
|
81
|
+
/** Monotonic per-session gap counter; a gap starts at each real request send. */
|
|
82
|
+
gapId: number;
|
|
83
|
+
/** Successful replays in the current gap. */
|
|
84
|
+
gapReplays: number;
|
|
85
|
+
/** Per-gap replay cap in effect. */
|
|
86
|
+
cap: number;
|
|
87
|
+
/** Next scheduled replay time, epoch ms; null when none is scheduled. */
|
|
88
|
+
nextReplayAt: number | null;
|
|
89
|
+
/** Successful replays across the session's lifetime in this process. */
|
|
90
|
+
sessionReplays: number;
|
|
91
|
+
/** Sum of ResumeResult.avoidedTokens across the session's gaps in this process. */
|
|
92
|
+
avoidedTokens: number;
|
|
93
|
+
/** Resumes (first call after a gap with ≥1 successful replay) that hit, in this process. */
|
|
94
|
+
resumeHits: number;
|
|
95
|
+
/** All resumes (hits + misses) in this process. */
|
|
96
|
+
resumeCount: number;
|
|
97
|
+
lastReplay?: ReplayResult;
|
|
98
|
+
resume?: ResumeResult;
|
|
99
|
+
}
|
|
100
|
+
/** Process-wide aggregates, informational only (never used to gate display). */
|
|
101
|
+
export interface ProcessTotals {
|
|
102
|
+
replays: number;
|
|
103
|
+
avoidedTokens: number;
|
|
104
|
+
replayReadTokens: number;
|
|
105
|
+
resumeHits: number;
|
|
106
|
+
resumeMisses: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Destination for engine state. Implementations persist sanitized entries for the
|
|
110
|
+
* TUI. Calls are synchronous and must never throw; persistence may be debounced.
|
|
111
|
+
* Single-threaded use from the plugin's event loop is assumed.
|
|
112
|
+
*/
|
|
113
|
+
export interface WarmStateSink {
|
|
114
|
+
/** Replace the entry for `entry.sessionID`. */
|
|
115
|
+
upsert(entry: SessionWarmEntry): void;
|
|
116
|
+
/** Forget a session (e.g. deleted). */
|
|
117
|
+
remove(sessionID: string): void;
|
|
118
|
+
/** Replace process totals. */
|
|
119
|
+
setTotals(totals: ProcessTotals): void;
|
|
120
|
+
/** Flush pending writes and remove this instance's persisted file. Never rejects. */
|
|
121
|
+
dispose(): Promise<void>;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,gFAAgF;AAChF,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAA;AAEvD;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,CAAA;AAEtE;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,QAAQ,GAAG,cAAc,GAAG,UAAU,CAAA;AAEvE,iDAAiD;AACjD,MAAM,WAAW,YAAY;IACzB,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAA;IACjB,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,+FAA+F;AAC/F,MAAM,WAAW,YAAY;IACzB,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,wFAAwF;IACxF,UAAU,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,GAAG,EAAE,OAAO,CAAA;IACZ,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAA;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAA;IACjB,yDAAyD;IACzD,OAAO,EAAE,OAAO,CAAA;IAChB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,OAAO,CAAA;IACZ,KAAK,EAAE,SAAS,CAAA;IAChB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAA;IAClB,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAA;IACX,yEAAyE;IACzE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,wEAAwE;IACxE,cAAc,EAAE,MAAM,CAAA;IACtB,mFAAmF;IACnF,aAAa,EAAE,MAAM,CAAA;IACrB,4FAA4F;IAC5F,UAAU,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,YAAY,CAAA;IACzB,MAAM,CAAC,EAAE,YAAY,CAAA;CACxB;AAED,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B,+CAA+C;IAC/C,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACrC,uCAAuC;IACvC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,8BAA8B;IAC9B,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;IACtC,qFAAqF;IACrF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B"}
|
package/dist/tui.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
import type { SessionWarmEntry } from "./lib/types";
|
|
3
|
+
/** Route-level owner for deduplicating rejected replay notifications. */
|
|
4
|
+
export declare function notifyRejectedReplayOnce(notified: Set<string>, sessionID: string, entry: SessionWarmEntry, toast: (message: string) => void): void;
|
|
2
5
|
declare const _default: {
|
|
3
6
|
id: string;
|
|
4
7
|
tui: import("@opencode-ai/plugin/tui").TuiPlugin;
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../tui.tsx"],"names":[],"mappings":"AAAA,sCAAsC;;;;;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../tui.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AAMtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEnD,yEAAyE;AACzE,wBAAgB,wBAAwB,CACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,EACrB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACjC,IAAI,CAWN;;;;;AAuCD,wBAAgF"}
|