@qvac/harness 0.8.5 → 0.8.7
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/CHANGELOG.md +1278 -472
- package/README.md +49 -0
- package/dist-lib/index.d.ts +42 -2
- package/dist-lib/index.js +447 -58
- package/dist-lib/lib/audio-transcode-bare.d.ts +1 -1
- package/dist-lib/lib/audio-transcode-bare.js +22 -25
- package/dist-lib/lib/audio-transcode-node.d.ts +1 -1
- package/dist-lib/lib/audio-transcode-node.js +1 -3
- package/dist-lib/lib/capabilities/audio-resample.d.ts +1 -1
- package/dist-lib/lib/capabilities/audio-resample.js +7 -8
- package/dist-lib/lib/capabilities/completion.d.ts +6 -3
- package/dist-lib/lib/capabilities/completion.js +96 -49
- package/dist-lib/lib/capabilities/download.d.ts +3 -1
- package/dist-lib/lib/capabilities/download.js +1 -1
- package/dist-lib/lib/capabilities/preview-model-source.d.ts +1 -0
- package/dist-lib/lib/capabilities/preview-model-source.js +1 -0
- package/dist-lib/lib/capabilities/tool-selection.d.ts +1 -3
- package/dist-lib/lib/capabilities/tool-selection.js +2 -4
- package/dist-lib/lib/capabilities/tool-turns.d.ts +0 -1
- package/dist-lib/lib/capabilities/tool-turns.js +0 -6
- package/dist-lib/lib/capabilities/usage-breakdown.js +4 -1
- package/dist-lib/lib/capabilities/voice.d.ts +5 -1
- package/dist-lib/lib/capabilities/voice.js +94 -26
- package/dist-lib/lib/connect.d.ts +4 -1
- package/dist-lib/lib/connect.js +16 -1
- package/dist-lib/lib/contract-types.d.ts +12 -0
- package/dist-lib/lib/helpers/tool-call-markup.d.ts +1 -0
- package/dist-lib/lib/helpers/tool-call-markup.js +3 -0
- package/dist-lib/lib/models/context-choice.d.ts +15 -0
- package/dist-lib/lib/models/context-choice.js +55 -0
- package/dist-lib/lib/models/download-gate.d.ts +20 -0
- package/dist-lib/lib/models/download-gate.js +73 -0
- package/dist-lib/lib/models/memory-cap.d.ts +13 -0
- package/dist-lib/lib/models/memory-cap.js +21 -0
- package/dist-lib/lib/models/model-catalog-constants.d.ts +3 -1
- package/dist-lib/lib/models/model-catalog-constants.js +9 -1
- package/dist-lib/lib/models/model-catalog.d.ts +6 -2
- package/dist-lib/lib/models/model-catalog.js +35 -3
- package/dist-lib/lib/models/model-handle.d.ts +8 -1
- package/dist-lib/lib/models/model-handle.js +20 -2
- package/dist-lib/lib/models/model-list.d.ts +8 -1
- package/dist-lib/lib/models/model-list.js +23 -0
- package/dist-lib/lib/models/model-pool.d.ts +35 -5
- package/dist-lib/lib/models/model-pool.js +97 -32
- package/dist-lib/lib/models/sdk-faults.d.ts +1 -0
- package/dist-lib/lib/models/sdk-faults.js +6 -0
- package/dist-lib/lib/office/engine/pptx/picture-area.d.ts +23 -0
- package/dist-lib/lib/office/engine/pptx/picture-area.js +84 -0
- package/dist-lib/lib/office/engine/pptx/presentation.d.ts +2 -0
- package/dist-lib/lib/office/engine/pptx/presentation.js +55 -17
- package/dist-lib/lib/office/engine/pptx/types.d.ts +1 -0
- package/dist-lib/lib/office/engine/xlsx/workbook.d.ts +1 -0
- package/dist-lib/lib/office/engine/xlsx/workbook.js +34 -3
- package/dist-lib/lib/serve.js +23 -3
- package/dist-lib/lib/spawn.js +4 -10
- package/dist-lib/lib/tools/exec.d.ts +4 -1
- package/dist-lib/lib/tools/exec.js +55 -11
- package/dist-lib/lib/tools/generate-image.d.ts +4 -2
- package/dist-lib/lib/tools/generate-image.js +5 -2
- package/dist-lib/lib/tools/generate-music.d.ts +4 -2
- package/dist-lib/lib/tools/generate-music.js +5 -2
- package/dist-lib/lib/tools/office/ops.js +1 -1
- package/dist-lib/lib/tools/office.js +29 -6
- package/dist-lib/lib/tools/skills/catalog.d.ts +1 -0
- package/dist-lib/lib/tools/skills/catalog.js +2 -0
- package/dist-lib/lib/tools/skills/cli-schema-check.d.ts +1 -0
- package/dist-lib/lib/tools/skills/cli-schema-check.js +3 -0
- package/dist-lib/lib/tools/skills/cli-schema-load.js +10 -0
- package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +2 -0
- package/dist-lib/lib/tools/skills/cli-schema.js +6 -3
- package/dist-lib/lib/tools/skills/frontmatter-parser.d.ts +1 -0
- package/dist-lib/lib/tools/skills/manifest-parse.d.ts +1 -0
- package/dist-lib/lib/tools/skills/manifest-parse.js +12 -0
- package/dist-lib/lib/tools/skills/mention.d.ts +0 -1
- package/dist-lib/lib/tools/skills/mention.js +0 -3
- package/dist-lib/lib/tools/translate.d.ts +3 -1
- package/dist-lib/lib/tools/translate.js +6 -1
- package/dist-lib/schema/harness.js +43 -4
- package/dist-lib/spec/bind.js +9 -0
- package/dist-lib/spec/calls.js +3 -0
- package/dist-lib/spec/hrpc/hrpc.json +39 -0
- package/dist-lib/spec/hrpc/index.js +39 -3
- package/dist-lib/spec/hrpc/messages.js +101 -13
- package/dist-lib/spec/hyperschema/index.js +101 -13
- package/dist-lib/spec/hyperschema/schema.json +62 -1
- package/dist-lib/spec/hyperschema/types.d.ts +20 -2
- package/package.json +8 -10
- package/worker/harness-sidecar.mjs +2 -1
|
@@ -7,7 +7,7 @@ export const PPTX_OPS = {
|
|
|
7
7
|
setText: { slots: [['slide', 'shape'], 'text'] },
|
|
8
8
|
setCellText: { slots: [['slide', 'shape', 'row', 'column'], 'text'] },
|
|
9
9
|
setStyle: { slots: [['slide', 'shape'], 'style', ['paragraph']] },
|
|
10
|
-
addSlide: { slots: [['like', 'layout', 'at', 'title', 'body']] },
|
|
10
|
+
addSlide: { slots: [['like', 'layout', 'at', 'title', 'body', 'image']] },
|
|
11
11
|
addPicture: { slots: ['slide', 'image', [...BOX, 'name', 'description']], inches: true },
|
|
12
12
|
addTextBox: { slots: ['slide', [...BOX, 'text', 'style', 'fill', 'name']], inches: true },
|
|
13
13
|
addTable: { slots: ['slide', [...BOX, 'rows', 'header', 'name']], inches: true },
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import b4a from 'b4a';
|
|
2
2
|
import { errorMessage, isRecord } from '../guards.js';
|
|
3
|
-
import { docx, pptx, units, xlsx } from '../office/engine/index.js';
|
|
3
|
+
import { DocsError, docx, pptx, units, xlsx } from '../office/engine/index.js';
|
|
4
4
|
import { stageInputs } from './exec/adapters/python/attachments.js';
|
|
5
5
|
import { checkOutputBytes, RUN_OUTPUT_BUDGET_BYTES } from './exec/adapters/python/output-policy.js';
|
|
6
6
|
import { DOCX_OPS, opArguments, opKeys, PPTX_OPS, withAliases, XLSX_OPS } from './office/ops.js';
|
|
7
7
|
const READ_CELL_LIMIT = 10_000;
|
|
8
8
|
const attachedThisTurn = new WeakMap();
|
|
9
9
|
const FIRST_SHEET = /^sheet ?1$/i;
|
|
10
|
+
const NEW_DECK_HINT = '; a new deck has only the slides its addSlide ops make, slides count from 0, and an op on a slide goes after the addSlide that makes it';
|
|
10
11
|
const SHAPE_ROLES = new Set(['title', 'subtitle', 'body']);
|
|
11
12
|
const HOISTED = ['attachmentId', 'output'];
|
|
12
13
|
const WHERE_IDS_ARE = 'copy the id from the [Attached file "…" — attachmentId: …] line or an earlier tool result';
|
|
@@ -25,6 +26,9 @@ export function shapeFor(deck, op) {
|
|
|
25
26
|
const found = deck.read()[slide]?.shapes.find((entry) => entry.name.toLowerCase() === wanted);
|
|
26
27
|
return found && found.id !== null ? { ...op, shape: found.id } : op;
|
|
27
28
|
}
|
|
29
|
+
function newDeckHint(err, created) {
|
|
30
|
+
return created && err instanceof DocsError && err.code === 'SLIDE_NOT_FOUND' ? NEW_DECK_HINT : '';
|
|
31
|
+
}
|
|
28
32
|
export function sheetFor(book, op, created) {
|
|
29
33
|
if (typeof op.sheet !== 'string')
|
|
30
34
|
return op;
|
|
@@ -70,7 +74,8 @@ const PPTX_FORMAT = {
|
|
|
70
74
|
create: (options) => pptx.create(options),
|
|
71
75
|
read: (deck) => deck.read(),
|
|
72
76
|
count: (deck) => ({ slides: deck.slideCount }),
|
|
73
|
-
prepare: (deck, op) => shapeFor(deck, op)
|
|
77
|
+
prepare: (deck, op) => shapeFor(deck, op),
|
|
78
|
+
hint: newDeckHint
|
|
74
79
|
};
|
|
75
80
|
const DOCX_FORMAT = {
|
|
76
81
|
name: 'docx',
|
|
@@ -141,7 +146,11 @@ function parseOp(format, op, i) {
|
|
|
141
146
|
return `ops[${i}] sheets lists the sheets and takes no arguments; to add a sheet use { op: "addSheet", name }`;
|
|
142
147
|
}
|
|
143
148
|
const takes = keys.length ? `it takes ${keys.join(', ')}` : 'it takes no arguments';
|
|
144
|
-
|
|
149
|
+
const nested = unknown.filter((key) => format.ops[key]);
|
|
150
|
+
const apart = nested.length
|
|
151
|
+
? `; ${nested.map((name) => `{ "op": "${name}", ... }`).join(' and ')} goes in ops as its own entry, next to this one, not inside it`
|
|
152
|
+
: '';
|
|
153
|
+
return `ops[${i}] ${op.op} does not take ${unknown.join(', ')}; ${takes}${apart}`;
|
|
145
154
|
}
|
|
146
155
|
function parseOps(format, ops) {
|
|
147
156
|
if (!Array.isArray(ops)) {
|
|
@@ -252,8 +261,11 @@ async function imageInput(op, i, ctx) {
|
|
|
252
261
|
}
|
|
253
262
|
return { attachmentId: id ? await imageId(ctx, id) : undefined, path: `image-${i}.png` };
|
|
254
263
|
}
|
|
264
|
+
function takesImage(op) {
|
|
265
|
+
return op.spec.slots.includes('image') || op.args.image !== undefined;
|
|
266
|
+
}
|
|
255
267
|
async function stagedImages(request, ctx) {
|
|
256
|
-
const wanted = request.ops.flatMap((op, i) => (
|
|
268
|
+
const wanted = request.ops.flatMap((op, i) => (takesImage(op) ? [i] : []));
|
|
257
269
|
const images = new Map();
|
|
258
270
|
if (!wanted.length) {
|
|
259
271
|
return images;
|
|
@@ -358,7 +370,8 @@ function runOps({ format, document, request, images }) {
|
|
|
358
370
|
results.push(runOp(document, op, input));
|
|
359
371
|
}
|
|
360
372
|
catch (err) {
|
|
361
|
-
|
|
373
|
+
const hint = format.hint?.(err, created) ?? '';
|
|
374
|
+
return { error: `ops[${i}] ${op.name}: ${errorMessage(err)}${hint}` };
|
|
362
375
|
}
|
|
363
376
|
}
|
|
364
377
|
return results;
|
|
@@ -452,6 +465,7 @@ async function execute(format, args, ctx) {
|
|
|
452
465
|
const renamed = output !== request.output
|
|
453
466
|
? `Saved as ${output}, so the attached ${fileName} keeps its own name. `
|
|
454
467
|
: '';
|
|
468
|
+
const unplaced = !!ctx.turnImages?.length && !images.size;
|
|
455
469
|
return {
|
|
456
470
|
results,
|
|
457
471
|
attachments: [attachment],
|
|
@@ -459,9 +473,18 @@ async function execute(format, args, ctx) {
|
|
|
459
473
|
reply: `${attachment.fileName} — ${countLine(counts)}`,
|
|
460
474
|
next: renamed +
|
|
461
475
|
`Done: ${attachment.fileName} ${repeated ? 'was already' : 'is'} attached to the chat and shown to the user. ` +
|
|
462
|
-
|
|
476
|
+
afterSave(format, attachment.attachmentId, unplaced)
|
|
463
477
|
};
|
|
464
478
|
}
|
|
479
|
+
function afterSave(format, attachmentId, unplaced) {
|
|
480
|
+
const reply = 'Your answer is the reply value alone, word for word.';
|
|
481
|
+
if (!unplaced) {
|
|
482
|
+
return `Do not call ${format.name} again for it. ${reply}`;
|
|
483
|
+
}
|
|
484
|
+
return (`The image the user attached to their message is not in it. If they asked for that image in the ${format.noun}, ` +
|
|
485
|
+
`call ${format.name} once more with attachmentId "${attachmentId}" and one op that adds it with "image": {}. ` +
|
|
486
|
+
`Otherwise: ${reply}`);
|
|
487
|
+
}
|
|
465
488
|
function createOfficeTool(format) {
|
|
466
489
|
return {
|
|
467
490
|
name: format.name,
|
|
@@ -82,6 +82,7 @@ function mergeOverlay(base, overlay) {
|
|
|
82
82
|
credentials: base.credentials,
|
|
83
83
|
allowList: base.allowList,
|
|
84
84
|
platform: base.platform,
|
|
85
|
+
env: base.env,
|
|
85
86
|
operations: base.operations,
|
|
86
87
|
mcpReads: base.mcpReads
|
|
87
88
|
};
|
|
@@ -166,6 +167,7 @@ async function loadEntry(skillsDir, dir, origin) {
|
|
|
166
167
|
requires: meta.requires,
|
|
167
168
|
install: meta.install,
|
|
168
169
|
setup: meta.setup,
|
|
170
|
+
env: origin === 'overlay' ? undefined : meta.env,
|
|
169
171
|
cliValidator: cli ? buildCliValidator(cli) : undefined,
|
|
170
172
|
stub: meta.stub,
|
|
171
173
|
minCapabilityProfile: meta.minCapabilityProfile || undefined,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { JsonSchema } from './cli-schema-types.ts';
|
|
2
2
|
export declare function buildSchemaAnnotation(schema: JsonSchema): (argv: readonly string[]) => 'read' | 'write';
|
|
3
|
+
export declare function buildSchemaOutputCap(schema: JsonSchema): (argv: readonly string[]) => number | undefined;
|
|
3
4
|
export declare function buildSchemaCheck(schema: JsonSchema, resourcePaths: readonly string[] | undefined): (argv: readonly string[]) => string | null;
|
|
@@ -13,6 +13,9 @@ export function buildSchemaAnnotation(schema) {
|
|
|
13
13
|
return walkCommands(argv, schema).node['x-effect'] === 'read' ? 'read' : 'write';
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
export function buildSchemaOutputCap(schema) {
|
|
17
|
+
return (argv) => walkCommands(argv, schema).node['x-max-output-chars'];
|
|
18
|
+
}
|
|
16
19
|
function basename(p) {
|
|
17
20
|
return p.slice(Math.max(p.lastIndexOf('/'), p.lastIndexOf('\\')) + 1);
|
|
18
21
|
}
|
|
@@ -28,6 +28,9 @@ export async function resolveCliSchema(skillDir, bin, readFile = (p) => fs.promi
|
|
|
28
28
|
if (!resourceEffectsValid(schema)) {
|
|
29
29
|
return { bin, schemaFile: CLI_SCHEMA_FILENAME };
|
|
30
30
|
}
|
|
31
|
+
if (!outputCapsValid(schema)) {
|
|
32
|
+
return { bin, schemaFile: CLI_SCHEMA_FILENAME };
|
|
33
|
+
}
|
|
31
34
|
const resourcePaths = resolveResourcePaths(skillDir, schema);
|
|
32
35
|
return {
|
|
33
36
|
bin,
|
|
@@ -63,6 +66,13 @@ function resourceEffectsValid(schema) {
|
|
|
63
66
|
const files = new Set(schema['x-resource-files'] ?? []);
|
|
64
67
|
return Object.entries(effects).every(([file, effect]) => effect === 'read' && files.has(file));
|
|
65
68
|
}
|
|
69
|
+
function outputCapsValid(schema) {
|
|
70
|
+
const cap = schema['x-max-output-chars'];
|
|
71
|
+
if (cap !== undefined && !(Number.isInteger(cap) && cap > 0)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return Object.values(schema.properties ?? {}).every(outputCapsValid);
|
|
75
|
+
}
|
|
66
76
|
function resolveResourcePaths(skillDir, schema) {
|
|
67
77
|
const resources = schema['x-resource-files'] ?? [];
|
|
68
78
|
return resources
|
|
@@ -13,6 +13,7 @@ export interface JsonSchema {
|
|
|
13
13
|
readonly 'x-resource-files'?: readonly string[];
|
|
14
14
|
readonly 'x-resource-effects'?: Readonly<Record<string, string>>;
|
|
15
15
|
readonly 'x-effect'?: string;
|
|
16
|
+
readonly 'x-max-output-chars'?: number;
|
|
16
17
|
readonly [key: string]: unknown;
|
|
17
18
|
}
|
|
18
19
|
export interface SkillCli {
|
|
@@ -27,4 +28,5 @@ export interface CliValidator {
|
|
|
27
28
|
readonly check: (argv: readonly string[]) => string | null;
|
|
28
29
|
readonly annotation: (argv: readonly string[]) => 'read' | 'write';
|
|
29
30
|
readonly effect: (argv: readonly string[]) => 'read' | 'write';
|
|
31
|
+
readonly outputCap: (argv: readonly string[]) => number | undefined;
|
|
30
32
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { CLI_SCHEMA_FILENAME } from './cli-schema-types.js';
|
|
2
2
|
export { argvToObject } from './cli-argv.js';
|
|
3
3
|
export { loadSkillCli, resolveCliSchema, execBinFromTools } from './cli-schema-load.js';
|
|
4
|
-
import { buildSchemaAnnotation, buildSchemaCheck } from './cli-schema-check.js';
|
|
4
|
+
import { buildSchemaAnnotation, buildSchemaCheck, buildSchemaOutputCap } from './cli-schema-check.js';
|
|
5
5
|
export function buildCliValidator(def) {
|
|
6
6
|
const bin = def.bin.toLowerCase();
|
|
7
7
|
if (!def.schema) {
|
|
@@ -9,16 +9,19 @@ export function buildCliValidator(def) {
|
|
|
9
9
|
bin,
|
|
10
10
|
check: () => 'skill cli schema is missing',
|
|
11
11
|
annotation: () => 'write',
|
|
12
|
-
effect: () => 'write'
|
|
12
|
+
effect: () => 'write',
|
|
13
|
+
outputCap: () => undefined
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
const check = buildSchemaCheck(def.schema, def.resourcePaths);
|
|
16
17
|
const annotation = buildSchemaAnnotation(def.schema);
|
|
18
|
+
const outputCap = buildSchemaOutputCap(def.schema);
|
|
17
19
|
return {
|
|
18
20
|
bin,
|
|
19
21
|
check,
|
|
20
22
|
annotation,
|
|
21
|
-
effect: (argv) => (check(argv) === null ? annotation(argv) : 'write')
|
|
23
|
+
effect: (argv) => (check(argv) === null ? annotation(argv) : 'write'),
|
|
24
|
+
outputCap: (argv) => (check(argv) === null ? outputCap(argv) : undefined)
|
|
22
25
|
};
|
|
23
26
|
}
|
|
24
27
|
export function checkCliOps(argv, compiled) {
|
|
@@ -12,11 +12,23 @@ export function parseManifestBlock(block, key = 'metadata') {
|
|
|
12
12
|
requires,
|
|
13
13
|
install,
|
|
14
14
|
setup,
|
|
15
|
+
env: readEnv(oc.env),
|
|
15
16
|
stub: typeof oc.stub === 'boolean' ? oc.stub : undefined,
|
|
16
17
|
minCapabilityProfile: typeof oc.minCapabilityProfile === 'string' ? oc.minCapabilityProfile : undefined,
|
|
17
18
|
emoji: typeof oc.emoji === 'string' ? oc.emoji : undefined
|
|
18
19
|
};
|
|
19
20
|
}
|
|
21
|
+
function readEnv(v) {
|
|
22
|
+
if (!isObj(v))
|
|
23
|
+
return undefined;
|
|
24
|
+
const env = {};
|
|
25
|
+
for (const [name, value] of Object.entries(v)) {
|
|
26
|
+
if (typeof value === 'string' && /^[A-Z_][A-Z0-9_]*$/.test(name)) {
|
|
27
|
+
env[name] = value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return Object.keys(env).length > 0 ? env : undefined;
|
|
31
|
+
}
|
|
20
32
|
function extractJsonBlock(block, key) {
|
|
21
33
|
const at = block.indexOf(`${key}:`);
|
|
22
34
|
if (at === -1) {
|
|
@@ -3,4 +3,3 @@ import { skillMentionName } from './mention-name.ts';
|
|
|
3
3
|
export { skillMentionName };
|
|
4
4
|
export declare function resolveSkillMention(text: string, catalog: readonly SkillCatalogEntry[]): SkillCatalogEntry | null;
|
|
5
5
|
export declare function resolveImplicitSkill(text: string, activeSkills: readonly SkillCatalogEntry[]): SkillCatalogEntry | null;
|
|
6
|
-
export declare function skillPreloadMessage(content: string, name: string, body: string): string;
|
|
@@ -3,6 +3,7 @@ import type { ToolDefinition } from '../capabilities/completion.ts';
|
|
|
3
3
|
import type { ModelSrc } from '../models/context.ts';
|
|
4
4
|
import { type NmtPlan } from '../models/nmt-catalog.ts';
|
|
5
5
|
import { type LoadTracker, type TrackedLoad } from '../models/model-pool.ts';
|
|
6
|
+
import type { HoldFn } from '../models/download-gate.ts';
|
|
6
7
|
import { type ModelRegistrySdk } from '../models/model-source.ts';
|
|
7
8
|
interface BergamotConfig {
|
|
8
9
|
engine: 'Bergamot';
|
|
@@ -42,6 +43,7 @@ export interface TranslationRuntimeOptions {
|
|
|
42
43
|
loadSdk: () => Promise<TranslationSdk>;
|
|
43
44
|
loads?: LoadTracker;
|
|
44
45
|
onProgress?: (model: string, progress: Record<string, unknown>) => void;
|
|
46
|
+
hold?: HoldFn;
|
|
45
47
|
stallMs?: number;
|
|
46
48
|
}
|
|
47
49
|
export interface TranslationRuntime {
|
|
@@ -53,7 +55,7 @@ export interface TranslationRuntime {
|
|
|
53
55
|
enter: (signal?: BareAbortSignal) => Promise<void>;
|
|
54
56
|
exit: () => void;
|
|
55
57
|
}
|
|
56
|
-
export declare function createTranslationRuntime({ loadSdk, loads, onProgress, stallMs }: TranslationRuntimeOptions): TranslationRuntime;
|
|
58
|
+
export declare function createTranslationRuntime({ loadSdk, loads, onProgress, hold, stallMs }: TranslationRuntimeOptions): TranslationRuntime;
|
|
57
59
|
export type SlmTranslateFn = (model: string, params: {
|
|
58
60
|
text: string;
|
|
59
61
|
from: string;
|
|
@@ -26,7 +26,7 @@ function bergamotConfig(plan) {
|
|
|
26
26
|
}
|
|
27
27
|
return config;
|
|
28
28
|
}
|
|
29
|
-
export function createTranslationRuntime({ loadSdk, loads = createLoadTracker(), onProgress, stallMs = TRANSLATION_LOAD_STALL_MS }) {
|
|
29
|
+
export function createTranslationRuntime({ loadSdk, loads = createLoadTracker(), onProgress, hold, stallMs = TRANSLATION_LOAD_STALL_MS }) {
|
|
30
30
|
let loading = null;
|
|
31
31
|
let residentFingerprint = null;
|
|
32
32
|
const lock = new ScopeLock();
|
|
@@ -95,6 +95,11 @@ export function createTranslationRuntime({ loadSdk, loads = createLoadTracker(),
|
|
|
95
95
|
loadSdk,
|
|
96
96
|
ensureLoaded: async (sdk, plan, signal) => {
|
|
97
97
|
const fingerprint = fingerprintOf(plan);
|
|
98
|
+
if (hold && !(loading && residentFingerprint === fingerprint)) {
|
|
99
|
+
for (const model of plan.pivot ? [plan.model, plan.pivot] : [plan.model]) {
|
|
100
|
+
await hold(model, 'nmt', signal);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
98
103
|
await lock.lock();
|
|
99
104
|
try {
|
|
100
105
|
if (loading && residentFingerprint !== fingerprint) {
|
|
@@ -113,7 +113,8 @@ export function registerHarnessTypes(ns) {
|
|
|
113
113
|
{ name: 'captureInferenceCalls', type: 'bool' },
|
|
114
114
|
{ name: 'capability', type: 'string' },
|
|
115
115
|
{ name: 'arguments', type: 'json' },
|
|
116
|
-
{ name: 'enhance', type: 'string' }
|
|
116
|
+
{ name: 'enhance', type: 'string' },
|
|
117
|
+
{ name: 'session', type: 'string' }
|
|
117
118
|
]
|
|
118
119
|
});
|
|
119
120
|
ns.register({
|
|
@@ -175,7 +176,16 @@ export function registerHarnessTypes(ns) {
|
|
|
175
176
|
});
|
|
176
177
|
ns.register({
|
|
177
178
|
name: 'model-event-status',
|
|
178
|
-
enum: [
|
|
179
|
+
enum: [
|
|
180
|
+
'loading',
|
|
181
|
+
'downloading',
|
|
182
|
+
'ready',
|
|
183
|
+
'error',
|
|
184
|
+
'unloading',
|
|
185
|
+
'unloaded',
|
|
186
|
+
'downloaded',
|
|
187
|
+
'held'
|
|
188
|
+
],
|
|
179
189
|
strings: true
|
|
180
190
|
});
|
|
181
191
|
ns.register({
|
|
@@ -195,7 +205,8 @@ export function registerHarnessTypes(ns) {
|
|
|
195
205
|
{ name: 'loaded', type: '@harness/loaded-model', array: true },
|
|
196
206
|
{ name: 'catalogChanged', type: 'bool' },
|
|
197
207
|
{ name: 'downloaded', type: 'uint' },
|
|
198
|
-
{ name: 'total', type: 'uint' }
|
|
208
|
+
{ name: 'total', type: 'uint' },
|
|
209
|
+
{ name: 'addon', type: 'string' }
|
|
199
210
|
]
|
|
200
211
|
});
|
|
201
212
|
ns.register({
|
|
@@ -340,7 +351,8 @@ export function registerHarnessTypes(ns) {
|
|
|
340
351
|
{ name: 'expectedSize', type: 'uint', required: true },
|
|
341
352
|
{ name: 'actualSize', type: 'uint' },
|
|
342
353
|
{ name: 'label', type: 'string' },
|
|
343
|
-
{ name: 'isLoading', type: 'bool' }
|
|
354
|
+
{ name: 'isLoading', type: 'bool' },
|
|
355
|
+
{ name: 'memoryBytes', type: 'uint' }
|
|
344
356
|
]
|
|
345
357
|
});
|
|
346
358
|
ns.register({
|
|
@@ -738,6 +750,18 @@ export function registerHarnessTypes(ns) {
|
|
|
738
750
|
name: 'unload-model-response',
|
|
739
751
|
fields: [{ name: 'unloaded', type: 'bool', required: true }]
|
|
740
752
|
});
|
|
753
|
+
ns.register({
|
|
754
|
+
name: 'set-model-memory-cap-request',
|
|
755
|
+
fields: [{ name: 'percent', type: 'uint', required: true }]
|
|
756
|
+
});
|
|
757
|
+
ns.register({
|
|
758
|
+
name: 'memory-usage',
|
|
759
|
+
fields: [{ name: 'usedBytes', type: 'uint', required: true }]
|
|
760
|
+
});
|
|
761
|
+
ns.register({
|
|
762
|
+
name: 'set-downloads-allowed-request',
|
|
763
|
+
fields: [{ name: 'allowed', type: 'bool', required: true }]
|
|
764
|
+
});
|
|
741
765
|
}
|
|
742
766
|
export function registerHarnessApi(api) {
|
|
743
767
|
api.register({
|
|
@@ -905,4 +929,19 @@ export function registerHarnessApi(api) {
|
|
|
905
929
|
request: { name: '@harness/unload-model-request', stream: false },
|
|
906
930
|
response: { name: '@harness/unload-model-response', stream: false }
|
|
907
931
|
});
|
|
932
|
+
api.register({
|
|
933
|
+
name: 'set-model-memory-cap',
|
|
934
|
+
request: { name: '@harness/set-model-memory-cap-request', stream: false },
|
|
935
|
+
response: { name: '@harness/ok-response', stream: false }
|
|
936
|
+
});
|
|
937
|
+
api.register({
|
|
938
|
+
name: 'memory-usage',
|
|
939
|
+
request: { name: '@harness/empty', stream: false },
|
|
940
|
+
response: { name: '@harness/memory-usage', stream: false }
|
|
941
|
+
});
|
|
942
|
+
api.register({
|
|
943
|
+
name: 'set-downloads-allowed',
|
|
944
|
+
request: { name: '@harness/set-downloads-allowed-request', stream: false },
|
|
945
|
+
response: { name: '@harness/ok-response', stream: false }
|
|
946
|
+
});
|
|
908
947
|
}
|
package/dist-lib/spec/bind.js
CHANGED
|
@@ -139,4 +139,13 @@ export function bindApi(rpc, api) {
|
|
|
139
139
|
if (api.unloadModel) {
|
|
140
140
|
rpc.onUnloadModel((req) => api.unloadModel(req));
|
|
141
141
|
}
|
|
142
|
+
if (api.setModelMemoryCap) {
|
|
143
|
+
rpc.onSetModelMemoryCap((req) => api.setModelMemoryCap(req));
|
|
144
|
+
}
|
|
145
|
+
if (api.memoryUsage) {
|
|
146
|
+
rpc.onMemoryUsage((req) => api.memoryUsage(req));
|
|
147
|
+
}
|
|
148
|
+
if (api.setDownloadsAllowed) {
|
|
149
|
+
rpc.onSetDownloadsAllowed((req) => api.setDownloadsAllowed(req));
|
|
150
|
+
}
|
|
142
151
|
}
|
package/dist-lib/spec/calls.js
CHANGED
|
@@ -43,5 +43,8 @@ export function harnessClient(rpc) {
|
|
|
43
43
|
setModelIdleTimeout: (input) => rpc.setModelIdleTimeout(input),
|
|
44
44
|
loadModel: (input) => rpc.loadModel(input),
|
|
45
45
|
unloadModel: (input) => rpc.unloadModel(input),
|
|
46
|
+
setModelMemoryCap: (input) => rpc.setModelMemoryCap(input),
|
|
47
|
+
memoryUsage: (input) => rpc.memoryUsage(input),
|
|
48
|
+
setDownloadsAllowed: (input) => rpc.setDownloadsAllowed(input),
|
|
46
49
|
};
|
|
47
50
|
}
|
|
@@ -429,6 +429,45 @@
|
|
|
429
429
|
"stream": false
|
|
430
430
|
},
|
|
431
431
|
"version": 1
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"id": 33,
|
|
435
|
+
"name": "@harness/set-model-memory-cap",
|
|
436
|
+
"request": {
|
|
437
|
+
"name": "@harness/set-model-memory-cap-request",
|
|
438
|
+
"stream": false
|
|
439
|
+
},
|
|
440
|
+
"response": {
|
|
441
|
+
"name": "@harness/ok-response",
|
|
442
|
+
"stream": false
|
|
443
|
+
},
|
|
444
|
+
"version": 1
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"id": 34,
|
|
448
|
+
"name": "@harness/memory-usage",
|
|
449
|
+
"request": {
|
|
450
|
+
"name": "@harness/empty",
|
|
451
|
+
"stream": false
|
|
452
|
+
},
|
|
453
|
+
"response": {
|
|
454
|
+
"name": "@harness/memory-usage",
|
|
455
|
+
"stream": false
|
|
456
|
+
},
|
|
457
|
+
"version": 1
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"id": 35,
|
|
461
|
+
"name": "@harness/set-downloads-allowed",
|
|
462
|
+
"request": {
|
|
463
|
+
"name": "@harness/set-downloads-allowed-request",
|
|
464
|
+
"stream": false
|
|
465
|
+
},
|
|
466
|
+
"response": {
|
|
467
|
+
"name": "@harness/ok-response",
|
|
468
|
+
"stream": false
|
|
469
|
+
},
|
|
470
|
+
"version": 1
|
|
432
471
|
}
|
|
433
472
|
]
|
|
434
473
|
}
|
|
@@ -71,7 +71,13 @@ const methods = new Map([
|
|
|
71
71
|
['@harness/load-model', 31],
|
|
72
72
|
[31, '@harness/load-model'],
|
|
73
73
|
['@harness/unload-model', 32],
|
|
74
|
-
[32, '@harness/unload-model']
|
|
74
|
+
[32, '@harness/unload-model'],
|
|
75
|
+
['@harness/set-model-memory-cap', 33],
|
|
76
|
+
[33, '@harness/set-model-memory-cap'],
|
|
77
|
+
['@harness/memory-usage', 34],
|
|
78
|
+
[34, '@harness/memory-usage'],
|
|
79
|
+
['@harness/set-downloads-allowed', 35],
|
|
80
|
+
[35, '@harness/set-downloads-allowed']
|
|
75
81
|
])
|
|
76
82
|
|
|
77
83
|
class HRPC {
|
|
@@ -111,7 +117,10 @@ class HRPC {
|
|
|
111
117
|
['@harness/preview-model-source', getEncoding('@harness/preview-model-source-request')],
|
|
112
118
|
['@harness/set-model-idle-timeout', getEncoding('@harness/set-model-idle-timeout-request')],
|
|
113
119
|
['@harness/load-model', getEncoding('@harness/warm-model-request')],
|
|
114
|
-
['@harness/unload-model', getEncoding('@harness/unload-model-request')]
|
|
120
|
+
['@harness/unload-model', getEncoding('@harness/unload-model-request')],
|
|
121
|
+
['@harness/set-model-memory-cap', getEncoding('@harness/set-model-memory-cap-request')],
|
|
122
|
+
['@harness/memory-usage', getEncoding('@harness/empty')],
|
|
123
|
+
['@harness/set-downloads-allowed', getEncoding('@harness/set-downloads-allowed-request')]
|
|
115
124
|
])
|
|
116
125
|
this._responseEncodings = new Map([
|
|
117
126
|
['@harness/completion', getEncoding('@harness/completion-event')],
|
|
@@ -146,7 +155,10 @@ class HRPC {
|
|
|
146
155
|
['@harness/preview-model-source', getEncoding('@harness/preview-model-source-response')],
|
|
147
156
|
['@harness/set-model-idle-timeout', getEncoding('@harness/ok-response')],
|
|
148
157
|
['@harness/load-model', getEncoding('@harness/load-model-response')],
|
|
149
|
-
['@harness/unload-model', getEncoding('@harness/unload-model-response')]
|
|
158
|
+
['@harness/unload-model', getEncoding('@harness/unload-model-response')],
|
|
159
|
+
['@harness/set-model-memory-cap', getEncoding('@harness/ok-response')],
|
|
160
|
+
['@harness/memory-usage', getEncoding('@harness/memory-usage')],
|
|
161
|
+
['@harness/set-downloads-allowed', getEncoding('@harness/ok-response')]
|
|
150
162
|
])
|
|
151
163
|
this._rpc = new RPC(stream, async (req) => {
|
|
152
164
|
const command = methods.get(req.command)
|
|
@@ -376,6 +388,18 @@ class HRPC {
|
|
|
376
388
|
return this._call('@harness/unload-model', args)
|
|
377
389
|
}
|
|
378
390
|
|
|
391
|
+
async setModelMemoryCap(args) {
|
|
392
|
+
return this._call('@harness/set-model-memory-cap', args)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
async memoryUsage(args) {
|
|
396
|
+
return this._call('@harness/memory-usage', args)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async setDownloadsAllowed(args) {
|
|
400
|
+
return this._call('@harness/set-downloads-allowed', args)
|
|
401
|
+
}
|
|
402
|
+
|
|
379
403
|
onCompletion(responseFn) {
|
|
380
404
|
this._handlers['@harness/completion'] = responseFn
|
|
381
405
|
}
|
|
@@ -508,6 +532,18 @@ class HRPC {
|
|
|
508
532
|
this._handlers['@harness/unload-model'] = responseFn
|
|
509
533
|
}
|
|
510
534
|
|
|
535
|
+
onSetModelMemoryCap(responseFn) {
|
|
536
|
+
this._handlers['@harness/set-model-memory-cap'] = responseFn
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
onMemoryUsage(responseFn) {
|
|
540
|
+
this._handlers['@harness/memory-usage'] = responseFn
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
onSetDownloadsAllowed(responseFn) {
|
|
544
|
+
this._handlers['@harness/set-downloads-allowed'] = responseFn
|
|
545
|
+
}
|
|
546
|
+
|
|
511
547
|
_requestIsStream(command) {
|
|
512
548
|
return [
|
|
513
549
|
'@harness/completion',
|