@qvac/harness 0.8.6 → 0.8.8
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 +1298 -507
- package/dist-lib/index.d.ts +11 -0
- package/dist-lib/index.js +102 -25
- package/dist-lib/lib/capabilities/completion.d.ts +5 -4
- package/dist-lib/lib/capabilities/completion.js +132 -64
- 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/connect.js +3 -0
- package/dist-lib/lib/contract-types.d.ts +2 -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/model-pool.d.ts +3 -1
- package/dist-lib/lib/models/model-pool.js +8 -11
- 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 +6 -1
- 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/file-glob.js +1 -0
- package/dist-lib/lib/tools/grep.js +1 -0
- package/dist-lib/lib/tools/office/ops.js +1 -1
- package/dist-lib/lib/tools/office.js +29 -6
- package/dist-lib/lib/tools/read-files.js +1 -0
- package/dist-lib/lib/tools/skill.js +6 -4
- package/dist-lib/lib/tools/skills/catalog.d.ts +2 -0
- package/dist-lib/lib/tools/skills/catalog.js +4 -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 +2 -0
- package/dist-lib/lib/tools/skills/frontmatter-parser.js +4 -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-name.d.ts +6 -0
- package/dist-lib/lib/tools/skills/mention-name.js +6 -0
- package/dist-lib/lib/tools/skills/mention.d.ts +2 -3
- package/dist-lib/lib/tools/skills/mention.js +5 -6
- package/dist-lib/lib/tools/weather-lookup.js +1 -0
- package/dist-lib/lib/tools/web-fetch.js +1 -0
- package/dist-lib/lib/tools/web-search.js +1 -0
- package/dist-lib/schema/harness.js +4 -2
- package/dist-lib/spec/hrpc/messages.js +18 -8
- package/dist-lib/spec/hyperschema/index.js +18 -8
- package/dist-lib/spec/hyperschema/schema.json +11 -1
- package/dist-lib/spec/hyperschema/types.d.ts +3 -1
- package/package.json +5 -7
- 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,
|
|
@@ -185,12 +185,14 @@ export function createSkillTool({ skillsDir, overlayDir = resolveSkillsOverlayDi
|
|
|
185
185
|
try {
|
|
186
186
|
return await mainInstead(file, available);
|
|
187
187
|
}
|
|
188
|
-
catch {
|
|
188
|
+
catch {
|
|
189
|
+
return { error: `skill not found: ${name}` };
|
|
190
|
+
}
|
|
189
191
|
}
|
|
190
192
|
const rest = available.length
|
|
191
|
-
? `
|
|
192
|
-
: '
|
|
193
|
-
return {
|
|
193
|
+
? `Its other files: ${available.join(', ')}.`
|
|
194
|
+
: 'It has no other files; you already have its full instructions, so act now.';
|
|
195
|
+
return { name, content: `There is no file ${file} in this skill. ${rest}` };
|
|
194
196
|
}
|
|
195
197
|
}
|
|
196
198
|
};
|
|
@@ -9,6 +9,7 @@ import { type OperationSpec } from '../operations/manifest.ts';
|
|
|
9
9
|
import type { CapabilityProfile } from '../../models/model-catalog.ts';
|
|
10
10
|
export interface SkillCatalogEntry {
|
|
11
11
|
name: string;
|
|
12
|
+
displayName?: string;
|
|
12
13
|
description: string;
|
|
13
14
|
aliases?: string[];
|
|
14
15
|
preloadOnName?: boolean;
|
|
@@ -20,6 +21,7 @@ export interface SkillCatalogEntry {
|
|
|
20
21
|
requires?: SkillRequires;
|
|
21
22
|
install?: InstallStep[];
|
|
22
23
|
setup?: SkillSetup;
|
|
24
|
+
env?: Readonly<Record<string, string>>;
|
|
23
25
|
cliValidator?: CliValidator;
|
|
24
26
|
stub?: boolean;
|
|
25
27
|
minCapabilityProfile?: string;
|
|
@@ -79,9 +79,11 @@ function mergeOverlay(base, overlay) {
|
|
|
79
79
|
const { origin: _origin, mcpReads: _mcpReads, operations: _operations, ...rest } = overlay;
|
|
80
80
|
return {
|
|
81
81
|
...rest,
|
|
82
|
+
displayName: base.displayName,
|
|
82
83
|
credentials: base.credentials,
|
|
83
84
|
allowList: base.allowList,
|
|
84
85
|
platform: base.platform,
|
|
86
|
+
env: base.env,
|
|
85
87
|
operations: base.operations,
|
|
86
88
|
mcpReads: base.mcpReads
|
|
87
89
|
};
|
|
@@ -155,6 +157,7 @@ async function loadEntry(skillsDir, dir, origin) {
|
|
|
155
157
|
const platform = platformsOf(meta.platform, origin);
|
|
156
158
|
return {
|
|
157
159
|
name: dir,
|
|
160
|
+
displayName: origin === 'overlay' ? undefined : meta.displayName || undefined,
|
|
158
161
|
description: meta.description ?? '',
|
|
159
162
|
aliases: meta.aliases,
|
|
160
163
|
preloadOnName: meta.preloadOnName === false ? false : undefined,
|
|
@@ -166,6 +169,7 @@ async function loadEntry(skillsDir, dir, origin) {
|
|
|
166
169
|
requires: meta.requires,
|
|
167
170
|
install: meta.install,
|
|
168
171
|
setup: meta.setup,
|
|
172
|
+
env: origin === 'overlay' ? undefined : meta.env,
|
|
169
173
|
cliValidator: cli ? buildCliValidator(cli) : undefined,
|
|
170
174
|
stub: meta.stub,
|
|
171
175
|
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) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { InstallStep, SkillRequires, SkillSetup } from './manifest.ts';
|
|
2
2
|
export interface SkillFrontMatter {
|
|
3
3
|
name?: string;
|
|
4
|
+
displayName?: string;
|
|
4
5
|
description?: string;
|
|
5
6
|
aliases?: string[];
|
|
6
7
|
preloadOnName?: boolean;
|
|
@@ -12,6 +13,7 @@ export interface SkillFrontMatter {
|
|
|
12
13
|
requires?: SkillRequires;
|
|
13
14
|
install?: InstallStep[];
|
|
14
15
|
setup?: SkillSetup;
|
|
16
|
+
env?: Readonly<Record<string, string>>;
|
|
15
17
|
stub?: boolean;
|
|
16
18
|
minCapabilityProfile?: string;
|
|
17
19
|
emoji?: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseManifestBlock } from './manifest-parse.js';
|
|
2
|
+
import { isMentionHandle } from './mention-name.js';
|
|
2
3
|
const FRONT_MATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
3
4
|
const FIELD_RE = /^([A-Za-z_][\w-]*):(.*)$/;
|
|
4
5
|
export function parseSkillFrontMatter(raw) {
|
|
@@ -54,6 +55,9 @@ function parseFields(block) {
|
|
|
54
55
|
else if (key === 'name' || key === 'description') {
|
|
55
56
|
meta[key] = stripQuotes(value);
|
|
56
57
|
}
|
|
58
|
+
else if (key === 'display_name' && isMentionHandle(stripQuotes(value))) {
|
|
59
|
+
meta.displayName = stripQuotes(value);
|
|
60
|
+
}
|
|
57
61
|
else if (key === 'preload_on_name') {
|
|
58
62
|
meta.preloadOnName = stripQuotes(value).toLowerCase() !== 'false';
|
|
59
63
|
}
|
|
@@ -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) {
|
|
@@ -1 +1,7 @@
|
|
|
1
1
|
export declare function skillMentionName(text: string): string | null;
|
|
2
|
+
export declare function isMentionHandle(value: string): boolean;
|
|
3
|
+
export interface MentionableSkill {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly displayName?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function skillMentionHandle(skill: MentionableSkill): string;
|
|
@@ -2,3 +2,9 @@ const MENTION_PATTERN = /^@([a-z0-9][a-z0-9_-]*)(?=\s|$)/;
|
|
|
2
2
|
export function skillMentionName(text) {
|
|
3
3
|
return MENTION_PATTERN.exec(text.trimStart().toLowerCase())?.[1] ?? null;
|
|
4
4
|
}
|
|
5
|
+
export function isMentionHandle(value) {
|
|
6
|
+
return skillMentionName(`@${value}`) === value.toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
export function skillMentionHandle(skill) {
|
|
9
|
+
return (skill.displayName ?? skill.name).toLowerCase();
|
|
10
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { SkillCatalogEntry } from './catalog.ts';
|
|
2
|
-
import { skillMentionName } from './mention-name.ts';
|
|
3
|
-
export { skillMentionName };
|
|
2
|
+
import { skillMentionHandle, skillMentionName } from './mention-name.ts';
|
|
3
|
+
export { skillMentionHandle, 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;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { has } from 'asenion';
|
|
2
|
-
import { skillMentionName } from './mention-name.js';
|
|
3
|
-
export { skillMentionName };
|
|
2
|
+
import { skillMentionHandle, skillMentionName } from './mention-name.js';
|
|
3
|
+
export { skillMentionHandle, skillMentionName };
|
|
4
4
|
export function resolveSkillMention(text, catalog) {
|
|
5
5
|
const name = skillMentionName(text);
|
|
6
6
|
if (!name) {
|
|
7
7
|
return null;
|
|
8
8
|
}
|
|
9
|
-
return catalog.find((skill) => skill.
|
|
9
|
+
return (catalog.find((skill) => skill.displayName?.toLowerCase() === name) ??
|
|
10
|
+
catalog.find((skill) => skill.name.toLowerCase() === name) ??
|
|
11
|
+
null);
|
|
10
12
|
}
|
|
11
13
|
const MIN_IMPLICIT_NAME_LENGTH = 4;
|
|
12
14
|
function matchesName(text, candidate) {
|
|
@@ -38,6 +40,3 @@ export function resolveImplicitSkill(text, activeSkills) {
|
|
|
38
40
|
}
|
|
39
41
|
return best;
|
|
40
42
|
}
|
|
41
|
-
export function skillPreloadMessage(content, name, body) {
|
|
42
|
-
return `[Skill invoked by user: ${name}]\n${body}\n\nThe user's message:\n${content}`;
|
|
43
|
-
}
|
|
@@ -32,6 +32,7 @@ export function createWeatherLookupTool({ fetch = noRedirectFetch, resolveHost =
|
|
|
32
32
|
required: ['location']
|
|
33
33
|
},
|
|
34
34
|
effect: () => 'read',
|
|
35
|
+
stableRead: true,
|
|
35
36
|
resource: () => ({ kind: 'host', label: `${GEOCODER_HOST}, ${WEATHER_HOST}` }),
|
|
36
37
|
execute: (args, ctx) => execute(args.location, ctx?.signal, { fetch, resolveHost, timeoutMs: geocodeTimeoutMs })
|
|
37
38
|
};
|
|
@@ -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({
|
|
@@ -321,7 +322,8 @@ export function registerHarnessTypes(ns) {
|
|
|
321
322
|
{ name: 'surfaceWhenUnsupported', type: 'bool' },
|
|
322
323
|
{ name: 'minCapabilityProfile', type: 'string' },
|
|
323
324
|
{ name: 'emoji', type: 'string' },
|
|
324
|
-
{ name: 'setupV2', type: '@harness/skill-setup-v2' }
|
|
325
|
+
{ name: 'setupV2', type: '@harness/skill-setup-v2' },
|
|
326
|
+
{ name: 'displayName', type: 'string' }
|
|
325
327
|
]
|
|
326
328
|
});
|
|
327
329
|
ns.register({
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// This file is autogenerated by the hyperschema compiler
|
|
2
|
-
// Schema Version:
|
|
2
|
+
// Schema Version: 21
|
|
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 = 21
|
|
10
10
|
|
|
11
11
|
// eslint-disable-next-line no-unused-vars
|
|
12
12
|
let version = VERSION
|
|
@@ -491,7 +491,8 @@ const encoding11 = {
|
|
|
491
491
|
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
|
|
492
492
|
((version >= 11 && m.capability) ? 67108864 : 0) |
|
|
493
493
|
((version >= 11 && m.arguments) ? 134217728 : 0) |
|
|
494
|
-
((version >= 12 && m.enhance) ? 268435456 : 0)
|
|
494
|
+
((version >= 12 && m.enhance) ? 268435456 : 0) |
|
|
495
|
+
((version >= 20 && m.session) ? 536870912 : 0)
|
|
495
496
|
|
|
496
497
|
encoding10.preencode(state, m.type)
|
|
497
498
|
c.uint.preencode(state, flags)
|
|
@@ -522,6 +523,7 @@ const encoding11 = {
|
|
|
522
523
|
if (version >= 11 && m.capability) c.string.preencode(state, m.capability)
|
|
523
524
|
if (version >= 11 && m.arguments) c.json.preencode(state, m.arguments)
|
|
524
525
|
if (version >= 12 && m.enhance) c.string.preencode(state, m.enhance)
|
|
526
|
+
if (version >= 20 && m.session) c.string.preencode(state, m.session)
|
|
525
527
|
},
|
|
526
528
|
encode(state, m) {
|
|
527
529
|
const flags =
|
|
@@ -553,7 +555,8 @@ const encoding11 = {
|
|
|
553
555
|
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
|
|
554
556
|
((version >= 11 && m.capability) ? 67108864 : 0) |
|
|
555
557
|
((version >= 11 && m.arguments) ? 134217728 : 0) |
|
|
556
|
-
((version >= 12 && m.enhance) ? 268435456 : 0)
|
|
558
|
+
((version >= 12 && m.enhance) ? 268435456 : 0) |
|
|
559
|
+
((version >= 20 && m.session) ? 536870912 : 0)
|
|
557
560
|
|
|
558
561
|
encoding10.encode(state, m.type)
|
|
559
562
|
c.uint.encode(state, flags)
|
|
@@ -584,6 +587,7 @@ const encoding11 = {
|
|
|
584
587
|
if (version >= 11 && m.capability) c.string.encode(state, m.capability)
|
|
585
588
|
if (version >= 11 && m.arguments) c.json.encode(state, m.arguments)
|
|
586
589
|
if (version >= 12 && m.enhance) c.string.encode(state, m.enhance)
|
|
590
|
+
if (version >= 20 && m.session) c.string.encode(state, m.session)
|
|
587
591
|
},
|
|
588
592
|
decode(state) {
|
|
589
593
|
const r0 = encoding10.decode(state)
|
|
@@ -619,7 +623,8 @@ const encoding11 = {
|
|
|
619
623
|
captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0),
|
|
620
624
|
capability: (version >= 11 && (flags & 67108864) !== 0) ? c.string.decode(state) : null,
|
|
621
625
|
arguments: (version >= 11 && (flags & 134217728) !== 0) ? c.json.decode(state) : null,
|
|
622
|
-
enhance: (version >= 12 && (flags & 268435456) !== 0) ? c.string.decode(state) : null
|
|
626
|
+
enhance: (version >= 12 && (flags & 268435456) !== 0) ? c.string.decode(state) : null,
|
|
627
|
+
session: (version >= 20 && (flags & 536870912) !== 0) ? c.string.decode(state) : null
|
|
623
628
|
}
|
|
624
629
|
}
|
|
625
630
|
}
|
|
@@ -1497,7 +1502,8 @@ const encoding28 = {
|
|
|
1497
1502
|
(m.surfaceWhenUnsupported ? 256 : 0) |
|
|
1498
1503
|
(m.minCapabilityProfile ? 512 : 0) |
|
|
1499
1504
|
(m.emoji ? 1024 : 0) |
|
|
1500
|
-
(m.setupV2 ? 2048 : 0)
|
|
1505
|
+
(m.setupV2 ? 2048 : 0) |
|
|
1506
|
+
((version >= 21 && m.displayName) ? 4096 : 0)
|
|
1501
1507
|
|
|
1502
1508
|
c.string.preencode(state, m.name)
|
|
1503
1509
|
c.string.preencode(state, m.description)
|
|
@@ -1514,6 +1520,7 @@ const encoding28 = {
|
|
|
1514
1520
|
if (m.minCapabilityProfile) c.string.preencode(state, m.minCapabilityProfile)
|
|
1515
1521
|
if (m.emoji) c.string.preencode(state, m.emoji)
|
|
1516
1522
|
if (m.setupV2) encoding28_14.preencode(state, m.setupV2)
|
|
1523
|
+
if (version >= 21 && m.displayName) c.string.preencode(state, m.displayName)
|
|
1517
1524
|
},
|
|
1518
1525
|
encode(state, m) {
|
|
1519
1526
|
const flags =
|
|
@@ -1528,7 +1535,8 @@ const encoding28 = {
|
|
|
1528
1535
|
(m.surfaceWhenUnsupported ? 256 : 0) |
|
|
1529
1536
|
(m.minCapabilityProfile ? 512 : 0) |
|
|
1530
1537
|
(m.emoji ? 1024 : 0) |
|
|
1531
|
-
(m.setupV2 ? 2048 : 0)
|
|
1538
|
+
(m.setupV2 ? 2048 : 0) |
|
|
1539
|
+
((version >= 21 && m.displayName) ? 4096 : 0)
|
|
1532
1540
|
|
|
1533
1541
|
c.string.encode(state, m.name)
|
|
1534
1542
|
c.string.encode(state, m.description)
|
|
@@ -1545,6 +1553,7 @@ const encoding28 = {
|
|
|
1545
1553
|
if (m.minCapabilityProfile) c.string.encode(state, m.minCapabilityProfile)
|
|
1546
1554
|
if (m.emoji) c.string.encode(state, m.emoji)
|
|
1547
1555
|
if (m.setupV2) encoding28_14.encode(state, m.setupV2)
|
|
1556
|
+
if (version >= 21 && m.displayName) c.string.encode(state, m.displayName)
|
|
1548
1557
|
},
|
|
1549
1558
|
decode(state) {
|
|
1550
1559
|
const r0 = c.string.decode(state)
|
|
@@ -1566,7 +1575,8 @@ const encoding28 = {
|
|
|
1566
1575
|
surfaceWhenUnsupported: (flags & 256) !== 0,
|
|
1567
1576
|
minCapabilityProfile: (flags & 512) !== 0 ? c.string.decode(state) : null,
|
|
1568
1577
|
emoji: (flags & 1024) !== 0 ? c.string.decode(state) : null,
|
|
1569
|
-
setupV2: (flags & 2048) !== 0 ? encoding28_14.decode(state) : null
|
|
1578
|
+
setupV2: (flags & 2048) !== 0 ? encoding28_14.decode(state) : null,
|
|
1579
|
+
displayName: (version >= 21 && (flags & 4096) !== 0) ? c.string.decode(state) : null
|
|
1570
1580
|
}
|
|
1571
1581
|
}
|
|
1572
1582
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// This file is autogenerated by the hyperschema compiler
|
|
2
|
-
// Schema Version:
|
|
2
|
+
// Schema Version: 21
|
|
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 = 21
|
|
10
10
|
|
|
11
11
|
// eslint-disable-next-line no-unused-vars
|
|
12
12
|
let version = VERSION
|
|
@@ -491,7 +491,8 @@ const encoding11 = {
|
|
|
491
491
|
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
|
|
492
492
|
((version >= 11 && m.capability) ? 67108864 : 0) |
|
|
493
493
|
((version >= 11 && m.arguments) ? 134217728 : 0) |
|
|
494
|
-
((version >= 12 && m.enhance) ? 268435456 : 0)
|
|
494
|
+
((version >= 12 && m.enhance) ? 268435456 : 0) |
|
|
495
|
+
((version >= 20 && m.session) ? 536870912 : 0)
|
|
495
496
|
|
|
496
497
|
encoding10.preencode(state, m.type)
|
|
497
498
|
c.uint.preencode(state, flags)
|
|
@@ -522,6 +523,7 @@ const encoding11 = {
|
|
|
522
523
|
if (version >= 11 && m.capability) c.string.preencode(state, m.capability)
|
|
523
524
|
if (version >= 11 && m.arguments) c.json.preencode(state, m.arguments)
|
|
524
525
|
if (version >= 12 && m.enhance) c.string.preencode(state, m.enhance)
|
|
526
|
+
if (version >= 20 && m.session) c.string.preencode(state, m.session)
|
|
525
527
|
},
|
|
526
528
|
encode(state, m) {
|
|
527
529
|
const flags =
|
|
@@ -553,7 +555,8 @@ const encoding11 = {
|
|
|
553
555
|
((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0) |
|
|
554
556
|
((version >= 11 && m.capability) ? 67108864 : 0) |
|
|
555
557
|
((version >= 11 && m.arguments) ? 134217728 : 0) |
|
|
556
|
-
((version >= 12 && m.enhance) ? 268435456 : 0)
|
|
558
|
+
((version >= 12 && m.enhance) ? 268435456 : 0) |
|
|
559
|
+
((version >= 20 && m.session) ? 536870912 : 0)
|
|
557
560
|
|
|
558
561
|
encoding10.encode(state, m.type)
|
|
559
562
|
c.uint.encode(state, flags)
|
|
@@ -584,6 +587,7 @@ const encoding11 = {
|
|
|
584
587
|
if (version >= 11 && m.capability) c.string.encode(state, m.capability)
|
|
585
588
|
if (version >= 11 && m.arguments) c.json.encode(state, m.arguments)
|
|
586
589
|
if (version >= 12 && m.enhance) c.string.encode(state, m.enhance)
|
|
590
|
+
if (version >= 20 && m.session) c.string.encode(state, m.session)
|
|
587
591
|
},
|
|
588
592
|
decode(state) {
|
|
589
593
|
const r0 = encoding10.decode(state)
|
|
@@ -619,7 +623,8 @@ const encoding11 = {
|
|
|
619
623
|
captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0),
|
|
620
624
|
capability: (version >= 11 && (flags & 67108864) !== 0) ? c.string.decode(state) : null,
|
|
621
625
|
arguments: (version >= 11 && (flags & 134217728) !== 0) ? c.json.decode(state) : null,
|
|
622
|
-
enhance: (version >= 12 && (flags & 268435456) !== 0) ? c.string.decode(state) : null
|
|
626
|
+
enhance: (version >= 12 && (flags & 268435456) !== 0) ? c.string.decode(state) : null,
|
|
627
|
+
session: (version >= 20 && (flags & 536870912) !== 0) ? c.string.decode(state) : null
|
|
623
628
|
}
|
|
624
629
|
}
|
|
625
630
|
}
|
|
@@ -1497,7 +1502,8 @@ const encoding28 = {
|
|
|
1497
1502
|
(m.surfaceWhenUnsupported ? 256 : 0) |
|
|
1498
1503
|
(m.minCapabilityProfile ? 512 : 0) |
|
|
1499
1504
|
(m.emoji ? 1024 : 0) |
|
|
1500
|
-
(m.setupV2 ? 2048 : 0)
|
|
1505
|
+
(m.setupV2 ? 2048 : 0) |
|
|
1506
|
+
((version >= 21 && m.displayName) ? 4096 : 0)
|
|
1501
1507
|
|
|
1502
1508
|
c.string.preencode(state, m.name)
|
|
1503
1509
|
c.string.preencode(state, m.description)
|
|
@@ -1514,6 +1520,7 @@ const encoding28 = {
|
|
|
1514
1520
|
if (m.minCapabilityProfile) c.string.preencode(state, m.minCapabilityProfile)
|
|
1515
1521
|
if (m.emoji) c.string.preencode(state, m.emoji)
|
|
1516
1522
|
if (m.setupV2) encoding28_14.preencode(state, m.setupV2)
|
|
1523
|
+
if (version >= 21 && m.displayName) c.string.preencode(state, m.displayName)
|
|
1517
1524
|
},
|
|
1518
1525
|
encode(state, m) {
|
|
1519
1526
|
const flags =
|
|
@@ -1528,7 +1535,8 @@ const encoding28 = {
|
|
|
1528
1535
|
(m.surfaceWhenUnsupported ? 256 : 0) |
|
|
1529
1536
|
(m.minCapabilityProfile ? 512 : 0) |
|
|
1530
1537
|
(m.emoji ? 1024 : 0) |
|
|
1531
|
-
(m.setupV2 ? 2048 : 0)
|
|
1538
|
+
(m.setupV2 ? 2048 : 0) |
|
|
1539
|
+
((version >= 21 && m.displayName) ? 4096 : 0)
|
|
1532
1540
|
|
|
1533
1541
|
c.string.encode(state, m.name)
|
|
1534
1542
|
c.string.encode(state, m.description)
|
|
@@ -1545,6 +1553,7 @@ const encoding28 = {
|
|
|
1545
1553
|
if (m.minCapabilityProfile) c.string.encode(state, m.minCapabilityProfile)
|
|
1546
1554
|
if (m.emoji) c.string.encode(state, m.emoji)
|
|
1547
1555
|
if (m.setupV2) encoding28_14.encode(state, m.setupV2)
|
|
1556
|
+
if (version >= 21 && m.displayName) c.string.encode(state, m.displayName)
|
|
1548
1557
|
},
|
|
1549
1558
|
decode(state) {
|
|
1550
1559
|
const r0 = c.string.decode(state)
|
|
@@ -1566,7 +1575,8 @@ const encoding28 = {
|
|
|
1566
1575
|
surfaceWhenUnsupported: (flags & 256) !== 0,
|
|
1567
1576
|
minCapabilityProfile: (flags & 512) !== 0 ? c.string.decode(state) : null,
|
|
1568
1577
|
emoji: (flags & 1024) !== 0 ? c.string.decode(state) : null,
|
|
1569
|
-
setupV2: (flags & 2048) !== 0 ? encoding28_14.decode(state) : null
|
|
1578
|
+
setupV2: (flags & 2048) !== 0 ? encoding28_14.decode(state) : null,
|
|
1579
|
+
displayName: (version >= 21 && (flags & 4096) !== 0) ? c.string.decode(state) : null
|
|
1570
1580
|
}
|
|
1571
1581
|
}
|
|
1572
1582
|
}
|