@qvac/harness 0.2.5 → 0.2.6
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/.claude/skills/asana/SKILL.md +86 -0
- package/.claude/skills/gh-stack/SKILL.md +181 -0
- package/.claude/skills/gh-stack/references/commands.md +177 -0
- package/.claude/skills/gh-stack/references/stack-design.md +97 -0
- package/.claude/skills/gh-stack/references/troubleshooting.md +159 -0
- package/.claude/skills/js-house-style/SKILL.md +650 -0
- package/.claude/skills/kvcache/SKILL.md +171 -0
- package/.claude/skills/pr-create/SKILL.md +137 -0
- package/.claude/skills/pr-review/SKILL.md +148 -0
- package/CLAUDE.md +36 -0
- package/dist/harness.bundle +5 -58
- package/dist/prebuilds-manifest.json +0 -8
- package/dist-lib/index.d.ts +4 -1
- package/dist-lib/index.js +23 -7
- package/dist-lib/lib/models/model-pool.d.ts +1 -1
- package/dist-lib/lib/models/model-pool.js +3 -2
- package/dist-lib/lib/spawn.d.ts +1 -0
- package/dist-lib/schema/generate.d.ts +6 -2
- package/dist-lib/schema/generate.js +10 -5
- package/docs/kvcache-reference.md +655 -0
- package/package.json +1 -1
- package/worker/harness-sidecar.mjs +3 -2
|
@@ -272,14 +272,6 @@
|
|
|
272
272
|
"win32-arm64",
|
|
273
273
|
"win32-x64"
|
|
274
274
|
],
|
|
275
|
-
"bare-tty/node_modules/bare-signals": [
|
|
276
|
-
"darwin-arm64",
|
|
277
|
-
"darwin-x64",
|
|
278
|
-
"linux-arm64",
|
|
279
|
-
"linux-x64",
|
|
280
|
-
"win32-arm64",
|
|
281
|
-
"win32-x64"
|
|
282
|
-
],
|
|
283
275
|
"bare-tty": [
|
|
284
276
|
"darwin-arm64",
|
|
285
277
|
"darwin-x64",
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -82,6 +82,7 @@ export interface HarnessOptions {
|
|
|
82
82
|
transcriptionDevice?: 'cpu' | 'gpu';
|
|
83
83
|
credentialStore?: CredentialStoreFn;
|
|
84
84
|
platform?: string;
|
|
85
|
+
completionModelCap?: number;
|
|
85
86
|
}
|
|
86
87
|
export interface CompletionContext {
|
|
87
88
|
model: string;
|
|
@@ -133,6 +134,7 @@ export declare class Harness extends ReadyResource {
|
|
|
133
134
|
private readonly _kvCacheV?;
|
|
134
135
|
private readonly _transcriptionDevice?;
|
|
135
136
|
private readonly _gpuStats?;
|
|
137
|
+
private readonly _completionModelCap;
|
|
136
138
|
private _allSkills;
|
|
137
139
|
private _credentialStore?;
|
|
138
140
|
private _credentials;
|
|
@@ -145,7 +147,7 @@ export declare class Harness extends ReadyResource {
|
|
|
145
147
|
private _capability;
|
|
146
148
|
private _capabilityInflight;
|
|
147
149
|
private readonly _modelFaults;
|
|
148
|
-
constructor({ tools, sdkLoader, skillsDir, projectionModel, imageModel, imageClamps, musicModel, musicClamps, llmDevice, llmGpuLayers, contextSize, kvCacheK, kvCacheV, embedDevice, embedGpuLayers, embedBatchSize, transcriptionDevice, credentialStore, platform, gpuStats }?: HarnessOptions);
|
|
150
|
+
constructor({ tools, sdkLoader, skillsDir, projectionModel, imageModel, imageClamps, musicModel, musicClamps, llmDevice, llmGpuLayers, contextSize, kvCacheK, kvCacheV, embedDevice, embedGpuLayers, embedBatchSize, transcriptionDevice, completionModelCap, credentialStore, platform, gpuStats }?: HarnessOptions);
|
|
149
151
|
_open(): Promise<void>;
|
|
150
152
|
get suspended(): boolean;
|
|
151
153
|
get skillNames(): string[];
|
|
@@ -238,6 +240,7 @@ export declare class Harness extends ReadyResource {
|
|
|
238
240
|
signal?: BareAbortSignal;
|
|
239
241
|
}): Promise<void>;
|
|
240
242
|
completion({ model, agent, messages, cacheKey, thinkingDefault, toolConfigs, generationParams, responseFormat, grantedDirs, grantedDrives, driveOp, grantedWriteDirs, approve, attach, fetchAttachment, ragSearch, progress, askUser, signal }: CompletionContext): AsyncGenerator<CompletionEvent>;
|
|
243
|
+
private _makeRoomForCompletion;
|
|
241
244
|
private _evictWedgedModel;
|
|
242
245
|
private _evictAfterLeases;
|
|
243
246
|
}
|
package/dist-lib/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import { AbortedError, raceAbort } from "./lib/helpers/race-abort.js";
|
|
|
17
17
|
import { audioGenDownloadMetadata, customProjectionMap, defaultProjectionMap, defaultTtsFor, defaultVoiceModel, diffusionDownloadMetadata, infraModelsFor, modelNameToCapabilityProfile, musicModelSet, setCustomModels } from "./lib/models/model-catalog.js";
|
|
18
18
|
import { createModelStatusCache, invalidateModelStatusCache, listModels } from "./lib/models/model-list.js";
|
|
19
19
|
import { deleteModelFiles, summarizeDelete } from "./lib/models/model-delete.js";
|
|
20
|
-
import { createEmbedPool, createLoadTracker, createModelPool, createVoicePool,
|
|
20
|
+
import { createEmbedPool, createLoadTracker, createModelPool, createVoicePool, awaitModelCapacity, evictIdle, evictModelWithin, isResident, leaseCount, loadedModels, modelKey, releaseModel, resolveLoadOptions, progressState } from "./lib/models/model-pool.js";
|
|
21
21
|
import { resolveMainGpu } from "./lib/models/gpu-selection.js";
|
|
22
22
|
import { openclCacheDir } from "./lib/models/opencl-cache.js";
|
|
23
23
|
import { assertEmbedDevice, createEmbedConfig } from "./lib/models/embed-config.js";
|
|
@@ -68,6 +68,9 @@ const TRANSCRIPTION_MODEL_LABEL = 'transcription model';
|
|
|
68
68
|
const DIFFUSION_EVICT_WAIT_MS = 15_000;
|
|
69
69
|
const MUSIC_EVICT_WAIT_MS = 15_000;
|
|
70
70
|
const WEDGED_EVICT_WAIT_MS = 10_000;
|
|
71
|
+
const MODEL_ROOM_WAIT_MS = 300_000;
|
|
72
|
+
const WARM_ROOM_WAIT_MS = 2_000;
|
|
73
|
+
const DEFAULT_COMPLETION_MODEL_CAP = 1;
|
|
71
74
|
const WEDGED_EVICT_LEASED_MS = 120_000;
|
|
72
75
|
const TTS_MODEL_CONFIG = {
|
|
73
76
|
ttsEngine: 'supertonic',
|
|
@@ -104,6 +107,7 @@ export class Harness extends ReadyResource {
|
|
|
104
107
|
_kvCacheV;
|
|
105
108
|
_transcriptionDevice;
|
|
106
109
|
_gpuStats;
|
|
110
|
+
_completionModelCap;
|
|
107
111
|
_allSkills;
|
|
108
112
|
_credentialStore;
|
|
109
113
|
_credentials = new Map();
|
|
@@ -116,7 +120,7 @@ export class Harness extends ReadyResource {
|
|
|
116
120
|
_capability = null;
|
|
117
121
|
_capabilityInflight = null;
|
|
118
122
|
_modelFaults = new Map();
|
|
119
|
-
constructor({ tools = [], sdkLoader, skillsDir, projectionModel, imageModel, imageClamps, musicModel, musicClamps, llmDevice, llmGpuLayers, contextSize, kvCacheK, kvCacheV, embedDevice, embedGpuLayers, embedBatchSize, transcriptionDevice, credentialStore, platform, gpuStats } = {}) {
|
|
123
|
+
constructor({ tools = [], sdkLoader, skillsDir, projectionModel, imageModel, imageClamps, musicModel, musicClamps, llmDevice, llmGpuLayers, contextSize, kvCacheK, kvCacheV, embedDevice, embedGpuLayers, embedBatchSize, transcriptionDevice, completionModelCap, credentialStore, platform, gpuStats } = {}) {
|
|
120
124
|
super();
|
|
121
125
|
this._sdk = sdkLoader ?? createSdkLoader();
|
|
122
126
|
this._llmDevice = llmDevice;
|
|
@@ -126,6 +130,7 @@ export class Harness extends ReadyResource {
|
|
|
126
130
|
this._kvCacheK = kvCacheK;
|
|
127
131
|
this._kvCacheV = kvCacheV;
|
|
128
132
|
this._transcriptionDevice = transcriptionDevice;
|
|
133
|
+
this._completionModelCap = completionModelCap ?? DEFAULT_COMPLETION_MODEL_CAP;
|
|
129
134
|
const embedConfig = createEmbedConfig({
|
|
130
135
|
device: embedDevice,
|
|
131
136
|
gpuLayers: embedGpuLayers,
|
|
@@ -168,7 +173,7 @@ export class Harness extends ReadyResource {
|
|
|
168
173
|
onBeforeLoad: async (signal) => {
|
|
169
174
|
if (this._models.destroyed)
|
|
170
175
|
return;
|
|
171
|
-
const evicted = await
|
|
176
|
+
const evicted = await awaitModelCapacity(this._models, 1, DIFFUSION_EVICT_WAIT_MS, undefined, signal);
|
|
172
177
|
if (signal?.aborted)
|
|
173
178
|
throw new AbortedError();
|
|
174
179
|
if (!evicted) {
|
|
@@ -187,7 +192,7 @@ export class Harness extends ReadyResource {
|
|
|
187
192
|
onBeforeLoad: async (signal) => {
|
|
188
193
|
if (this._models.destroyed)
|
|
189
194
|
return;
|
|
190
|
-
const evicted = await
|
|
195
|
+
const evicted = await awaitModelCapacity(this._models, 1, MUSIC_EVICT_WAIT_MS, undefined, signal);
|
|
191
196
|
if (signal?.aborted)
|
|
192
197
|
throw new AbortedError();
|
|
193
198
|
if (!evicted) {
|
|
@@ -927,7 +932,8 @@ export class Harness extends ReadyResource {
|
|
|
927
932
|
const pool = this._models;
|
|
928
933
|
hlog('warm model', { model, resident: isResident(pool, key) });
|
|
929
934
|
if (!isResident(pool, key)) {
|
|
930
|
-
await
|
|
935
|
+
if (!(await this._makeRoomForCompletion(signal, WARM_ROOM_WAIT_MS)))
|
|
936
|
+
return;
|
|
931
937
|
await this._imageRuntime?.unloadIdle().catch(noop);
|
|
932
938
|
}
|
|
933
939
|
try {
|
|
@@ -953,13 +959,13 @@ export class Harness extends ReadyResource {
|
|
|
953
959
|
const resident = isResident(pool, key);
|
|
954
960
|
hlog('completion start', { model, resident, projection: Boolean(projectionModel) });
|
|
955
961
|
if (!resident) {
|
|
956
|
-
await
|
|
962
|
+
await this._makeRoomForCompletion(signal);
|
|
957
963
|
await this._imageRuntime?.unloadIdle().catch(noop);
|
|
958
964
|
await this._musicRuntime?.unloadIdle().catch(noop);
|
|
959
965
|
}
|
|
960
966
|
const acquireRound = async () => {
|
|
961
967
|
if (!isResident(pool, key)) {
|
|
962
|
-
await
|
|
968
|
+
await this._makeRoomForCompletion(signal);
|
|
963
969
|
await this._imageRuntime?.unloadIdle().catch(noop);
|
|
964
970
|
await this._musicRuntime?.unloadIdle().catch(noop);
|
|
965
971
|
}
|
|
@@ -1052,6 +1058,16 @@ export class Harness extends ReadyResource {
|
|
|
1052
1058
|
void this._musicRuntime?.unloadIdle().catch(noop);
|
|
1053
1059
|
}
|
|
1054
1060
|
}
|
|
1061
|
+
async _makeRoomForCompletion(signal, deadlineMs = MODEL_ROOM_WAIT_MS) {
|
|
1062
|
+
const roomed = await awaitModelCapacity(this._models, this._completionModelCap, deadlineMs, 250, signal);
|
|
1063
|
+
if (!roomed) {
|
|
1064
|
+
hlog('model room wait gave up', {
|
|
1065
|
+
cap: this._completionModelCap,
|
|
1066
|
+
loaded: loadedModels(this._models).length
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
return roomed;
|
|
1070
|
+
}
|
|
1055
1071
|
async _evictWedgedModel(model, key) {
|
|
1056
1072
|
const faults = (this._modelFaults.get(model) ?? 0) + 1;
|
|
1057
1073
|
this._modelFaults.set(model, faults);
|
|
@@ -72,7 +72,7 @@ export declare function loadedModels(pool: PoolLike): LoadedModel[];
|
|
|
72
72
|
export declare function isResident(pool: PoolLike, key: string): boolean;
|
|
73
73
|
export declare function leaseCount(pool: PoolLike, key: string): number;
|
|
74
74
|
export declare function evictIdle(pool: PoolLike): Promise<void>;
|
|
75
|
-
export declare function
|
|
75
|
+
export declare function awaitModelCapacity(pool: PoolLike, cap: number, deadlineMs: number, tickMs?: number, signal?: {
|
|
76
76
|
aborted?: boolean;
|
|
77
77
|
}): Promise<boolean>;
|
|
78
78
|
export declare function evictModelWithin(pool: PoolLike, key: string, deadlineMs: number, tickMs?: number): Promise<boolean>;
|
|
@@ -103,7 +103,8 @@ export async function evictIdle(pool) {
|
|
|
103
103
|
await pool.gc();
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
export async function
|
|
106
|
+
export async function awaitModelCapacity(pool, cap, deadlineMs, tickMs = 250, signal) {
|
|
107
|
+
const roomed = () => loadedModels(pool).length < cap;
|
|
107
108
|
let done = false;
|
|
108
109
|
let timer = null;
|
|
109
110
|
const expired = new Promise((resolve) => {
|
|
@@ -114,7 +115,7 @@ export async function evictAllWithin(pool, deadlineMs, tickMs = 250, signal) {
|
|
|
114
115
|
});
|
|
115
116
|
const evicting = (async () => {
|
|
116
117
|
await evictIdle(pool);
|
|
117
|
-
while (
|
|
118
|
+
while (!roomed()) {
|
|
118
119
|
if (done || signal?.aborted)
|
|
119
120
|
return false;
|
|
120
121
|
await new Promise((resolve) => setTimeout(resolve, tickMs));
|
package/dist-lib/lib/spawn.d.ts
CHANGED
|
@@ -13,8 +13,12 @@ interface HRPCHandler {
|
|
|
13
13
|
interface HRPCBuilderLike {
|
|
14
14
|
handlers: ReadonlyArray<HRPCHandler>;
|
|
15
15
|
}
|
|
16
|
+
interface CallSiteOptions {
|
|
17
|
+
readonly optionalRequests?: ReadonlySet<string>;
|
|
18
|
+
readonly exportName?: string;
|
|
19
|
+
}
|
|
16
20
|
export declare function writeBind(builder: HRPCBuilderLike, outFile: string): void;
|
|
17
|
-
export declare function writeClient(builder: HRPCBuilderLike, outFile: string,
|
|
18
|
-
export declare function writeCapabilities(builder: HRPCBuilderLike, outFile: string): void;
|
|
21
|
+
export declare function writeClient(builder: HRPCBuilderLike, outFile: string, options?: CallSiteOptions | string): void;
|
|
22
|
+
export declare function writeCapabilities(builder: HRPCBuilderLike, outFile: string, options?: CallSiteOptions): void;
|
|
19
23
|
export declare function writeConfigTypes(outFile: string): void;
|
|
20
24
|
export {};
|
|
@@ -13,6 +13,7 @@ function camel(name, prefix = '') {
|
|
|
13
13
|
return prefix + cased.join('');
|
|
14
14
|
}
|
|
15
15
|
const HEADER = '// This file is autogenerated by schema/build.js\n// Do not edit manually.\n\n';
|
|
16
|
+
const DEFAULT_OPTIONAL_REQUESTS = new Set(['@assistant/empty']);
|
|
16
17
|
export function writeBind(builder, outFile) {
|
|
17
18
|
let s = `${HEADER}import { pipeline, Readable } from "streamx";\n\nfunction noop() {}\n\nexport function bindApi(rpc, api) {\n`;
|
|
18
19
|
for (const handler of builder.handlers) {
|
|
@@ -56,24 +57,28 @@ export function writeBind(builder, outFile) {
|
|
|
56
57
|
s += '}\n';
|
|
57
58
|
fs.writeFileSync(outFile, s);
|
|
58
59
|
}
|
|
59
|
-
export function writeClient(builder, outFile,
|
|
60
|
+
export function writeClient(builder, outFile, options = {}) {
|
|
61
|
+
const callSite = typeof options === 'string' ? { exportName: options } : options;
|
|
62
|
+
const { optionalRequests = DEFAULT_OPTIONAL_REQUESTS, exportName = 'engineClient' } = callSite;
|
|
60
63
|
let s = `${HEADER}function noop() {}\n\nfunction armed(stream) {\n stream.on("error", noop);\n return stream;\n}\n\nexport function ${exportName}(rpc) {\n return {\n`;
|
|
61
64
|
for (const handler of builder.handlers) {
|
|
62
65
|
const method = camel(handler.name);
|
|
66
|
+
const input = optionalRequests.has(handler.request?.name ?? '') ? 'input ?? {}' : 'input';
|
|
63
67
|
if (handler.request?.stream && handler.response?.stream) {
|
|
64
68
|
s += ` ${method}: () => armed(rpc.${method}()),\n`;
|
|
65
69
|
}
|
|
66
70
|
else if (handler.response?.stream) {
|
|
67
|
-
s += ` ${method}: (input) => armed(rpc.${method}(input)),\n`;
|
|
71
|
+
s += ` ${method}: (input) => armed(rpc.${method}(${input})),\n`;
|
|
68
72
|
}
|
|
69
73
|
else {
|
|
70
|
-
s += ` ${method}: (input) => rpc.${method}(input),\n`;
|
|
74
|
+
s += ` ${method}: (input) => rpc.${method}(${input}),\n`;
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
s += ' };\n}\n';
|
|
74
78
|
fs.writeFileSync(outFile, s);
|
|
75
79
|
}
|
|
76
|
-
export function writeCapabilities(builder, outFile) {
|
|
80
|
+
export function writeCapabilities(builder, outFile, options = {}) {
|
|
81
|
+
const { optionalRequests = DEFAULT_OPTIONAL_REQUESTS } = options;
|
|
77
82
|
let s = HEADER;
|
|
78
83
|
s += "import type * as T from './hyperschema/types.d.ts'\n\n";
|
|
79
84
|
s +=
|
|
@@ -112,7 +117,7 @@ export function writeCapabilities(builder, outFile) {
|
|
|
112
117
|
const method = camel(handler.name);
|
|
113
118
|
const req = `T.${tsName(handler.request.name)}`;
|
|
114
119
|
const res = `T.${tsName(handler.response.name)}`;
|
|
115
|
-
const input = handler.request.name
|
|
120
|
+
const input = optionalRequests.has(handler.request.name) ? `input?: ${req}` : `input: ${req}`;
|
|
116
121
|
if (handler.request?.stream && handler.response?.stream) {
|
|
117
122
|
client += ` ${method}(): UploadStream<${req}, ${res}>\n`;
|
|
118
123
|
server += ` ${method}(stream: AsyncIterable<${req}> | HandlerFrames<${req}>): AsyncIterable<${res}>\n`;
|