@qvac/harness 0.2.8 → 0.2.9
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/harness.bundle +65 -12
- package/dist/prebuilds-manifest.json +8 -0
- package/dist-lib/index.d.ts +2 -1
- package/dist-lib/index.js +2 -1
- package/dist-lib/lib/capabilities/completion.d.ts +35 -2
- package/dist-lib/lib/capabilities/completion.js +84 -18
- package/dist-lib/lib/connect.js +1 -0
- package/dist-lib/lib/contract-types.d.ts +1 -0
- package/dist-lib/lib/serve.js +1 -0
- package/dist-lib/lib/wire.js +28 -0
- package/dist-lib/schema/harness.js +5 -2
- package/dist-lib/spec/hrpc/messages.js +22 -7
- package/dist-lib/spec/hyperschema/index.js +22 -7
- package/dist-lib/spec/hyperschema/schema.json +14 -1
- package/dist-lib/spec/hyperschema/types.d.ts +3 -2
- package/package.json +6 -6
- package/.claude/skills/asana/SKILL.md +0 -86
- package/.claude/skills/gh-stack/SKILL.md +0 -181
- package/.claude/skills/gh-stack/references/commands.md +0 -177
- package/.claude/skills/gh-stack/references/stack-design.md +0 -97
- package/.claude/skills/gh-stack/references/troubleshooting.md +0 -159
- package/.claude/skills/js-house-style/SKILL.md +0 -671
- package/.claude/skills/kvcache/SKILL.md +0 -171
- package/.claude/skills/pr-create/SKILL.md +0 -180
- package/.claude/skills/pr-review/SKILL.md +0 -414
- package/CLAUDE.md +0 -39
- package/docs/decisions/2026-05-29-kvcache-tool-turns.md +0 -75
- package/docs/decisions/2026-06-02-kvcache-tool-turns-reenabled.md +0 -127
- package/docs/decisions/2026-06-23-android-cpu-llm-defaults.md +0 -126
- package/docs/decisions/2026-07-29-assistant-owned-storage-layout.md +0 -88
- package/docs/decisions/2026-08-04-sidecar-orphan-reaping.md +0 -79
- package/docs/decisions/2026-08-11-pyodide-worker-thread.md +0 -68
- package/docs/decisions/2026-08-17-harness-hook-pipeline.md +0 -84
- package/docs/decisions/2026-08-17-harness-outbound-egress-guard.md +0 -176
- package/docs/decisions/2026-08-20-chat-prompt-prefix-is-stable.md +0 -95
- package/docs/decisions/2026-08-20-kvcache-static-placement.md +0 -109
- package/docs/decisions/2026-08-21-vendored-python-wheels.md +0 -85
- package/docs/decisions/2026-08-26-exec-is-not-gated-by-skills.md +0 -64
- package/docs/decisions/2026-08-27-writable-skills-overlay.md +0 -56
- package/docs/decisions/2026-09-01-skill-operation-manifests.md +0 -53
- package/docs/decisions/2026-09-01-usage-breakdown-is-measured.md +0 -78
- package/docs/decisions/2026-09-03-usage-breakdown-reported-by-the-harness.md +0 -136
- package/docs/decisions/2026-09-10-skill-wording-is-measured-offline.md +0 -63
- package/docs/decisions/2026-09-16-a-lookup-reports-the-place-it-resolved.md +0 -70
- package/docs/decisions/INDEX.md +0 -40
- package/docs/decisions/TEMPLATE.md +0 -32
- package/docs/kvcache-reference.md +0 -655
|
@@ -272,6 +272,14 @@
|
|
|
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
|
+
],
|
|
275
283
|
"bare-tty": [
|
|
276
284
|
"darwin-arm64",
|
|
277
285
|
"darwin-x64",
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -93,6 +93,7 @@ export interface CompletionContext {
|
|
|
93
93
|
toolConfigs?: Record<string, Record<string, unknown>>;
|
|
94
94
|
generationParams?: LlmGenerationParams;
|
|
95
95
|
responseFormat?: ResponseFormat;
|
|
96
|
+
captureInferenceCalls?: boolean;
|
|
96
97
|
grantedDirs?: string[];
|
|
97
98
|
grantedDrives?: GrantedDrive[];
|
|
98
99
|
driveOp?: DriveOpFn;
|
|
@@ -239,7 +240,7 @@ export declare class Harness extends ReadyResource {
|
|
|
239
240
|
agent?: Agent;
|
|
240
241
|
signal?: BareAbortSignal;
|
|
241
242
|
}): Promise<void>;
|
|
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
|
+
completion({ model, agent, messages, cacheKey, thinkingDefault, toolConfigs, generationParams, responseFormat, captureInferenceCalls, grantedDirs, grantedDrives, driveOp, grantedWriteDirs, approve, attach, fetchAttachment, ragSearch, progress, askUser, signal }: CompletionContext): AsyncGenerator<CompletionEvent>;
|
|
243
244
|
private _makeRoomForCompletion;
|
|
244
245
|
private _evictWedgedModel;
|
|
245
246
|
private _evictAfterLeases;
|
package/dist-lib/index.js
CHANGED
|
@@ -943,7 +943,7 @@ export class Harness extends ReadyResource {
|
|
|
943
943
|
releaseModel(pool, key);
|
|
944
944
|
}
|
|
945
945
|
}
|
|
946
|
-
async *completion({ model, agent, messages, cacheKey, thinkingDefault, toolConfigs, generationParams, responseFormat, grantedDirs, grantedDrives, driveOp, grantedWriteDirs, approve, attach, fetchAttachment, ragSearch, progress, askUser, signal }) {
|
|
946
|
+
async *completion({ model, agent, messages, cacheKey, thinkingDefault, toolConfigs, generationParams, responseFormat, captureInferenceCalls, grantedDirs, grantedDrives, driveOp, grantedWriteDirs, approve, attach, fetchAttachment, ragSearch, progress, askUser, signal }) {
|
|
947
947
|
await this.ready();
|
|
948
948
|
if (this.suspended)
|
|
949
949
|
throw new Error('harness is suspended');
|
|
@@ -1016,6 +1016,7 @@ export class Harness extends ReadyResource {
|
|
|
1016
1016
|
thinkingDefault,
|
|
1017
1017
|
generationParams,
|
|
1018
1018
|
responseFormat,
|
|
1019
|
+
captureInferenceCalls,
|
|
1019
1020
|
messages: turns,
|
|
1020
1021
|
tools: this._tools,
|
|
1021
1022
|
skillCatalog: await this._completionSkills(agent?.id ?? null, model),
|
|
@@ -221,8 +221,40 @@ export type MetricsEvent = {
|
|
|
221
221
|
ctxSize?: number | undefined;
|
|
222
222
|
backends?: RunBackendUse[] | undefined;
|
|
223
223
|
usage?: UsageBreakdown | undefined;
|
|
224
|
+
stopReason?: string | undefined;
|
|
224
225
|
};
|
|
225
|
-
export
|
|
226
|
+
export interface InferenceCall {
|
|
227
|
+
round: number;
|
|
228
|
+
droppedTurns: number;
|
|
229
|
+
modelId: string;
|
|
230
|
+
messages: Message[];
|
|
231
|
+
tools: SdkTool[] | undefined;
|
|
232
|
+
generationParams: LlmGenerationParams | undefined;
|
|
233
|
+
responseFormat: ResponseFormat | undefined;
|
|
234
|
+
toolDialect: ToolDialect | undefined;
|
|
235
|
+
cacheKey: string | undefined;
|
|
236
|
+
promptPrefix: string;
|
|
237
|
+
}
|
|
238
|
+
export type InferenceCallEvent = {
|
|
239
|
+
type: 'inference-call';
|
|
240
|
+
call: InferenceCall;
|
|
241
|
+
};
|
|
242
|
+
export type InferenceSentEvent = {
|
|
243
|
+
type: 'inference-sent';
|
|
244
|
+
round: number;
|
|
245
|
+
droppedTurns: number;
|
|
246
|
+
messages: Message[] | undefined;
|
|
247
|
+
tokens: InferenceTokens | undefined;
|
|
248
|
+
outcome: 'completed' | 'overflowed' | 'failed';
|
|
249
|
+
reason: string | undefined;
|
|
250
|
+
};
|
|
251
|
+
export interface InferenceTokens {
|
|
252
|
+
prompt?: number | undefined;
|
|
253
|
+
generated?: number | undefined;
|
|
254
|
+
cached?: number | undefined;
|
|
255
|
+
timeToFirstToken?: number | undefined;
|
|
256
|
+
}
|
|
257
|
+
export type CompletionEvent = TextEvent | ToolCallEvent | ToolResultEvent | ToolActivityEvent | ErrorEvent | AbortedEvent | MetricsEvent | InferenceCallEvent | InferenceSentEvent;
|
|
226
258
|
export interface CompletionSdkResult {
|
|
227
259
|
requestId?: string;
|
|
228
260
|
tokenStream: AsyncIterable<string>;
|
|
@@ -283,6 +315,7 @@ interface CompletionArgs {
|
|
|
283
315
|
toolConfigs?: Record<string, Record<string, unknown>>;
|
|
284
316
|
fsRoots?: readonly DriveRoot[];
|
|
285
317
|
fsWriteRoots?: readonly DriveRoot[];
|
|
318
|
+
captureInferenceCalls?: boolean;
|
|
286
319
|
}
|
|
287
320
|
export declare const CONTEXT_OVERFLOW_MESSAGE = "This message is too large for the model context window.";
|
|
288
321
|
export declare function trustedSourcesFrom(history: readonly Message[]): TrustedSource[];
|
|
@@ -290,5 +323,5 @@ export declare function toSdkTool(tool: ToolDefinition): SdkTool;
|
|
|
290
323
|
export type CompletionSkillEntry = SkillCatalogEntry & {
|
|
291
324
|
readonly status?: SkillState;
|
|
292
325
|
};
|
|
293
|
-
export declare function completion(sdk: CompletionSdk, { modelId, acquireRound, model, agent, ctxSize, cacheKey, thinkingDefault, generationParams: generationParamsOverride, responseFormat, messages: storedMessages, tools: allTools, skillCatalog, approve, attach, fetchAttachment, ragSearch, progress, askUser, signal, toolConfigs, fsRoots, fsWriteRoots }: CompletionArgs): AsyncGenerator<CompletionEvent>;
|
|
326
|
+
export declare function completion(sdk: CompletionSdk, { modelId, acquireRound, model, agent, ctxSize, cacheKey, thinkingDefault, generationParams: generationParamsOverride, responseFormat, messages: storedMessages, tools: allTools, skillCatalog, approve, attach, fetchAttachment, ragSearch, progress, askUser, signal, toolConfigs, fsRoots, fsWriteRoots, captureInferenceCalls }: CompletionArgs): AsyncGenerator<CompletionEvent>;
|
|
294
327
|
export {};
|
|
@@ -157,7 +157,8 @@ function preloadLastUser(messages, name, body) {
|
|
|
157
157
|
}
|
|
158
158
|
return messages;
|
|
159
159
|
}
|
|
160
|
-
function collectStats(state, stats) {
|
|
160
|
+
function collectStats(state, stats, stopReason) {
|
|
161
|
+
state.stopReason = stopReason;
|
|
161
162
|
if (!stats)
|
|
162
163
|
return;
|
|
163
164
|
if (state.ttft === undefined && stats.timeToFirstToken)
|
|
@@ -191,7 +192,8 @@ function metricsEvent(state, usage) {
|
|
|
191
192
|
cacheTokens: state.cacheTokens,
|
|
192
193
|
...(state.ctxSize ? { ctxSize: state.ctxSize } : {}),
|
|
193
194
|
...(state.backends.length ? { backends: state.backends } : {}),
|
|
194
|
-
...(usage ? { usage } : {})
|
|
195
|
+
...(usage ? { usage } : {}),
|
|
196
|
+
...(state.stopReason ? { stopReason: state.stopReason } : {})
|
|
195
197
|
};
|
|
196
198
|
}
|
|
197
199
|
const TOOL_DENIED_MESSAGE = 'The user declined this call. Do not retry it or call it with different arguments to get ' +
|
|
@@ -463,6 +465,21 @@ async function* runRoundTokens(sdk, result, state, signal, startInThink = false)
|
|
|
463
465
|
await events.return(null);
|
|
464
466
|
}
|
|
465
467
|
}
|
|
468
|
+
function sentMessages(stats) {
|
|
469
|
+
const sent = stats?.sentMessages;
|
|
470
|
+
return Array.isArray(sent) ? sent : null;
|
|
471
|
+
}
|
|
472
|
+
function roundTokens(stats) {
|
|
473
|
+
if (!stats)
|
|
474
|
+
return undefined;
|
|
475
|
+
const tokens = {
|
|
476
|
+
prompt: stats.promptTokens,
|
|
477
|
+
generated: stats.generatedTokens,
|
|
478
|
+
cached: stats.cacheTokens,
|
|
479
|
+
timeToFirstToken: stats.timeToFirstToken
|
|
480
|
+
};
|
|
481
|
+
return Object.values(tokens).some((value) => value !== undefined) ? tokens : undefined;
|
|
482
|
+
}
|
|
466
483
|
const TRUNCATED_FINAL_MS = 2000;
|
|
467
484
|
function truncatedFinal(final, contentText) {
|
|
468
485
|
const accepted = { contentText, toolCalls: [], raw: { fullText: contentText } };
|
|
@@ -496,17 +513,35 @@ async function* runRecoveredRoundWith(sdk, args, modelId) {
|
|
|
496
513
|
let emitted = false;
|
|
497
514
|
const state = { stopToken: null, unproven: null, rawContentText: '' };
|
|
498
515
|
const cacheable = candidate.history === args.history;
|
|
516
|
+
const params = {
|
|
517
|
+
modelId,
|
|
518
|
+
history: projectVisionHistory(candidate.history),
|
|
519
|
+
stream: true,
|
|
520
|
+
tools: args.tools,
|
|
521
|
+
generationParams: args.generationParams,
|
|
522
|
+
responseFormat: args.responseFormat,
|
|
523
|
+
toolDialect: args.toolDialect,
|
|
524
|
+
kvCache: cacheable ? args.cacheKey : undefined
|
|
525
|
+
};
|
|
526
|
+
if (args.capture) {
|
|
527
|
+
yield {
|
|
528
|
+
type: 'inference-call',
|
|
529
|
+
call: {
|
|
530
|
+
round: args.round,
|
|
531
|
+
droppedTurns: candidate.droppedTurns,
|
|
532
|
+
modelId,
|
|
533
|
+
messages: params.history,
|
|
534
|
+
tools: params.tools,
|
|
535
|
+
generationParams: params.generationParams,
|
|
536
|
+
responseFormat: params.responseFormat,
|
|
537
|
+
toolDialect: params.toolDialect,
|
|
538
|
+
cacheKey: params.kvCache,
|
|
539
|
+
promptPrefix: args.promptPrefix
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
499
543
|
try {
|
|
500
|
-
const result = sdk.completion(
|
|
501
|
-
modelId,
|
|
502
|
-
history: projectVisionHistory(candidate.history),
|
|
503
|
-
stream: true,
|
|
504
|
-
tools: args.tools,
|
|
505
|
-
generationParams: args.generationParams,
|
|
506
|
-
...(args.responseFormat ? { responseFormat: args.responseFormat } : {}),
|
|
507
|
-
toolDialect: args.toolDialect,
|
|
508
|
-
...(cacheable && args.cacheKey ? { kvCache: args.cacheKey } : {})
|
|
509
|
-
});
|
|
544
|
+
const result = sdk.completion(params);
|
|
510
545
|
result.final.catch(noop);
|
|
511
546
|
const startInThink = args.generationParams?.reasoning_budget === -1;
|
|
512
547
|
for await (const event of runRoundTokens(sdk, result, state, args.signal, startInThink)) {
|
|
@@ -518,6 +553,17 @@ async function* runRecoveredRoundWith(sdk, args, modelId) {
|
|
|
518
553
|
const final = state.stopToken
|
|
519
554
|
? await truncatedFinal(result.final, state.rawContentText)
|
|
520
555
|
: await raceAbort(result.final, args.signal);
|
|
556
|
+
if (args.capture) {
|
|
557
|
+
yield {
|
|
558
|
+
type: 'inference-sent',
|
|
559
|
+
round: args.round,
|
|
560
|
+
droppedTurns: candidate.droppedTurns,
|
|
561
|
+
messages: sentMessages(final.stats) ?? undefined,
|
|
562
|
+
tokens: roundTokens(final.stats),
|
|
563
|
+
outcome: 'completed',
|
|
564
|
+
reason: undefined
|
|
565
|
+
};
|
|
566
|
+
}
|
|
521
567
|
const replay = unprovenReplay(state, final);
|
|
522
568
|
hlog('final', {
|
|
523
569
|
stopReason: final.stopReason,
|
|
@@ -535,6 +581,17 @@ async function* runRecoveredRoundWith(sdk, args, modelId) {
|
|
|
535
581
|
};
|
|
536
582
|
}
|
|
537
583
|
catch (err) {
|
|
584
|
+
if (args.capture) {
|
|
585
|
+
yield {
|
|
586
|
+
type: 'inference-sent',
|
|
587
|
+
round: args.round,
|
|
588
|
+
droppedTurns: candidate.droppedTurns,
|
|
589
|
+
messages: undefined,
|
|
590
|
+
tokens: undefined,
|
|
591
|
+
outcome: isContextOverflowError(err) ? 'overflowed' : 'failed',
|
|
592
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
593
|
+
};
|
|
594
|
+
}
|
|
538
595
|
if (!isContextOverflowError(err))
|
|
539
596
|
throw err;
|
|
540
597
|
if (emitted)
|
|
@@ -551,7 +608,7 @@ function* reportUnnamedWrites(said, landed) {
|
|
|
551
608
|
if (unreported)
|
|
552
609
|
yield { type: 'content', text: unreported };
|
|
553
610
|
}
|
|
554
|
-
export async function* completion(sdk, { modelId, acquireRound, model, agent, ctxSize, cacheKey, thinkingDefault, generationParams: generationParamsOverride, responseFormat, messages: storedMessages, tools: allTools = [], skillCatalog = [], approve, attach, fetchAttachment, ragSearch, progress, askUser, signal, toolConfigs, fsRoots = [], fsWriteRoots = [] }) {
|
|
611
|
+
export async function* completion(sdk, { modelId, acquireRound, model, agent, ctxSize, cacheKey, thinkingDefault, generationParams: generationParamsOverride, responseFormat, messages: storedMessages, tools: allTools = [], skillCatalog = [], approve, attach, fetchAttachment, ragSearch, progress, askUser, signal, toolConfigs, fsRoots = [], fsWriteRoots = [], captureInferenceCalls = false }) {
|
|
555
612
|
const pipeline = new HookPipeline();
|
|
556
613
|
const agentId = agent?.id ?? null;
|
|
557
614
|
const tools = permittedTools(allTools, agent?.disabledToolsets);
|
|
@@ -789,7 +846,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
789
846
|
let mute = 0;
|
|
790
847
|
let narrated = false;
|
|
791
848
|
let cappedRounds = 0;
|
|
792
|
-
|
|
849
|
+
let roundsSent = 0;
|
|
850
|
+
let round = 0;
|
|
851
|
+
for (; round < MAX_TOOL_ROUNDS; round++) {
|
|
793
852
|
if (signal?.aborted)
|
|
794
853
|
throw new AbortedError();
|
|
795
854
|
if (Date.now() >= runBudget.deadlineMs) {
|
|
@@ -820,13 +879,17 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
820
879
|
responseFormat,
|
|
821
880
|
toolDialect,
|
|
822
881
|
cacheKey: roundCacheKey,
|
|
823
|
-
signal
|
|
882
|
+
signal,
|
|
883
|
+
round,
|
|
884
|
+
promptPrefix,
|
|
885
|
+
capture: captureInferenceCalls
|
|
824
886
|
});
|
|
887
|
+
roundsSent = round + 1;
|
|
825
888
|
const final = recovered.final;
|
|
826
889
|
if (!recovered.cacheable)
|
|
827
890
|
roundCacheKey = undefined;
|
|
828
891
|
history = recovered.history;
|
|
829
|
-
collectStats(stats, final.stats);
|
|
892
|
+
collectStats(stats, final.stats, final.stopReason);
|
|
830
893
|
hlog('round stats', { round, wallMs: Date.now() - roundStarted, ...(final.stats ?? {}) });
|
|
831
894
|
const markup = stripToolResponseBlocks(truncateAtControlToken(final.raw.fullText) || recovered.unproven || '');
|
|
832
895
|
let toolCalls = final.toolCalls?.length
|
|
@@ -1060,9 +1123,12 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1060
1123
|
tools: undefined,
|
|
1061
1124
|
generationParams,
|
|
1062
1125
|
cacheKey: roundCacheKey,
|
|
1063
|
-
signal
|
|
1126
|
+
signal,
|
|
1127
|
+
round: roundsSent,
|
|
1128
|
+
promptPrefix: promptPrefixHash({ system: systemContent, tools: undefined }),
|
|
1129
|
+
capture: captureInferenceCalls
|
|
1064
1130
|
});
|
|
1065
|
-
collectStats(stats, recovered.final.stats);
|
|
1131
|
+
collectStats(stats, recovered.final.stats, recovered.final.stopReason);
|
|
1066
1132
|
const answer = recovered.replay ? stripToolCallMarkup(recovered.replay) : '';
|
|
1067
1133
|
if (answer)
|
|
1068
1134
|
yield { type: 'content', text: answer };
|
package/dist-lib/lib/connect.js
CHANGED
|
@@ -112,6 +112,7 @@ export class RemoteHarness extends EventEmitter {
|
|
|
112
112
|
thinkingDefault: context.thinkingDefault,
|
|
113
113
|
generationParams: context.generationParams,
|
|
114
114
|
responseFormat: context.responseFormat,
|
|
115
|
+
captureInferenceCalls: context.captureInferenceCalls,
|
|
115
116
|
messages: context.messages.map(({ role, content, attachments }) => ({
|
|
116
117
|
role,
|
|
117
118
|
content,
|
|
@@ -48,6 +48,7 @@ export interface CompletionContext {
|
|
|
48
48
|
toolConfigs?: Record<string, Record<string, unknown>>;
|
|
49
49
|
generationParams?: LlmGenerationParams;
|
|
50
50
|
responseFormat?: ResponseFormat;
|
|
51
|
+
captureInferenceCalls?: boolean;
|
|
51
52
|
grantedDirs?: string[];
|
|
52
53
|
grantedDrives?: GrantedDrive[];
|
|
53
54
|
driveOp?: DriveOpFn;
|
package/dist-lib/lib/serve.js
CHANGED
|
@@ -414,6 +414,7 @@ function completion(harness) {
|
|
|
414
414
|
thinkingDefault: frame.thinkingDefault ?? undefined,
|
|
415
415
|
generationParams: frame.generationParams ?? undefined,
|
|
416
416
|
responseFormat: frame.responseFormat ?? undefined,
|
|
417
|
+
captureInferenceCalls: frame.captureInferenceCalls ?? undefined,
|
|
417
418
|
messages: (frame.messages ?? []).map(({ role, content, attachments }) => ({
|
|
418
419
|
role,
|
|
419
420
|
content,
|
package/dist-lib/lib/wire.js
CHANGED
|
@@ -32,6 +32,20 @@ export function toWire(event) {
|
|
|
32
32
|
const { type, ...metrics } = event;
|
|
33
33
|
return { type, metrics };
|
|
34
34
|
}
|
|
35
|
+
case 'inference-call':
|
|
36
|
+
return { type: 'inference-call', payload: event.call };
|
|
37
|
+
case 'inference-sent':
|
|
38
|
+
return {
|
|
39
|
+
type: 'inference-sent',
|
|
40
|
+
payload: {
|
|
41
|
+
round: event.round,
|
|
42
|
+
droppedTurns: event.droppedTurns,
|
|
43
|
+
messages: event.messages,
|
|
44
|
+
tokens: event.tokens,
|
|
45
|
+
outcome: event.outcome,
|
|
46
|
+
reason: event.reason
|
|
47
|
+
}
|
|
48
|
+
};
|
|
35
49
|
case 'error':
|
|
36
50
|
return { type: 'error', message: event.message };
|
|
37
51
|
case 'aborted':
|
|
@@ -73,6 +87,20 @@ export function fromWire(event) {
|
|
|
73
87
|
};
|
|
74
88
|
case 'metrics':
|
|
75
89
|
return { type: 'metrics', ...event.metrics };
|
|
90
|
+
case 'inference-call':
|
|
91
|
+
return { type: 'inference-call', call: event.payload };
|
|
92
|
+
case 'inference-sent': {
|
|
93
|
+
const sent = (event.payload ?? {});
|
|
94
|
+
return {
|
|
95
|
+
type: 'inference-sent',
|
|
96
|
+
messages: sent.messages,
|
|
97
|
+
round: Number(sent.round ?? 0),
|
|
98
|
+
droppedTurns: Number(sent.droppedTurns ?? 0),
|
|
99
|
+
tokens: sent.tokens,
|
|
100
|
+
outcome: sent.outcome || 'completed',
|
|
101
|
+
reason: sent.reason || undefined
|
|
102
|
+
};
|
|
103
|
+
}
|
|
76
104
|
case 'error':
|
|
77
105
|
return { type: 'error', message: event.message ?? 'harness error' };
|
|
78
106
|
case 'aborted':
|
|
@@ -107,7 +107,8 @@ export function registerHarnessTypes(ns) {
|
|
|
107
107
|
{ name: 'grantedDirs', type: 'string', array: true },
|
|
108
108
|
{ name: 'grantedDrives', type: '@harness/granted-drive', array: true },
|
|
109
109
|
{ name: 'payload', type: 'json' },
|
|
110
|
-
{ name: 'grantedWriteDirs', type: 'string', array: true }
|
|
110
|
+
{ name: 'grantedWriteDirs', type: 'string', array: true },
|
|
111
|
+
{ name: 'captureInferenceCalls', type: 'bool' }
|
|
111
112
|
]
|
|
112
113
|
});
|
|
113
114
|
ns.register({
|
|
@@ -128,7 +129,9 @@ export function registerHarnessTypes(ns) {
|
|
|
128
129
|
'question-ask',
|
|
129
130
|
'done',
|
|
130
131
|
'tool-activity',
|
|
131
|
-
'drive-ask'
|
|
132
|
+
'drive-ask',
|
|
133
|
+
'inference-call',
|
|
134
|
+
'inference-sent'
|
|
132
135
|
],
|
|
133
136
|
strings: true
|
|
134
137
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// This file is autogenerated by the hyperschema compiler
|
|
2
|
-
// Schema Version:
|
|
2
|
+
// Schema Version: 9
|
|
3
3
|
/* eslint-disable camelcase */
|
|
4
4
|
/* eslint-disable quotes */
|
|
5
5
|
/* eslint-disable space-before-function-paren */
|
|
6
6
|
|
|
7
7
|
import { c } from 'hyperschema/runtime'
|
|
8
8
|
|
|
9
|
-
const VERSION =
|
|
9
|
+
const VERSION = 9
|
|
10
10
|
|
|
11
11
|
// eslint-disable-next-line no-unused-vars
|
|
12
12
|
let version = VERSION
|
|
@@ -478,7 +478,8 @@ const encoding11 = {
|
|
|
478
478
|
((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
|
|
479
479
|
((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
|
|
480
480
|
((version >= 5 && m.payload) ? 8388608 : 0) |
|
|
481
|
-
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
|
|
481
|
+
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
|
|
482
|
+
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
|
|
482
483
|
|
|
483
484
|
encoding10.preencode(state, m.type)
|
|
484
485
|
c.uint.preencode(state, flags)
|
|
@@ -533,7 +534,8 @@ const encoding11 = {
|
|
|
533
534
|
((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
|
|
534
535
|
((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
|
|
535
536
|
((version >= 5 && m.payload) ? 8388608 : 0) |
|
|
536
|
-
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
|
|
537
|
+
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
|
|
538
|
+
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
|
|
537
539
|
|
|
538
540
|
encoding10.encode(state, m.type)
|
|
539
541
|
c.uint.encode(state, flags)
|
|
@@ -592,7 +594,8 @@ const encoding11 = {
|
|
|
592
594
|
grantedDirs: (version >= 5 && (flags & 2097152) !== 0) ? encoding11_22.decode(state) : null,
|
|
593
595
|
grantedDrives: (version >= 5 && (flags & 4194304) !== 0) ? encoding11_23.decode(state) : null,
|
|
594
596
|
payload: (version >= 5 && (flags & 8388608) !== 0) ? c.json.decode(state) : null,
|
|
595
|
-
grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null
|
|
597
|
+
grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null,
|
|
598
|
+
captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0)
|
|
596
599
|
}
|
|
597
600
|
}
|
|
598
601
|
}
|
|
@@ -613,13 +616,15 @@ const encoding12_enum = {
|
|
|
613
616
|
"question-ask": 'question-ask',
|
|
614
617
|
done: 'done',
|
|
615
618
|
"tool-activity": 'tool-activity',
|
|
616
|
-
"drive-ask": 'drive-ask'
|
|
619
|
+
"drive-ask": 'drive-ask',
|
|
620
|
+
"inference-call": 'inference-call',
|
|
621
|
+
"inference-sent": 'inference-sent'
|
|
617
622
|
}
|
|
618
623
|
|
|
619
624
|
// @harness/completion-event-type enum
|
|
620
625
|
const encoding12 = {
|
|
621
626
|
preencode (state, m) {
|
|
622
|
-
state.end++ // max enum is
|
|
627
|
+
state.end++ // max enum is 18 so always one byte
|
|
623
628
|
},
|
|
624
629
|
encode (state, m) {
|
|
625
630
|
switch (m) {
|
|
@@ -671,6 +676,12 @@ const encoding12 = {
|
|
|
671
676
|
case 'drive-ask':
|
|
672
677
|
c.uint.encode(state, 16)
|
|
673
678
|
break
|
|
679
|
+
case 'inference-call':
|
|
680
|
+
c.uint.encode(state, 17)
|
|
681
|
+
break
|
|
682
|
+
case 'inference-sent':
|
|
683
|
+
c.uint.encode(state, 18)
|
|
684
|
+
break
|
|
674
685
|
default:
|
|
675
686
|
throw new Error('Unknown enum')
|
|
676
687
|
}
|
|
@@ -709,6 +720,10 @@ const encoding12 = {
|
|
|
709
720
|
return 'tool-activity'
|
|
710
721
|
case 16:
|
|
711
722
|
return 'drive-ask'
|
|
723
|
+
case 17:
|
|
724
|
+
return 'inference-call'
|
|
725
|
+
case 18:
|
|
726
|
+
return 'inference-sent'
|
|
712
727
|
default: return null
|
|
713
728
|
}
|
|
714
729
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// This file is autogenerated by the hyperschema compiler
|
|
2
|
-
// Schema Version:
|
|
2
|
+
// Schema Version: 9
|
|
3
3
|
/* eslint-disable camelcase */
|
|
4
4
|
/* eslint-disable quotes */
|
|
5
5
|
/* eslint-disable space-before-function-paren */
|
|
6
6
|
|
|
7
7
|
import { c } from 'hyperschema/runtime'
|
|
8
8
|
|
|
9
|
-
const VERSION =
|
|
9
|
+
const VERSION = 9
|
|
10
10
|
|
|
11
11
|
// eslint-disable-next-line no-unused-vars
|
|
12
12
|
let version = VERSION
|
|
@@ -478,7 +478,8 @@ const encoding11 = {
|
|
|
478
478
|
((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
|
|
479
479
|
((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
|
|
480
480
|
((version >= 5 && m.payload) ? 8388608 : 0) |
|
|
481
|
-
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
|
|
481
|
+
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
|
|
482
|
+
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
|
|
482
483
|
|
|
483
484
|
encoding10.preencode(state, m.type)
|
|
484
485
|
c.uint.preencode(state, flags)
|
|
@@ -533,7 +534,8 @@ const encoding11 = {
|
|
|
533
534
|
((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
|
|
534
535
|
((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
|
|
535
536
|
((version >= 5 && m.payload) ? 8388608 : 0) |
|
|
536
|
-
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
|
|
537
|
+
((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
|
|
538
|
+
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
|
|
537
539
|
|
|
538
540
|
encoding10.encode(state, m.type)
|
|
539
541
|
c.uint.encode(state, flags)
|
|
@@ -592,7 +594,8 @@ const encoding11 = {
|
|
|
592
594
|
grantedDirs: (version >= 5 && (flags & 2097152) !== 0) ? encoding11_22.decode(state) : null,
|
|
593
595
|
grantedDrives: (version >= 5 && (flags & 4194304) !== 0) ? encoding11_23.decode(state) : null,
|
|
594
596
|
payload: (version >= 5 && (flags & 8388608) !== 0) ? c.json.decode(state) : null,
|
|
595
|
-
grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null
|
|
597
|
+
grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null,
|
|
598
|
+
captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0)
|
|
596
599
|
}
|
|
597
600
|
}
|
|
598
601
|
}
|
|
@@ -613,13 +616,15 @@ const encoding12_enum = {
|
|
|
613
616
|
"question-ask": 'question-ask',
|
|
614
617
|
done: 'done',
|
|
615
618
|
"tool-activity": 'tool-activity',
|
|
616
|
-
"drive-ask": 'drive-ask'
|
|
619
|
+
"drive-ask": 'drive-ask',
|
|
620
|
+
"inference-call": 'inference-call',
|
|
621
|
+
"inference-sent": 'inference-sent'
|
|
617
622
|
}
|
|
618
623
|
|
|
619
624
|
// @harness/completion-event-type enum
|
|
620
625
|
const encoding12 = {
|
|
621
626
|
preencode (state, m) {
|
|
622
|
-
state.end++ // max enum is
|
|
627
|
+
state.end++ // max enum is 18 so always one byte
|
|
623
628
|
},
|
|
624
629
|
encode (state, m) {
|
|
625
630
|
switch (m) {
|
|
@@ -671,6 +676,12 @@ const encoding12 = {
|
|
|
671
676
|
case 'drive-ask':
|
|
672
677
|
c.uint.encode(state, 16)
|
|
673
678
|
break
|
|
679
|
+
case 'inference-call':
|
|
680
|
+
c.uint.encode(state, 17)
|
|
681
|
+
break
|
|
682
|
+
case 'inference-sent':
|
|
683
|
+
c.uint.encode(state, 18)
|
|
684
|
+
break
|
|
674
685
|
default:
|
|
675
686
|
throw new Error('Unknown enum')
|
|
676
687
|
}
|
|
@@ -709,6 +720,10 @@ const encoding12 = {
|
|
|
709
720
|
return 'tool-activity'
|
|
710
721
|
case 16:
|
|
711
722
|
return 'drive-ask'
|
|
723
|
+
case 17:
|
|
724
|
+
return 'inference-call'
|
|
725
|
+
case 18:
|
|
726
|
+
return 'inference-sent'
|
|
712
727
|
default: return null
|
|
713
728
|
}
|
|
714
729
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 9,
|
|
3
3
|
"schema": [
|
|
4
4
|
{
|
|
5
5
|
"name": "empty",
|
|
@@ -446,6 +446,11 @@
|
|
|
446
446
|
"array": true,
|
|
447
447
|
"type": "string",
|
|
448
448
|
"version": 5
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"name": "captureInferenceCalls",
|
|
452
|
+
"type": "bool",
|
|
453
|
+
"version": 9
|
|
449
454
|
}
|
|
450
455
|
]
|
|
451
456
|
},
|
|
@@ -517,6 +522,14 @@
|
|
|
517
522
|
{
|
|
518
523
|
"key": "drive-ask",
|
|
519
524
|
"version": 5
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
"key": "inference-call",
|
|
528
|
+
"version": 9
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
"key": "inference-sent",
|
|
532
|
+
"version": 9
|
|
520
533
|
}
|
|
521
534
|
],
|
|
522
535
|
"strings": true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// This file is autogenerated by hyperschema-ts
|
|
2
|
-
// Schema version:
|
|
2
|
+
// Schema version: 9
|
|
3
3
|
// Do not edit manually.
|
|
4
4
|
|
|
5
5
|
export interface HarnessEmpty {
|
|
@@ -86,9 +86,10 @@ export interface HarnessCompletionFrame {
|
|
|
86
86
|
grantedDrives?: HarnessGrantedDrive[] | null
|
|
87
87
|
payload?: unknown | null
|
|
88
88
|
grantedWriteDirs?: string[] | null
|
|
89
|
+
captureInferenceCalls?: boolean
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
export type HarnessCompletionEventType = "content" | "thinking" | "tool-call" | "tool-result" | "approval-ask" | "metrics" | "error" | "aborted" | "attach-ask" | "fetch-ask" | "progress" | "rag-ask" | "question-ask" | "done" | "tool-activity" | "drive-ask"
|
|
92
|
+
export type HarnessCompletionEventType = "content" | "thinking" | "tool-call" | "tool-result" | "approval-ask" | "metrics" | "error" | "aborted" | "attach-ask" | "fetch-ask" | "progress" | "rag-ask" | "question-ask" | "done" | "tool-activity" | "drive-ask" | "inference-call" | "inference-sent"
|
|
92
93
|
|
|
93
94
|
export interface HarnessCompletionEvent {
|
|
94
95
|
type: HarnessCompletionEventType
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qvac/harness",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An AI harness implementing generate(context) via @qvac/sdk. Knows nothing about workbench, hyperdb, or chunks — just inference in, events out.",
|
|
6
6
|
"exports": {
|
|
@@ -555,9 +555,8 @@
|
|
|
555
555
|
},
|
|
556
556
|
"scripts": {
|
|
557
557
|
"build:schema": "bare schema/build.ts",
|
|
558
|
-
"test": "npm run vendor:wheels && npm run test:
|
|
559
|
-
"test:
|
|
560
|
-
"test:bare": "QVAC_NO_SKILL_BIN_PROBE=1 brittle-bare test/all.ts | prettytap",
|
|
558
|
+
"test": "npm run vendor:wheels && npm run test:bare && npm run test:addons",
|
|
559
|
+
"test:bare": "QVAC_NO_SKILL_BIN_PROBE=1 prettytap -- brittle-bare test/all.ts",
|
|
561
560
|
"format": "prettier . --write",
|
|
562
561
|
"lint": "prettier . --check && lunte && tsc --noEmit",
|
|
563
562
|
"build:bundle": "node scripts/build-bundle.mjs",
|
|
@@ -714,7 +713,7 @@
|
|
|
714
713
|
"lunte": "^1.8.3",
|
|
715
714
|
"prettier": "^3.6.2",
|
|
716
715
|
"prettier-config-holepunch": "^2.0.0",
|
|
717
|
-
"prettytap": "^0.
|
|
716
|
+
"prettytap": "^0.2.0",
|
|
718
717
|
"terser": "^5.51.2",
|
|
719
718
|
"typescript": "^7.0.2"
|
|
720
719
|
},
|
|
@@ -724,7 +723,8 @@
|
|
|
724
723
|
"localwatch@1.4.3": "patches/localwatch@1.4.3.patch",
|
|
725
724
|
"hypercore-blob-server@1.15.0": "patches/hypercore-blob-server@1.15.0.patch",
|
|
726
725
|
"bare-stow@0.1.5": "patches/bare-stow@0.1.5.patch",
|
|
727
|
-
"@qvac/inference@0.19.0": "patches/@qvac%2Finference@0.19.0.patch"
|
|
726
|
+
"@qvac/inference@0.19.0": "patches/@qvac%2Finference@0.19.0.patch",
|
|
727
|
+
"brittle@4.1.0": "patches/brittle@4.1.0.patch"
|
|
728
728
|
},
|
|
729
729
|
"repository": {
|
|
730
730
|
"type": "git",
|