@qvac/harness 0.2.12 → 0.3.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.
@@ -1,6 +1,7 @@
1
1
  import ScopeLock from 'scope-lock';
2
2
  import { AbortedError, raceAbort } from '../helpers/race-abort.js';
3
3
  import { DIFFUSION_CATALOG, imageModelFor } from '../models/model-catalog.js';
4
+ import { createLoadStall } from '../helpers/load-stall.js';
4
5
  import { createLoadTracker } from '../models/model-pool.js';
5
6
  import { resolveModelSrc } from '../models/model-source.js';
6
7
  export const MAX_DIM = 1024;
@@ -36,30 +37,6 @@ function diffusionProgressName(set) {
36
37
  return entry?.name ?? set.model;
37
38
  }
38
39
  export const IMAGE_LOAD_STALL_ERROR = 'image model download stalled';
39
- function createLoadStall(ms) {
40
- let timer = null;
41
- let rejectStall = null;
42
- const promise = new Promise((_, reject) => {
43
- rejectStall = reject;
44
- });
45
- const arm = () => {
46
- if (timer !== null)
47
- clearTimeout(timer);
48
- timer = setTimeout(() => {
49
- rejectStall?.(new Error(IMAGE_LOAD_STALL_ERROR));
50
- }, ms);
51
- };
52
- arm();
53
- return {
54
- bump: arm,
55
- clear: () => {
56
- if (timer !== null)
57
- clearTimeout(timer);
58
- timer = null;
59
- },
60
- promise
61
- };
62
- }
63
40
  export function createDiffusionRuntime({ loadSdk, onProgress, onLoaded, onBeforeLoad, loads = createLoadTracker(), stallMs = IMAGE_LOAD_STALL_MS, ...base }) {
64
41
  let loading = null;
65
42
  let residentFingerprint = null;
@@ -116,7 +93,7 @@ export function createDiffusionRuntime({ loadSdk, onProgress, onLoaded, onBefore
116
93
  config.vaeModelSrc = await resolveModelSrc(sdk, set.vaeModel, 'diffusion');
117
94
  }
118
95
  const modelConfig = Object.keys(config).length ? config : undefined;
119
- const stall = createLoadStall(stallMs);
96
+ const stall = createLoadStall(stallMs, IMAGE_LOAD_STALL_ERROR);
120
97
  const pending = sdk.loadModel({
121
98
  modelSrc,
122
99
  modelType: 'diffusion',
@@ -0,0 +1,78 @@
1
+ import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
2
+ import type { ToolDefinition } from '../capabilities/completion.ts';
3
+ import type { ModelSrc } from '../models/context.ts';
4
+ import { type NmtPlan } from '../models/nmt-catalog.ts';
5
+ import { type LoadTracker, type TrackedLoad } from '../models/model-pool.ts';
6
+ import { type ModelRegistrySdk } from '../models/model-source.ts';
7
+ interface BergamotConfig {
8
+ engine: 'Bergamot';
9
+ from: string;
10
+ to: string;
11
+ pivotModel?: {
12
+ modelSrc: ModelSrc;
13
+ };
14
+ srcVocabSrc?: string;
15
+ dstVocabSrc?: string;
16
+ }
17
+ export type TranslationSdk = ModelRegistrySdk & {
18
+ loadModel(params: {
19
+ modelSrc: ModelSrc;
20
+ modelType: 'nmtcpp-translation';
21
+ modelConfig: BergamotConfig;
22
+ onProgress?: (progress: Record<string, unknown>) => void;
23
+ }): TrackedLoad;
24
+ unloadModel(params: {
25
+ modelId: string;
26
+ }): Promise<unknown>;
27
+ cancel?(params: {
28
+ requestId: string;
29
+ }): Promise<void>;
30
+ translate(params: {
31
+ modelId: string;
32
+ text: string;
33
+ stream: false;
34
+ modelType: 'nmt';
35
+ }): {
36
+ text: Promise<string>;
37
+ };
38
+ };
39
+ export declare const TRANSLATION_LOAD_STALL_MS: number;
40
+ export declare const TRANSLATION_LOAD_STALL_ERROR = "translation model download stalled";
41
+ export interface TranslationRuntimeOptions {
42
+ loadSdk: () => Promise<TranslationSdk>;
43
+ loads?: LoadTracker;
44
+ onProgress?: (model: string, progress: Record<string, unknown>) => void;
45
+ stallMs?: number;
46
+ }
47
+ export interface TranslationRuntime {
48
+ loadSdk: () => Promise<TranslationSdk>;
49
+ ensureLoaded: (sdk: TranslationSdk, plan: NmtPlan, signal?: BareAbortSignal) => Promise<{
50
+ modelId: string;
51
+ }>;
52
+ unload: () => Promise<void>;
53
+ enter: (signal?: BareAbortSignal) => Promise<void>;
54
+ exit: () => void;
55
+ }
56
+ export declare function createTranslationRuntime({ loadSdk, loads, onProgress, stallMs }: TranslationRuntimeOptions): TranslationRuntime;
57
+ export type SlmTranslateFn = (model: string, params: {
58
+ text: string;
59
+ from: string;
60
+ to: string;
61
+ }, signal?: BareAbortSignal) => Promise<string>;
62
+ export declare function stripLanguageLabel(text: string, ...codes: string[]): string;
63
+ export interface TranslateArgs {
64
+ text: string;
65
+ to: string;
66
+ from?: string;
67
+ }
68
+ export declare function parseTranslateArgs(args: Record<string, unknown>): TranslateArgs | {
69
+ error: string;
70
+ };
71
+ export declare function sourceLanguage(text: string, from?: string): string | {
72
+ error: string;
73
+ };
74
+ export interface TranslateToolOptions {
75
+ slm?: SlmTranslateFn;
76
+ }
77
+ export declare function createTranslateTool(runtime: TranslationRuntime, { slm }?: TranslateToolOptions): ToolDefinition;
78
+ export {};
@@ -0,0 +1,228 @@
1
+ import ScopeLock from 'scope-lock';
2
+ import { getLangName } from '@qvac/langdetect-text';
3
+ import { detectLanguage, UNDETERMINED } from '../capabilities/detect-language.js';
4
+ import { AbortedError, raceAbort } from '../helpers/race-abort.js';
5
+ import { ENGLISH, NMT_FROM_ENGLISH, NMT_TO_ENGLISH, languageLabel, SLM_LANGUAGE_CODES, sameLanguage, translationPlanFor } from '../models/nmt-catalog.js';
6
+ import { createLoadStall } from '../helpers/load-stall.js';
7
+ import { createLoadTracker } from '../models/model-pool.js';
8
+ import { resolveModelSrc } from '../models/model-source.js';
9
+ export const TRANSLATION_LOAD_STALL_MS = 15 * 60_000;
10
+ export const TRANSLATION_LOAD_STALL_ERROR = 'translation model download stalled';
11
+ function packName(plan) {
12
+ const pair = plan.model.match(/model\.([a-z]+)\.intgemm/)?.[1];
13
+ if (pair)
14
+ return `Bergamot ${pair}`;
15
+ return plan.model.includes('/en-xx/') ? 'EuroNano en-xx' : 'EuroNano xx-en';
16
+ }
17
+ const fingerprintOf = (plan) => `${plan.model}|${plan.pivot ?? ''}`;
18
+ function bergamotConfig(plan) {
19
+ const config = { engine: 'Bergamot', from: plan.from, to: plan.to };
20
+ if (plan.srcVocab)
21
+ config.srcVocabSrc = plan.srcVocab;
22
+ if (plan.dstVocab)
23
+ config.dstVocabSrc = plan.dstVocab;
24
+ return config;
25
+ }
26
+ export function createTranslationRuntime({ loadSdk, loads = createLoadTracker(), onProgress, stallMs = TRANSLATION_LOAD_STALL_MS }) {
27
+ let loading = null;
28
+ let residentFingerprint = null;
29
+ const lock = new ScopeLock();
30
+ const turn = new ScopeLock();
31
+ const loadPack = async (sdk, plan) => {
32
+ const modelSrc = await resolveModelSrc(sdk, plan.model, 'nmt');
33
+ const modelConfig = bergamotConfig(plan);
34
+ if (plan.pivot) {
35
+ modelConfig.pivotModel = { modelSrc: await resolveModelSrc(sdk, plan.pivot, 'nmt') };
36
+ }
37
+ const name = packName(plan);
38
+ const stall = createLoadStall(stallMs, TRANSLATION_LOAD_STALL_ERROR);
39
+ onProgress?.(name, {});
40
+ const pending = sdk.loadModel({
41
+ modelSrc,
42
+ modelType: 'nmtcpp-translation',
43
+ modelConfig,
44
+ onProgress: (progress) => {
45
+ stall.bump();
46
+ onProgress?.(name, progress);
47
+ }
48
+ });
49
+ try {
50
+ const modelId = await Promise.race([loads.track(pending), stall.promise]);
51
+ return { modelId };
52
+ }
53
+ catch (err) {
54
+ if (err instanceof Error &&
55
+ err.message === TRANSLATION_LOAD_STALL_ERROR &&
56
+ pending.requestId) {
57
+ void sdk.cancel?.({ requestId: pending.requestId }).catch(() => { });
58
+ }
59
+ throw err;
60
+ }
61
+ finally {
62
+ stall.clear();
63
+ }
64
+ };
65
+ const doUnload = async () => {
66
+ const pending = loading;
67
+ if (!pending) {
68
+ residentFingerprint = null;
69
+ return;
70
+ }
71
+ const loaded = await pending.catch(() => null);
72
+ if (!loaded) {
73
+ loading = null;
74
+ residentFingerprint = null;
75
+ return;
76
+ }
77
+ const sdk = await loadSdk();
78
+ await sdk.unloadModel({ modelId: loaded.modelId });
79
+ loading = null;
80
+ residentFingerprint = null;
81
+ };
82
+ const unload = async () => {
83
+ await lock.lock();
84
+ try {
85
+ await doUnload();
86
+ }
87
+ finally {
88
+ lock.unlock();
89
+ }
90
+ };
91
+ return {
92
+ loadSdk,
93
+ ensureLoaded: async (sdk, plan, signal) => {
94
+ const fingerprint = fingerprintOf(plan);
95
+ await lock.lock();
96
+ try {
97
+ if (loading && residentFingerprint !== fingerprint)
98
+ await doUnload();
99
+ residentFingerprint = fingerprint;
100
+ loading ??= loadPack(sdk, plan).catch((err) => {
101
+ loading = null;
102
+ residentFingerprint = null;
103
+ throw err;
104
+ });
105
+ }
106
+ finally {
107
+ lock.unlock();
108
+ }
109
+ return raceAbort(loading, signal);
110
+ },
111
+ unload,
112
+ enter: async (signal) => {
113
+ const pending = turn.lock();
114
+ try {
115
+ await raceAbort(pending, signal);
116
+ }
117
+ catch (err) {
118
+ void pending.then(() => turn.unlock());
119
+ throw err;
120
+ }
121
+ },
122
+ exit: () => turn.unlock()
123
+ };
124
+ }
125
+ export function stripLanguageLabel(text, ...codes) {
126
+ const at = text.indexOf(':');
127
+ if (at === -1)
128
+ return text;
129
+ const head = text.slice(0, at).trim();
130
+ const labels = codes.map((code) => languageLabel(code) ?? getLangName(code));
131
+ return labels.includes(head) ? text.slice(at + 1).trim() : text;
132
+ }
133
+ export function parseTranslateArgs(args) {
134
+ const text = typeof args.text === 'string' ? args.text.trim() : '';
135
+ if (!text)
136
+ return { error: 'text must be a non-empty string' };
137
+ const to = typeof args.to === 'string' ? args.to.trim() : '';
138
+ if (!to)
139
+ return { error: 'to must be a language code' };
140
+ const from = typeof args.from === 'string' ? args.from.trim() : undefined;
141
+ return { text, to, from };
142
+ }
143
+ export function sourceLanguage(text, from) {
144
+ if (from)
145
+ return from;
146
+ const [{ code }] = detectLanguage({ text });
147
+ if (code === UNDETERMINED)
148
+ return { error: NEEDS_SOURCE };
149
+ return code;
150
+ }
151
+ const NEEDS_SOURCE = 'could not detect the source language; pass `from` explicitly';
152
+ export function createTranslateTool(runtime, { slm } = {}) {
153
+ return {
154
+ name: 'translate',
155
+ toolset: null,
156
+ description: 'Translate text between languages using the local neural translation models. ' +
157
+ `\`to\` and \`from\` are ISO 639-1 codes. Translating into ${ENGLISH} supports ` +
158
+ `${NMT_TO_ENGLISH.length} languages and out of it ${NMT_FROM_ENGLISH.length}; a pair ` +
159
+ 'with English on neither side is translated through English, except between the ' +
160
+ 'languages below. ' +
161
+ `${SLM_LANGUAGE_CODES.length} further languages, mostly African, may also be named by ` +
162
+ 'their FLORES-200 code and always need an explicit `from`, which the detector cannot ' +
163
+ 'name. Elsewhere `from` is detected from the text when omitted; pass it when known.',
164
+ parameters: {
165
+ type: 'object',
166
+ properties: {
167
+ text: { type: 'string', description: 'The text to translate' },
168
+ to: {
169
+ type: 'string',
170
+ description: 'Target language as an ISO 639-1 code, e.g. `es`, or a FLORES-200 code'
171
+ },
172
+ from: {
173
+ type: 'string',
174
+ description: 'Source language as an ISO 639-1 or FLORES-200 code; detected from the text when omitted'
175
+ }
176
+ },
177
+ required: ['text', 'to']
178
+ },
179
+ effect: () => 'read',
180
+ resource: (args) => ({ kind: 'translation', label: String(args.to ?? '') }),
181
+ execute: async (args, ctx) => {
182
+ const parsed = parseTranslateArgs(args);
183
+ if ('error' in parsed)
184
+ return parsed;
185
+ const from = sourceLanguage(parsed.text, parsed.from);
186
+ if (typeof from === 'object')
187
+ return from;
188
+ if (sameLanguage(from, parsed.to)) {
189
+ return { text: parsed.text, from, to: parsed.to, engine: 'none' };
190
+ }
191
+ const plan = translationPlanFor(from, parsed.to);
192
+ if ('error' in plan)
193
+ return plan;
194
+ if (plan.route === 'slm' && !slm) {
195
+ return { error: `this device cannot translate ${from} to ${parsed.to}` };
196
+ }
197
+ let entered = false;
198
+ try {
199
+ await runtime.enter(ctx?.signal);
200
+ entered = true;
201
+ if (plan.route === 'slm') {
202
+ const text = await slm(plan.model, { text: parsed.text, from: plan.from, to: plan.to }, ctx?.signal);
203
+ return {
204
+ text: stripLanguageLabel(text, plan.from, plan.to),
205
+ from,
206
+ to: parsed.to,
207
+ engine: 'slm',
208
+ model: plan.model
209
+ };
210
+ }
211
+ const sdk = await runtime.loadSdk();
212
+ const { modelId } = await runtime.ensureLoaded(sdk, plan, ctx?.signal);
213
+ const source = plan.tag ? `${plan.tag} ${parsed.text}` : parsed.text;
214
+ const text = await raceAbort(sdk.translate({ modelId, text: source, stream: false, modelType: 'nmt' }).text, ctx?.signal);
215
+ return { text, from, to: parsed.to, engine: 'nmt', pivoted: Boolean(plan.pivot) };
216
+ }
217
+ catch (err) {
218
+ if (err instanceof AbortedError)
219
+ return { error: 'translation canceled' };
220
+ throw err;
221
+ }
222
+ finally {
223
+ if (entered)
224
+ runtime.exit();
225
+ }
226
+ }
227
+ };
228
+ }
@@ -112,7 +112,8 @@ export function registerHarnessTypes(ns) {
112
112
  { name: 'grantedWriteDirs', type: 'string', array: true },
113
113
  { name: 'captureInferenceCalls', type: 'bool' },
114
114
  { name: 'capability', type: 'string' },
115
- { name: 'arguments', type: 'json' }
115
+ { name: 'arguments', type: 'json' },
116
+ { name: 'enhance', type: 'string' }
116
117
  ]
117
118
  });
118
119
  ns.register({
@@ -1,12 +1,12 @@
1
1
  // This file is autogenerated by the hyperschema compiler
2
- // Schema Version: 11
2
+ // Schema Version: 12
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 = 11
9
+ const VERSION = 12
10
10
 
11
11
  // eslint-disable-next-line no-unused-vars
12
12
  let version = VERSION
@@ -490,7 +490,8 @@ const encoding11 = {
490
490
  ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
491
491
  ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
492
492
  ((version >= 11 && m.capability) ? 67108864 : 0) |
493
- ((version >= 11 && m.arguments) ? 134217728 : 0)
493
+ ((version >= 11 && m.arguments) ? 134217728 : 0) |
494
+ ((version >= 12 && m.enhance) ? 268435456 : 0)
494
495
 
495
496
  encoding10.preencode(state, m.type)
496
497
  c.uint.preencode(state, flags)
@@ -520,6 +521,7 @@ const encoding11 = {
520
521
  if (version >= 5 && m.grantedWriteDirs) encoding11_25.preencode(state, m.grantedWriteDirs)
521
522
  if (version >= 11 && m.capability) c.string.preencode(state, m.capability)
522
523
  if (version >= 11 && m.arguments) c.json.preencode(state, m.arguments)
524
+ if (version >= 12 && m.enhance) c.string.preencode(state, m.enhance)
523
525
  },
524
526
  encode(state, m) {
525
527
  const flags =
@@ -550,7 +552,8 @@ const encoding11 = {
550
552
  ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
551
553
  ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
552
554
  ((version >= 11 && m.capability) ? 67108864 : 0) |
553
- ((version >= 11 && m.arguments) ? 134217728 : 0)
555
+ ((version >= 11 && m.arguments) ? 134217728 : 0) |
556
+ ((version >= 12 && m.enhance) ? 268435456 : 0)
554
557
 
555
558
  encoding10.encode(state, m.type)
556
559
  c.uint.encode(state, flags)
@@ -580,6 +583,7 @@ const encoding11 = {
580
583
  if (version >= 5 && m.grantedWriteDirs) encoding11_25.encode(state, m.grantedWriteDirs)
581
584
  if (version >= 11 && m.capability) c.string.encode(state, m.capability)
582
585
  if (version >= 11 && m.arguments) c.json.encode(state, m.arguments)
586
+ if (version >= 12 && m.enhance) c.string.encode(state, m.enhance)
583
587
  },
584
588
  decode(state) {
585
589
  const r0 = encoding10.decode(state)
@@ -614,7 +618,8 @@ const encoding11 = {
614
618
  grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null,
615
619
  captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0),
616
620
  capability: (version >= 11 && (flags & 67108864) !== 0) ? c.string.decode(state) : null,
617
- arguments: (version >= 11 && (flags & 134217728) !== 0) ? c.json.decode(state) : null
621
+ arguments: (version >= 11 && (flags & 134217728) !== 0) ? c.json.decode(state) : null,
622
+ enhance: (version >= 12 && (flags & 268435456) !== 0) ? c.string.decode(state) : null
618
623
  }
619
624
  }
620
625
  }
@@ -1,12 +1,12 @@
1
1
  // This file is autogenerated by the hyperschema compiler
2
- // Schema Version: 11
2
+ // Schema Version: 12
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 = 11
9
+ const VERSION = 12
10
10
 
11
11
  // eslint-disable-next-line no-unused-vars
12
12
  let version = VERSION
@@ -490,7 +490,8 @@ const encoding11 = {
490
490
  ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
491
491
  ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
492
492
  ((version >= 11 && m.capability) ? 67108864 : 0) |
493
- ((version >= 11 && m.arguments) ? 134217728 : 0)
493
+ ((version >= 11 && m.arguments) ? 134217728 : 0) |
494
+ ((version >= 12 && m.enhance) ? 268435456 : 0)
494
495
 
495
496
  encoding10.preencode(state, m.type)
496
497
  c.uint.preencode(state, flags)
@@ -520,6 +521,7 @@ const encoding11 = {
520
521
  if (version >= 5 && m.grantedWriteDirs) encoding11_25.preencode(state, m.grantedWriteDirs)
521
522
  if (version >= 11 && m.capability) c.string.preencode(state, m.capability)
522
523
  if (version >= 11 && m.arguments) c.json.preencode(state, m.arguments)
524
+ if (version >= 12 && m.enhance) c.string.preencode(state, m.enhance)
523
525
  },
524
526
  encode(state, m) {
525
527
  const flags =
@@ -550,7 +552,8 @@ const encoding11 = {
550
552
  ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
551
553
  ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
552
554
  ((version >= 11 && m.capability) ? 67108864 : 0) |
553
- ((version >= 11 && m.arguments) ? 134217728 : 0)
555
+ ((version >= 11 && m.arguments) ? 134217728 : 0) |
556
+ ((version >= 12 && m.enhance) ? 268435456 : 0)
554
557
 
555
558
  encoding10.encode(state, m.type)
556
559
  c.uint.encode(state, flags)
@@ -580,6 +583,7 @@ const encoding11 = {
580
583
  if (version >= 5 && m.grantedWriteDirs) encoding11_25.encode(state, m.grantedWriteDirs)
581
584
  if (version >= 11 && m.capability) c.string.encode(state, m.capability)
582
585
  if (version >= 11 && m.arguments) c.json.encode(state, m.arguments)
586
+ if (version >= 12 && m.enhance) c.string.encode(state, m.enhance)
583
587
  },
584
588
  decode(state) {
585
589
  const r0 = encoding10.decode(state)
@@ -614,7 +618,8 @@ const encoding11 = {
614
618
  grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null,
615
619
  captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0),
616
620
  capability: (version >= 11 && (flags & 67108864) !== 0) ? c.string.decode(state) : null,
617
- arguments: (version >= 11 && (flags & 134217728) !== 0) ? c.json.decode(state) : null
621
+ arguments: (version >= 11 && (flags & 134217728) !== 0) ? c.json.decode(state) : null,
622
+ enhance: (version >= 12 && (flags & 268435456) !== 0) ? c.string.decode(state) : null
618
623
  }
619
624
  }
620
625
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": 11,
2
+ "version": 12,
3
3
  "schema": [
4
4
  {
5
5
  "name": "empty",
@@ -470,6 +470,11 @@
470
470
  "name": "arguments",
471
471
  "type": "json",
472
472
  "version": 11
473
+ },
474
+ {
475
+ "name": "enhance",
476
+ "type": "string",
477
+ "version": 12
473
478
  }
474
479
  ]
475
480
  },
@@ -1,5 +1,5 @@
1
1
  // This file is autogenerated by hyperschema-ts
2
- // Schema version: 11
2
+ // Schema version: 12
3
3
  // Do not edit manually.
4
4
 
5
5
  export interface HarnessEmpty {
@@ -90,6 +90,7 @@ export interface HarnessCompletionFrame {
90
90
  captureInferenceCalls?: boolean
91
91
  capability?: string | null
92
92
  arguments?: unknown | null
93
+ enhance?: string | null
93
94
  }
94
95
 
95
96
  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"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qvac/harness",
3
- "version": "0.2.12",
3
+ "version": "0.3.0",
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": {
@@ -540,6 +540,10 @@
540
540
  "types": "./dist-lib/lib/tools/skills/tool-grants.d.ts",
541
541
  "default": "./dist-lib/lib/tools/skills/tool-grants.js"
542
542
  },
543
+ "./lib/tools/translate.ts": {
544
+ "types": "./dist-lib/lib/tools/translate.d.ts",
545
+ "default": "./dist-lib/lib/tools/translate.js"
546
+ },
543
547
  "./lib/tools/url-guard.ts": {
544
548
  "types": "./dist-lib/lib/tools/url-guard.d.ts",
545
549
  "default": "./dist-lib/lib/tools/url-guard.js"
@@ -565,6 +569,7 @@
565
569
  "lint": "prettier . --check && lunte && tsc --noEmit",
566
570
  "build:bundle": "node scripts/build-bundle.mjs",
567
571
  "skill-eval": "bare examples/skill-eval/run.ts",
572
+ "translate-eval": "bare examples/translate-eval/run.ts",
568
573
  "prepack": "node scripts/vendor-python-wheels.mjs && node scripts/build-lib.mjs && node scripts/build-bundle.mjs --minify",
569
574
  "vendor:wheels": "node scripts/vendor-python-wheels.mjs",
570
575
  "build:lib": "node scripts/build-lib.mjs",