@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
|
@@ -2,6 +2,7 @@ import b4a from 'b4a';
|
|
|
2
2
|
import { errorMessage } from '../guards.js';
|
|
3
3
|
import { AbortedError } from '../helpers/race-abort.js';
|
|
4
4
|
import { hlog } from '../log.js';
|
|
5
|
+
import { buildWavBuffer } from '../wav-encode.js';
|
|
5
6
|
import { normalizeForSpeech } from './speech-text.js';
|
|
6
7
|
export const SUPERTONIC_SAMPLE_RATE = 44100;
|
|
7
8
|
export function createVoiceLane() {
|
|
@@ -14,31 +15,19 @@ export function createVoiceLane() {
|
|
|
14
15
|
}
|
|
15
16
|
const TRANSCRIBE_SAMPLE_RATE = 16000;
|
|
16
17
|
const TRANSCRIBE_CHUNK_BYTES = TRANSCRIBE_SAMPLE_RATE * 2;
|
|
18
|
+
const TRANSCRIBE_STREAM_MIN_BYTES = TRANSCRIBE_CHUNK_BYTES * 60;
|
|
19
|
+
const TRANSCRIBE_SEGMENT_SECONDS = 300;
|
|
17
20
|
const PARAKEET_STREAMING = { emitPartials: false, chunkMs: 5000 };
|
|
18
21
|
const TRANSCRIBE_WITH_METADATA = false;
|
|
19
22
|
const TRANSCRIBE_PACE_MS = 40;
|
|
20
23
|
function pace(ms) {
|
|
21
24
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
22
25
|
}
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
async function writePaced(session, data, signal) {
|
|
26
|
-
for (let offset = 0; offset < data.length; offset += TRANSCRIBE_CHUNK_BYTES) {
|
|
26
|
+
async function writePaced(session, pcm, signal) {
|
|
27
|
+
for await (const second of pcm) {
|
|
27
28
|
if (signal?.aborted)
|
|
28
29
|
return;
|
|
29
|
-
session.write(
|
|
30
|
-
await pace(TRANSCRIBE_PACE_MS);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async function drainUntilIdle(lastPieceAt, streamClosed, signal) {
|
|
34
|
-
const deadline = Date.now() + TRANSCRIBE_DRAIN_MAX_MS;
|
|
35
|
-
for (;;) {
|
|
36
|
-
if (signal?.aborted || streamClosed() || Date.now() >= deadline)
|
|
37
|
-
return;
|
|
38
|
-
const last = lastPieceAt();
|
|
39
|
-
if (last > 0 && Date.now() - last >= TRANSCRIBE_DRAIN_IDLE_MS) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
30
|
+
session.write(second);
|
|
42
31
|
await pace(TRANSCRIBE_PACE_MS);
|
|
43
32
|
}
|
|
44
33
|
}
|
|
@@ -59,7 +48,93 @@ function transcribePiece(piece) {
|
|
|
59
48
|
}
|
|
60
49
|
return null;
|
|
61
50
|
}
|
|
62
|
-
|
|
51
|
+
async function* inSeconds(pcm) {
|
|
52
|
+
let pending = [];
|
|
53
|
+
let size = 0;
|
|
54
|
+
for await (const chunk of pcm) {
|
|
55
|
+
pending.push(chunk);
|
|
56
|
+
size += chunk.length;
|
|
57
|
+
if (size < TRANSCRIBE_CHUNK_BYTES) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const joined = pending.length === 1 ? chunk : b4a.concat(pending);
|
|
61
|
+
let offset = 0;
|
|
62
|
+
for (; joined.length - offset >= TRANSCRIBE_CHUNK_BYTES; offset += TRANSCRIBE_CHUNK_BYTES) {
|
|
63
|
+
yield joined.subarray(offset, offset + TRANSCRIBE_CHUNK_BYTES);
|
|
64
|
+
}
|
|
65
|
+
size = joined.length - offset;
|
|
66
|
+
pending = size > 0 ? [joined.subarray(offset)] : [];
|
|
67
|
+
}
|
|
68
|
+
if (size > 0) {
|
|
69
|
+
yield b4a.concat(pending);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function readHead(seconds, signal) {
|
|
73
|
+
const head = { seconds: [], bytes: 0 };
|
|
74
|
+
try {
|
|
75
|
+
while (head.bytes < TRANSCRIBE_STREAM_MIN_BYTES && !signal?.aborted) {
|
|
76
|
+
const next = await seconds.next();
|
|
77
|
+
if (next.done) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
head.seconds.push(next.value);
|
|
81
|
+
head.bytes += next.value.length;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
hlog('audio decode/resample failed', { error: errorMessage(err) });
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return head;
|
|
89
|
+
}
|
|
90
|
+
async function* resume(head, rest) {
|
|
91
|
+
yield* head.seconds;
|
|
92
|
+
yield* { [Symbol.asyncIterator]: () => rest };
|
|
93
|
+
}
|
|
94
|
+
export async function transcribeAudio(sdk, pcm, { modelId, signal, audio }) {
|
|
95
|
+
const seconds = inSeconds(pcm);
|
|
96
|
+
const head = await readHead(seconds, signal);
|
|
97
|
+
if (signal?.aborted) {
|
|
98
|
+
await seconds.return(undefined);
|
|
99
|
+
throw new AbortedError();
|
|
100
|
+
}
|
|
101
|
+
if (!head || head.bytes === 0) {
|
|
102
|
+
return transcribeOnce(sdk, modelId, audio);
|
|
103
|
+
}
|
|
104
|
+
if (head.bytes < TRANSCRIBE_STREAM_MIN_BYTES) {
|
|
105
|
+
return transcribeOnce(sdk, modelId, buildWavBuffer(b4a.concat(head.seconds)));
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
return await transcribeStreaming(sdk, resume(head, seconds), { modelId, signal });
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
await seconds.return(undefined);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function* segment(first, rest) {
|
|
115
|
+
yield first;
|
|
116
|
+
for (let n = 1; n < TRANSCRIBE_SEGMENT_SECONDS; n++) {
|
|
117
|
+
const next = await rest.next();
|
|
118
|
+
if (next.done) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
yield next.value;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function transcribeStreaming(sdk, pcm, opts) {
|
|
125
|
+
const seconds = pcm[Symbol.asyncIterator]();
|
|
126
|
+
const parts = [];
|
|
127
|
+
try {
|
|
128
|
+
for (let first = await seconds.next(); !first.done; first = await seconds.next()) {
|
|
129
|
+
parts.push(await transcribeSession(sdk, segment(first.value, seconds), opts));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
await seconds.return?.();
|
|
134
|
+
}
|
|
135
|
+
return parts.filter(Boolean).join(' ');
|
|
136
|
+
}
|
|
137
|
+
async function transcribeSession(sdk, pcm, { modelId, signal }) {
|
|
63
138
|
const session = await sdk.transcribeStream({
|
|
64
139
|
modelId,
|
|
65
140
|
metadata: TRANSCRIBE_WITH_METADATA,
|
|
@@ -67,27 +142,20 @@ export async function transcribeStreaming(sdk, pcm, { modelId, signal }) {
|
|
|
67
142
|
});
|
|
68
143
|
const onAbort = () => session.destroy();
|
|
69
144
|
signal?.addEventListener('abort', onAbort, { once: true });
|
|
70
|
-
let lastPieceAt = 0;
|
|
71
|
-
let streamClosed = false;
|
|
72
145
|
const collect = (async () => {
|
|
73
146
|
let out = '';
|
|
74
147
|
for await (const piece of session) {
|
|
75
|
-
lastPieceAt = Date.now();
|
|
76
148
|
const seg = transcribePiece(piece);
|
|
77
149
|
if (!seg) {
|
|
78
150
|
continue;
|
|
79
151
|
}
|
|
80
152
|
out += !out || seg.append ? seg.text : ` ${seg.text}`;
|
|
81
153
|
}
|
|
82
|
-
streamClosed = true;
|
|
83
154
|
return out.replace(/\s+/g, ' ').trim();
|
|
84
155
|
})();
|
|
85
|
-
collect.catch(
|
|
86
|
-
streamClosed = true;
|
|
87
|
-
});
|
|
156
|
+
collect.catch(noop);
|
|
88
157
|
try {
|
|
89
158
|
await writePaced(session, pcm, signal);
|
|
90
|
-
await drainUntilIdle(() => lastPieceAt, () => streamClosed, signal);
|
|
91
159
|
if (!signal?.aborted) {
|
|
92
160
|
session.end();
|
|
93
161
|
}
|
|
@@ -3,7 +3,7 @@ import { type Transport } from './rpc-session.ts';
|
|
|
3
3
|
import { type KvCacheDeletionResult } from './capabilities/kv-cache.ts';
|
|
4
4
|
import type { CustomModelEntry } from './models/model-catalog.ts';
|
|
5
5
|
import { type ModelSourcePreview, type PreviewModelSourceContext } from './capabilities/preview-model-source.ts';
|
|
6
|
-
import type { CapabilityInfo, CompletionContext, CredentialEntry, DetectedLanguage, DetectLanguageContext, DownloadContext, EmbedContext, HarnessContract, HarnessDiagnostics, HarnessEvent, HarnessInfo, InfraModel, InvokeContext, ListModelsOptions, ModelInfo, ResolvedSkillCatalogEntry, SkillsOptions, SkillWriteResult, SpeakContext, SpeakResult, SpeakStreamContext, ToolCatalogEntry, TranscribeContext, LoadModelContext, LoadModelResult, UnloadModelContext, UnloadModelResult, WarmModelContext } from './contract-types.ts';
|
|
6
|
+
import type { CapabilityInfo, CompletionContext, CredentialEntry, DetectedLanguage, DetectLanguageContext, DownloadContext, EmbedContext, HarnessContract, HarnessDiagnostics, HarnessEvent, HarnessInfo, InfraModel, InvokeContext, ListModelsOptions, ModelInfo, ResolvedSkillCatalogEntry, SkillsOptions, SkillWriteResult, SpeakContext, SpeakResult, SpeakStreamContext, ToolCatalogEntry, TranscribeContext, LoadModelContext, LoadModelResult, MemoryUsage, UnloadModelContext, UnloadModelResult, WarmModelContext, DownloadsAllowedOptions } from './contract-types.ts';
|
|
7
7
|
import { type EmbedDevice } from './models/embed-config.ts';
|
|
8
8
|
import type { DeleteModelSummary } from './models/model-delete.ts';
|
|
9
9
|
import type { CopyBaseResult, DeleteOverlayResult, ManagedSkill, SkillFileContent } from './tools/skills/overlay-crud.ts';
|
|
@@ -36,6 +36,9 @@ export declare class RemoteHarness extends EventEmitter implements HarnessContra
|
|
|
36
36
|
setCredentials(entries: ReadonlyArray<CredentialEntry>): Promise<void>;
|
|
37
37
|
setSkillSettings(entries: ReadonlyArray<SkillSettingEntry>): Promise<void>;
|
|
38
38
|
setModelIdleTimeout(ms: number): Promise<void>;
|
|
39
|
+
setModelMemoryCap(percent: number): Promise<void>;
|
|
40
|
+
memoryUsage(): Promise<MemoryUsage>;
|
|
41
|
+
setDownloadsAllowed({ allowed }: DownloadsAllowedOptions): Promise<void>;
|
|
39
42
|
listManagedSkills(): Promise<ManagedSkill[]>;
|
|
40
43
|
readSkillFile(name: string): Promise<SkillFileContent | null>;
|
|
41
44
|
writeSkillFile(name: string, content: string): Promise<SkillWriteResult>;
|
package/dist-lib/lib/connect.js
CHANGED
|
@@ -102,6 +102,7 @@ export class RemoteHarness extends EventEmitter {
|
|
|
102
102
|
model: context.model,
|
|
103
103
|
agent: knobs(context.agent),
|
|
104
104
|
cacheKey: context.cacheKey,
|
|
105
|
+
session: context.session,
|
|
105
106
|
thinkingDefault: context.thinkingDefault,
|
|
106
107
|
generationParams: context.generationParams,
|
|
107
108
|
responseFormat: context.responseFormat,
|
|
@@ -111,6 +112,7 @@ export class RemoteHarness extends EventEmitter {
|
|
|
111
112
|
content,
|
|
112
113
|
attachments: attachments?.map(({ path: file }) => ({ path: file }))
|
|
113
114
|
})),
|
|
115
|
+
payload: { typedText: context.typedText },
|
|
114
116
|
toolConfigs: context.toolConfigs,
|
|
115
117
|
grantedDirs: context.grantedDirs,
|
|
116
118
|
grantedDrives: context.grantedDrives,
|
|
@@ -422,6 +424,18 @@ export class RemoteHarness extends EventEmitter {
|
|
|
422
424
|
const { client } = await this._ensure();
|
|
423
425
|
await client.setModelIdleTimeout({ ms });
|
|
424
426
|
}
|
|
427
|
+
async setModelMemoryCap(percent) {
|
|
428
|
+
const { client } = await this._ensure();
|
|
429
|
+
await client.setModelMemoryCap({ percent });
|
|
430
|
+
}
|
|
431
|
+
async memoryUsage() {
|
|
432
|
+
const { client } = await this._ensure();
|
|
433
|
+
return await client.memoryUsage({});
|
|
434
|
+
}
|
|
435
|
+
async setDownloadsAllowed({ allowed }) {
|
|
436
|
+
const { client } = await this._ensure();
|
|
437
|
+
await client.setDownloadsAllowed({ allowed });
|
|
438
|
+
}
|
|
425
439
|
async listManagedSkills() {
|
|
426
440
|
const { client } = await this._ensure();
|
|
427
441
|
const response = await client.listManagedSkills({});
|
|
@@ -566,10 +580,11 @@ export class RemoteHarness extends EventEmitter {
|
|
|
566
580
|
cachedOnly: options.cachedOnly,
|
|
567
581
|
fullRegistry: options.fullRegistry
|
|
568
582
|
});
|
|
569
|
-
return (response.models ?? []).map(({ actualSize, label, ...row }) => ({
|
|
583
|
+
return (response.models ?? []).map(({ actualSize, label, memoryBytes, ...row }) => ({
|
|
570
584
|
...row,
|
|
571
585
|
actualSize: actualSize || undefined,
|
|
572
586
|
label: label || undefined,
|
|
587
|
+
memoryBytes: memoryBytes || undefined,
|
|
573
588
|
taskType: addonTaskType(row.type)
|
|
574
589
|
}));
|
|
575
590
|
}
|
|
@@ -46,7 +46,9 @@ export interface CompletionContext {
|
|
|
46
46
|
model: string;
|
|
47
47
|
agent: AgentKnobs;
|
|
48
48
|
messages: ChatMessage[];
|
|
49
|
+
typedText?: string;
|
|
49
50
|
cacheKey?: string;
|
|
51
|
+
session?: string;
|
|
50
52
|
thinkingDefault?: string;
|
|
51
53
|
toolConfigs?: Record<string, Record<string, unknown>>;
|
|
52
54
|
generationParams?: LlmGenerationParams;
|
|
@@ -95,6 +97,9 @@ export interface HarnessEvent {
|
|
|
95
97
|
message?: string;
|
|
96
98
|
[key: string]: unknown;
|
|
97
99
|
}
|
|
100
|
+
export interface DownloadsAllowedOptions {
|
|
101
|
+
allowed: boolean;
|
|
102
|
+
}
|
|
98
103
|
export interface ModelState {
|
|
99
104
|
status: string;
|
|
100
105
|
model?: string;
|
|
@@ -107,6 +112,7 @@ export interface ModelState {
|
|
|
107
112
|
model: string;
|
|
108
113
|
refs: number;
|
|
109
114
|
}>;
|
|
115
|
+
addon?: string | null;
|
|
110
116
|
}
|
|
111
117
|
export interface WarmModelContext {
|
|
112
118
|
model: string;
|
|
@@ -118,6 +124,9 @@ export interface LoadModelResult {
|
|
|
118
124
|
loaded: boolean;
|
|
119
125
|
reason?: 'memory';
|
|
120
126
|
}
|
|
127
|
+
export interface MemoryUsage {
|
|
128
|
+
readonly usedBytes: number;
|
|
129
|
+
}
|
|
121
130
|
export interface UnloadModelContext {
|
|
122
131
|
model: string;
|
|
123
132
|
}
|
|
@@ -223,6 +232,9 @@ export interface HarnessContract {
|
|
|
223
232
|
agentId?: string | null;
|
|
224
233
|
}>): void | Promise<void>;
|
|
225
234
|
setModelIdleTimeout?(ms: number): void | Promise<void>;
|
|
235
|
+
setModelMemoryCap?(percent: number): void | Promise<void>;
|
|
236
|
+
memoryUsage?(): Promise<MemoryUsage>;
|
|
237
|
+
setDownloadsAllowed?(options: DownloadsAllowedOptions): void | Promise<void>;
|
|
226
238
|
listManagedSkills?(): Promise<ManagedSkill[]>;
|
|
227
239
|
readSkillFile?(name: string): Promise<SkillFileContent | null>;
|
|
228
240
|
writeSkillFile?(name: string, content: string): Promise<{
|
|
@@ -9,6 +9,7 @@ export declare function clipRawCall(raw: string): string;
|
|
|
9
9
|
export interface KnownTool {
|
|
10
10
|
readonly name: string;
|
|
11
11
|
}
|
|
12
|
+
export declare function hasMarkupCall(text: string): boolean;
|
|
12
13
|
export declare function recoverMarkupToolCalls(text: string, knownTools: ReadonlyArray<KnownTool>): RecoveredToolCall[];
|
|
13
14
|
export declare function stripToolCallMarkup(text: string): string;
|
|
14
15
|
export declare function stripToolResponseBlocks(text: string): string;
|
|
@@ -46,6 +46,9 @@ export const MAX_RAW_CALL_CHARS = 4096;
|
|
|
46
46
|
export function clipRawCall(raw) {
|
|
47
47
|
return raw.length > MAX_RAW_CALL_CHARS ? raw.slice(0, MAX_RAW_CALL_CHARS) : raw;
|
|
48
48
|
}
|
|
49
|
+
export function hasMarkupCall(text) {
|
|
50
|
+
return !markupBlocks(text, FUNCTION_OPEN, FUNCTION_CLOSE).next().done;
|
|
51
|
+
}
|
|
49
52
|
export function recoverMarkupToolCalls(text, knownTools) {
|
|
50
53
|
const known = new Set(knownTools.map((tool) => tool.name));
|
|
51
54
|
const calls = [];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CapabilityProfile } from './model-catalog-constants.ts';
|
|
2
|
+
export interface ContextAsk {
|
|
3
|
+
trained(): Promise<number | undefined>;
|
|
4
|
+
fits(ctxSize: number): Promise<boolean>;
|
|
5
|
+
}
|
|
6
|
+
export declare class ContextChoice {
|
|
7
|
+
private readonly _profile;
|
|
8
|
+
private readonly _pending;
|
|
9
|
+
private readonly _chosen;
|
|
10
|
+
constructor(profile: () => Promise<CapabilityProfile | undefined>);
|
|
11
|
+
static ceiling(profile: CapabilityProfile | undefined): number | undefined;
|
|
12
|
+
chosen(key: string): number | undefined;
|
|
13
|
+
choose(key: string, tier: number, ask: ContextAsk): Promise<number>;
|
|
14
|
+
private _climb;
|
|
15
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const RUNGS = [262_144, 131_072, 65_536];
|
|
2
|
+
const CEILINGS = {
|
|
3
|
+
mid: 65_536,
|
|
4
|
+
high: 131_072,
|
|
5
|
+
xhigh: 262_144
|
|
6
|
+
};
|
|
7
|
+
export class ContextChoice {
|
|
8
|
+
_profile;
|
|
9
|
+
_pending = new Map();
|
|
10
|
+
_chosen = new Map();
|
|
11
|
+
constructor(profile) {
|
|
12
|
+
this._profile = profile;
|
|
13
|
+
}
|
|
14
|
+
static ceiling(profile) {
|
|
15
|
+
return profile && CEILINGS[profile];
|
|
16
|
+
}
|
|
17
|
+
chosen(key) {
|
|
18
|
+
return this._chosen.get(key);
|
|
19
|
+
}
|
|
20
|
+
choose(key, tier, ask) {
|
|
21
|
+
const pending = this._pending.get(key);
|
|
22
|
+
if (pending) {
|
|
23
|
+
return pending;
|
|
24
|
+
}
|
|
25
|
+
const choice = this._climb(tier, ask).then((ctxSize) => {
|
|
26
|
+
if (ctxSize === undefined) {
|
|
27
|
+
this._pending.delete(key);
|
|
28
|
+
return tier;
|
|
29
|
+
}
|
|
30
|
+
this._chosen.set(key, ctxSize);
|
|
31
|
+
return ctxSize;
|
|
32
|
+
});
|
|
33
|
+
this._pending.set(key, choice);
|
|
34
|
+
return choice;
|
|
35
|
+
}
|
|
36
|
+
async _climb(tier, ask) {
|
|
37
|
+
const ceiling = ContextChoice.ceiling(await this._profile());
|
|
38
|
+
if (!ceiling || ceiling <= tier) {
|
|
39
|
+
return tier;
|
|
40
|
+
}
|
|
41
|
+
const trained = await ask.trained();
|
|
42
|
+
if (!trained) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
for (const rung of RUNGS) {
|
|
46
|
+
if (rung > ceiling || rung > trained || rung <= tier) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (await ask.fits(rung)) {
|
|
50
|
+
return rung;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return tier;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
|
|
2
|
+
import type { ModelAddon } from './model-source.ts';
|
|
3
|
+
export interface HeldModel {
|
|
4
|
+
readonly model: string;
|
|
5
|
+
readonly addon: ModelAddon;
|
|
6
|
+
}
|
|
7
|
+
export interface DownloadGateOptions {
|
|
8
|
+
isCached(model: string, addon: ModelAddon): Promise<boolean>;
|
|
9
|
+
onHeld(held: HeldModel): void;
|
|
10
|
+
onDropped(held: HeldModel): void;
|
|
11
|
+
}
|
|
12
|
+
export type HoldFn = (model: string, addon: ModelAddon, signal?: BareAbortSignal) => Promise<void>;
|
|
13
|
+
export interface DownloadGate {
|
|
14
|
+
readonly allowed: boolean;
|
|
15
|
+
setAllowed(allowed: boolean): void;
|
|
16
|
+
downloaded(): void;
|
|
17
|
+
hold: HoldFn;
|
|
18
|
+
abandon(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare function createDownloadGate({ isCached, onHeld, onDropped }: DownloadGateOptions): DownloadGate;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { AbortedError, raceAbort } from '../helpers/race-abort.js';
|
|
2
|
+
function deferred() {
|
|
3
|
+
const next = Promise.withResolvers();
|
|
4
|
+
next.promise.catch(noop);
|
|
5
|
+
return next;
|
|
6
|
+
}
|
|
7
|
+
export function createDownloadGate({ isCached, onHeld, onDropped }) {
|
|
8
|
+
let allowed = true;
|
|
9
|
+
let woke = deferred();
|
|
10
|
+
let dropped = deferred();
|
|
11
|
+
const wake = () => {
|
|
12
|
+
const woken = woke;
|
|
13
|
+
woke = deferred();
|
|
14
|
+
woken.resolve();
|
|
15
|
+
};
|
|
16
|
+
const wait = async (held, signal, onWait) => {
|
|
17
|
+
const drop = dropped;
|
|
18
|
+
const cancelled = () => signal?.aborted === true || drop !== dropped;
|
|
19
|
+
for (;;) {
|
|
20
|
+
const change = Promise.race([raceAbort(woke.promise, signal), drop.promise]);
|
|
21
|
+
change.catch(noop);
|
|
22
|
+
const ready = allowed || (await isCached(held.model, held.addon).catch(() => false));
|
|
23
|
+
if (cancelled()) {
|
|
24
|
+
throw new AbortedError();
|
|
25
|
+
}
|
|
26
|
+
if (ready) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
onWait();
|
|
30
|
+
await change;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
get allowed() {
|
|
35
|
+
return allowed;
|
|
36
|
+
},
|
|
37
|
+
setAllowed(next) {
|
|
38
|
+
allowed = next;
|
|
39
|
+
if (allowed) {
|
|
40
|
+
wake();
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
downloaded: wake,
|
|
44
|
+
async hold(model, addon, signal) {
|
|
45
|
+
if (allowed)
|
|
46
|
+
return;
|
|
47
|
+
if (signal?.aborted)
|
|
48
|
+
throw new AbortedError();
|
|
49
|
+
const held = { model, addon };
|
|
50
|
+
let shown = false;
|
|
51
|
+
try {
|
|
52
|
+
await wait(held, signal, () => {
|
|
53
|
+
if (!shown) {
|
|
54
|
+
shown = true;
|
|
55
|
+
onHeld(held);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (shown) {
|
|
61
|
+
onDropped(held);
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
abandon() {
|
|
67
|
+
const abandoned = dropped;
|
|
68
|
+
dropped = deferred();
|
|
69
|
+
abandoned.reject(new AbortedError());
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function noop() { }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const VictimRank: {
|
|
2
|
+
readonly generator: 0;
|
|
3
|
+
readonly companion: 1;
|
|
4
|
+
readonly requested: 2;
|
|
5
|
+
readonly pinned: 3;
|
|
6
|
+
readonly replying: 4;
|
|
7
|
+
};
|
|
8
|
+
export interface CapVictim {
|
|
9
|
+
readonly rank: number;
|
|
10
|
+
readonly lastUsed: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function nextVictim<T extends CapVictim>(victims: ReadonlyArray<T>): T | undefined;
|
|
13
|
+
export declare function memoryCapBytes(percent: number, availableBytes: number): number;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const VictimRank = {
|
|
2
|
+
generator: 0,
|
|
3
|
+
companion: 1,
|
|
4
|
+
requested: 2,
|
|
5
|
+
pinned: 3,
|
|
6
|
+
replying: 4
|
|
7
|
+
};
|
|
8
|
+
export function nextVictim(victims) {
|
|
9
|
+
let best;
|
|
10
|
+
for (const victim of victims) {
|
|
11
|
+
if (best === undefined ||
|
|
12
|
+
victim.rank < best.rank ||
|
|
13
|
+
(victim.rank === best.rank && victim.lastUsed < best.lastUsed)) {
|
|
14
|
+
best = victim;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return best;
|
|
18
|
+
}
|
|
19
|
+
export function memoryCapBytes(percent, availableBytes) {
|
|
20
|
+
return Math.round((Math.min(percent, 100) / 100) * availableBytes);
|
|
21
|
+
}
|
|
@@ -6,6 +6,8 @@ export declare const QWEN_35_9B = "Qwen3.5-9B-Q4_K_M";
|
|
|
6
6
|
export declare const QWEN_36_27B = "Qwen3.6-27B-UD-Q4_K_XL";
|
|
7
7
|
export declare const QWEN_36_35B_A3B = "Qwen3.6-35B-A3B-UD-Q4_K_M";
|
|
8
8
|
export declare const QWEN_38_27B = "Qwen3.8-27B-UD-Q4_K_XL";
|
|
9
|
+
export declare const BONSAI_2_27B_PQ2 = "Ternary-Bonsai-2-27B-PQ2_0";
|
|
10
|
+
export declare const BONSAI_2_27B_PTQ1 = "Ternary-Bonsai-2-27B-PTQ1_0";
|
|
9
11
|
export declare const MEDPSY_1_7B = "medpsy-1.7b-q4_k_m-imat";
|
|
10
12
|
export declare const MEDPSY_4B = "medpsy-4b-q4_k_m-imat";
|
|
11
13
|
export declare function isCapabilityProfile(value: string): value is CapabilityProfile;
|
|
@@ -19,7 +21,7 @@ export interface HostCapability {
|
|
|
19
21
|
export declare function isMobilePlatform(platform: string): boolean;
|
|
20
22
|
export declare function runnableModelName(requested: string, host: HostCapability | null): string;
|
|
21
23
|
export declare function capabilityProfileToModelName(profile: CapabilityProfile): string;
|
|
22
|
-
export declare const AGENT_MODEL_NAMES: readonly ["Qwen3.5-2B-Q4_K_M", "Qwen3.5-4B-Q4_K_M", "Qwen3.5-9B-Q4_K_M", "Qwen3.6-27B-UD-Q4_K_XL", "Qwen3.6-35B-A3B-UD-Q4_K_M", "Qwen3.8-27B-UD-Q4_K_XL", "medpsy-1.7b-q4_k_m-imat", "medpsy-4b-q4_k_m-imat"];
|
|
24
|
+
export declare const AGENT_MODEL_NAMES: readonly ["Qwen3.5-2B-Q4_K_M", "Qwen3.5-4B-Q4_K_M", "Qwen3.5-9B-Q4_K_M", "Qwen3.6-27B-UD-Q4_K_XL", "Qwen3.6-35B-A3B-UD-Q4_K_M", "Qwen3.8-27B-UD-Q4_K_XL", "Ternary-Bonsai-2-27B-PQ2_0", "Ternary-Bonsai-2-27B-PTQ1_0", "medpsy-1.7b-q4_k_m-imat", "medpsy-4b-q4_k_m-imat"];
|
|
23
25
|
export declare function modelDisplayName(modelName: string): string;
|
|
24
26
|
export declare function capabilityProfileModelLabel(profile: CapabilityProfile): string;
|
|
25
27
|
export declare function isMultimodalLlm(modelName: string): boolean;
|
|
@@ -11,6 +11,8 @@ export const QWEN_35_9B = 'Qwen3.5-9B-Q4_K_M';
|
|
|
11
11
|
export const QWEN_36_27B = 'Qwen3.6-27B-UD-Q4_K_XL';
|
|
12
12
|
export const QWEN_36_35B_A3B = 'Qwen3.6-35B-A3B-UD-Q4_K_M';
|
|
13
13
|
export const QWEN_38_27B = 'Qwen3.8-27B-UD-Q4_K_XL';
|
|
14
|
+
export const BONSAI_2_27B_PQ2 = 'Ternary-Bonsai-2-27B-PQ2_0';
|
|
15
|
+
export const BONSAI_2_27B_PTQ1 = 'Ternary-Bonsai-2-27B-PTQ1_0';
|
|
14
16
|
export const MEDPSY_1_7B = 'medpsy-1.7b-q4_k_m-imat';
|
|
15
17
|
export const MEDPSY_4B = 'medpsy-4b-q4_k_m-imat';
|
|
16
18
|
export function isCapabilityProfile(value) {
|
|
@@ -26,6 +28,8 @@ const MODEL_NAME_TO_PROFILE = new Map([
|
|
|
26
28
|
[QWEN_36_27B, 'xhigh'],
|
|
27
29
|
[QWEN_36_35B_A3B, 'xhigh'],
|
|
28
30
|
[QWEN_38_27B, 'xhigh'],
|
|
31
|
+
[BONSAI_2_27B_PQ2, 'high'],
|
|
32
|
+
[BONSAI_2_27B_PTQ1, 'high'],
|
|
29
33
|
[MEDPSY_1_7B, 'low'],
|
|
30
34
|
[MEDPSY_4B, 'mid']
|
|
31
35
|
]);
|
|
@@ -70,6 +74,8 @@ export const AGENT_MODEL_NAMES = [
|
|
|
70
74
|
QWEN_36_27B,
|
|
71
75
|
QWEN_36_35B_A3B,
|
|
72
76
|
QWEN_38_27B,
|
|
77
|
+
BONSAI_2_27B_PQ2,
|
|
78
|
+
BONSAI_2_27B_PTQ1,
|
|
73
79
|
MEDPSY_1_7B,
|
|
74
80
|
MEDPSY_4B
|
|
75
81
|
];
|
|
@@ -87,7 +93,9 @@ const MULTIMODAL_LLMS = new Set([
|
|
|
87
93
|
QWEN_35_9B,
|
|
88
94
|
QWEN_36_27B,
|
|
89
95
|
QWEN_36_35B_A3B,
|
|
90
|
-
QWEN_38_27B
|
|
96
|
+
QWEN_38_27B,
|
|
97
|
+
BONSAI_2_27B_PQ2,
|
|
98
|
+
BONSAI_2_27B_PTQ1
|
|
91
99
|
]);
|
|
92
100
|
export function isMultimodalLlm(modelName) {
|
|
93
101
|
return MULTIMODAL_LLMS.has(modelName);
|
|
@@ -6,8 +6,8 @@ import type { ModelAddon } from './model-source.ts';
|
|
|
6
6
|
export interface SdkModelAsset extends ModelRegistryEntry {
|
|
7
7
|
readonly src: string;
|
|
8
8
|
}
|
|
9
|
-
import { CAPABILITY_PROFILE_ORDER, QWEN_35_2B, QWEN_35_4B, QWEN_35_9B, QWEN_36_27B, QWEN_36_35B_A3B, QWEN_38_27B, MEDPSY_1_7B, MEDPSY_4B, isCapabilityProfile, meetsMinCapabilityProfile, modelNameToCapabilityProfile, capabilityProfileToModelName, isMultimodalLlm, AGENT_MODEL_NAMES, modelDisplayName, capabilityProfileModelLabel, DEFAULT_IMAGE_MODEL_CHOICE, IMAGE_CHOICE_CATALOG, isMobilePlatform, runnableModelName, type CapabilityProfile, type HostCapability, type ImageModelChoice, type ImageChoiceEntry } from './model-catalog-constants.ts';
|
|
10
|
-
export { CAPABILITY_PROFILE_ORDER, QWEN_35_2B, QWEN_35_4B, QWEN_35_9B, QWEN_36_27B, QWEN_36_35B_A3B, QWEN_38_27B, MEDPSY_1_7B, MEDPSY_4B, isCapabilityProfile, meetsMinCapabilityProfile, modelNameToCapabilityProfile, capabilityProfileToModelName, isMultimodalLlm, AGENT_MODEL_NAMES, modelDisplayName, capabilityProfileModelLabel, DEFAULT_IMAGE_MODEL_CHOICE, IMAGE_CHOICE_CATALOG, isMobilePlatform, runnableModelName };
|
|
9
|
+
import { CAPABILITY_PROFILE_ORDER, QWEN_35_2B, QWEN_35_4B, QWEN_35_9B, QWEN_36_27B, QWEN_36_35B_A3B, QWEN_38_27B, BONSAI_2_27B_PQ2, BONSAI_2_27B_PTQ1, MEDPSY_1_7B, MEDPSY_4B, isCapabilityProfile, meetsMinCapabilityProfile, modelNameToCapabilityProfile, capabilityProfileToModelName, isMultimodalLlm, AGENT_MODEL_NAMES, modelDisplayName, capabilityProfileModelLabel, DEFAULT_IMAGE_MODEL_CHOICE, IMAGE_CHOICE_CATALOG, isMobilePlatform, runnableModelName, type CapabilityProfile, type HostCapability, type ImageModelChoice, type ImageChoiceEntry } from './model-catalog-constants.ts';
|
|
10
|
+
export { CAPABILITY_PROFILE_ORDER, QWEN_35_2B, QWEN_35_4B, QWEN_35_9B, QWEN_36_27B, QWEN_36_35B_A3B, QWEN_38_27B, BONSAI_2_27B_PQ2, BONSAI_2_27B_PTQ1, MEDPSY_1_7B, MEDPSY_4B, isCapabilityProfile, meetsMinCapabilityProfile, modelNameToCapabilityProfile, capabilityProfileToModelName, isMultimodalLlm, AGENT_MODEL_NAMES, modelDisplayName, capabilityProfileModelLabel, DEFAULT_IMAGE_MODEL_CHOICE, IMAGE_CHOICE_CATALOG, isMobilePlatform, runnableModelName };
|
|
11
11
|
export type { CapabilityProfile, HostCapability, ImageModelChoice, ImageChoiceEntry };
|
|
12
12
|
export interface LlmCatalogEntry {
|
|
13
13
|
readonly name: string;
|
|
@@ -15,6 +15,7 @@ export interface LlmCatalogEntry {
|
|
|
15
15
|
readonly capabilityProfile: CapabilityProfile;
|
|
16
16
|
readonly projection?: SdkModelAsset;
|
|
17
17
|
readonly textOnly?: true;
|
|
18
|
+
readonly toolDialect?: ToolDialect;
|
|
18
19
|
}
|
|
19
20
|
export declare const LLM_CATALOG: ReadonlyArray<LlmCatalogEntry>;
|
|
20
21
|
export declare function defaultProjectionMap(): Record<string, string>;
|
|
@@ -52,6 +53,7 @@ export interface DiffusionDownloadMetadata {
|
|
|
52
53
|
}
|
|
53
54
|
export declare function diffusionDownloadName(model: string): string | null;
|
|
54
55
|
export declare function diffusionDownloadMetadata(model: string, addon: ModelAddon | undefined): DiffusionDownloadMetadata | undefined;
|
|
56
|
+
export declare function assetBytes(src: string): number | undefined;
|
|
55
57
|
import { DEFAULT_MUSIC_MODEL_CHOICE, isMusicModelChoice, musicModelChoiceFrom, type MusicModelChoice } from './music-catalog.ts';
|
|
56
58
|
export { DEFAULT_MUSIC_MODEL_CHOICE, isMusicModelChoice, musicModelChoiceFrom, type MusicModelChoice };
|
|
57
59
|
export interface AudioGenCatalogEntry {
|
|
@@ -108,6 +110,7 @@ export declare function curatedListables(): CuratedListable[];
|
|
|
108
110
|
export declare function curatedModelAsset(name: string, addon: ModelRegistryEntry['addon']): SdkModelAsset | undefined;
|
|
109
111
|
export declare function modelAddonOf(model: string): ModelRegistryEntry['addon'];
|
|
110
112
|
export declare function residentSrc(model: string, addon: ModelRegistryEntry['addon']): string;
|
|
113
|
+
export declare function catalogModelName(model: string, addon: ModelRegistryEntry['addon']): string;
|
|
111
114
|
export declare const CUSTOM_TASK_TYPES: readonly ['llm'];
|
|
112
115
|
export type CustomTaskType = (typeof CUSTOM_TASK_TYPES)[number];
|
|
113
116
|
export interface CustomModelEntry {
|
|
@@ -123,6 +126,7 @@ export declare function setCustomModels(entries: ReadonlyArray<CustomModelEntry>
|
|
|
123
126
|
export declare function customModels(): ReadonlyArray<CustomModelEntry>;
|
|
124
127
|
export declare function customContextLength(name: string): number | undefined;
|
|
125
128
|
export declare function customModelSrc(name: string, addon: ModelRegistryEntry['addon']): string | undefined;
|
|
129
|
+
export declare function toolDialectFor(name: string): ToolDialect | undefined;
|
|
126
130
|
export declare function customToolDialect(name: string): ToolDialect | undefined;
|
|
127
131
|
export declare function customProjectionMap(): Record<string, string>;
|
|
128
132
|
export declare function companionRegistryPaths(): Map<string, string[]>;
|