@asterxsk/kiln 0.4.0 → 0.4.2
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/README.md +155 -155
- package/agent/AGENTS.md +67 -67
- package/agent/README.md +5 -5
- package/agent/extensions/ask-user/index.ts +418 -418
- package/agent/extensions/ask-user/install.ps1 +27 -27
- package/agent/extensions/ask-user/install.sh +24 -24
- package/agent/extensions/ask-user/package-lock.json +769 -769
- package/agent/extensions/ask-user/package.json +19 -19
- package/agent/extensions/ask-user/prompt.ts +45 -45
- package/agent/extensions/ask-user/tsconfig.json +7 -7
- package/agent/extensions/background-terminals/docs/implementation-guide.md +942 -942
- package/agent/extensions/background-terminals/index.ts +627 -627
- package/agent/extensions/background-terminals/install.ps1 +27 -27
- package/agent/extensions/background-terminals/install.sh +24 -24
- package/agent/extensions/background-terminals/manager.test.ts +735 -735
- package/agent/extensions/background-terminals/output.test.ts +109 -109
- package/agent/extensions/background-terminals/package-lock.json +769 -769
- package/agent/extensions/background-terminals/package.json +17 -17
- package/agent/extensions/background-terminals/prompt.test.ts +125 -125
- package/agent/extensions/background-terminals/ps.test.ts +82 -82
- package/agent/extensions/background-terminals/result-delivery.test.ts +44 -44
- package/agent/extensions/background-terminals/src/domain.ts +87 -87
- package/agent/extensions/background-terminals/src/manager.ts +907 -907
- package/agent/extensions/background-terminals/src/output.ts +84 -84
- package/agent/extensions/background-terminals/src/prompt.ts +142 -142
- package/agent/extensions/background-terminals/src/result-delivery.ts +27 -27
- package/agent/extensions/background-terminals/src/runtime.ts +36 -36
- package/agent/extensions/background-terminals/src/ui/output-view.ts +79 -79
- package/agent/extensions/background-terminals/src/ui/ps.ts +621 -621
- package/agent/extensions/background-terminals/tsconfig.json +7 -7
- package/agent/extensions/destructive/README.md +31 -31
- package/agent/extensions/destructive/index.ts +88 -88
- package/agent/extensions/destructive/install.ps1 +27 -27
- package/agent/extensions/destructive/install.sh +24 -24
- package/agent/extensions/file-search/index.spec.ts +443 -443
- package/agent/extensions/file-search/index.ts +459 -459
- package/agent/extensions/file-search/install.ps1 +27 -27
- package/agent/extensions/file-search/install.sh +24 -24
- package/agent/extensions/file-search/package-lock.json +2253 -2253
- package/agent/extensions/file-search/package.json +23 -23
- package/agent/extensions/file-search/src/args.ts +122 -122
- package/agent/extensions/file-search/src/binaries.ts +422 -422
- package/agent/extensions/file-search/src/output.ts +126 -126
- package/agent/extensions/file-search/src/process.ts +146 -146
- package/agent/extensions/file-search/src/prompt.ts +52 -52
- package/agent/extensions/file-search/tsconfig.json +7 -7
- package/agent/extensions/goal/README.md +50 -50
- package/agent/extensions/goal/index.ts +155 -155
- package/agent/extensions/goal/install.ps1 +27 -27
- package/agent/extensions/goal/install.sh +24 -24
- package/agent/extensions/kiln-update/README.md +38 -25
- package/agent/extensions/kiln-update/index.ts +177 -99
- package/agent/extensions/modelconf/PLAN.md +915 -915
- package/agent/extensions/modelconf/README.md +66 -66
- package/agent/extensions/modelconf/index.ts +296 -296
- package/agent/extensions/modelconf/install.ps1 +27 -27
- package/agent/extensions/modelconf/install.sh +24 -24
- package/agent/extensions/modelconf/package-lock.json +1809 -1809
- package/agent/extensions/modelconf/package.json +13 -13
- package/agent/extensions/modelconf/src/fuzzy.ts +26 -26
- package/agent/extensions/modelconf/src/glob.ts +13 -13
- package/agent/extensions/modelconf/src/persistence.test.ts +46 -46
- package/agent/extensions/modelconf/src/persistence.ts +164 -164
- package/agent/extensions/modelconf/src/ui/ModelConfView.test.ts +75 -75
- package/agent/extensions/modelconf/src/ui/ModelConfView.ts +1101 -1101
- package/agent/extensions/modelconf/tsconfig.json +15 -15
- package/agent/extensions/pi-web-access/CHANGELOG.md +690 -690
- package/agent/extensions/pi-web-access/LICENSE +21 -21
- package/agent/extensions/pi-web-access/README.md +470 -470
- package/agent/extensions/pi-web-access/SECURITY.md +5 -5
- package/agent/extensions/pi-web-access/activity.ts +101 -101
- package/agent/extensions/pi-web-access/auth-fetch.ts +148 -148
- package/agent/extensions/pi-web-access/brightdata-unlocker.ts +272 -272
- package/agent/extensions/pi-web-access/chrome-cookies.ts +669 -669
- package/agent/extensions/pi-web-access/content-find.ts +139 -139
- package/agent/extensions/pi-web-access/credential-source.ts +191 -191
- package/agent/extensions/pi-web-access/data-uri-sanitize.ts +406 -406
- package/agent/extensions/pi-web-access/datalab-pdf-extract.ts +568 -568
- package/agent/extensions/pi-web-access/declared-web-links.ts +173 -173
- package/agent/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +496 -496
- package/agent/extensions/pi-web-access/evidence/contract-probe.mjs +140 -140
- package/agent/extensions/pi-web-access/exa.ts +526 -526
- package/agent/extensions/pi-web-access/extract.ts +1196 -1196
- package/agent/extensions/pi-web-access/feature-config.ts +29 -29
- package/agent/extensions/pi-web-access/fetch-params.ts +111 -111
- package/agent/extensions/pi-web-access/gemini-adc.ts +298 -298
- package/agent/extensions/pi-web-access/gemini-api.ts +353 -353
- package/agent/extensions/pi-web-access/gemini-pdf-extract.ts +108 -108
- package/agent/extensions/pi-web-access/gemini-search.ts +21 -21
- package/agent/extensions/pi-web-access/gemini-url-context.ts +128 -128
- package/agent/extensions/pi-web-access/gemini-web-config.ts +101 -101
- package/agent/extensions/pi-web-access/gemini-web.ts +487 -487
- package/agent/extensions/pi-web-access/github-api.ts +197 -197
- package/agent/extensions/pi-web-access/github-extract.ts +746 -746
- package/agent/extensions/pi-web-access/github-issue-pr.ts +700 -700
- package/agent/extensions/pi-web-access/index.ts +1737 -1737
- package/agent/extensions/pi-web-access/package-lock.json +5808 -5808
- package/agent/extensions/pi-web-access/package.json +64 -64
- package/agent/extensions/pi-web-access/page-query.ts +96 -96
- package/agent/extensions/pi-web-access/pdf-extract.ts +409 -409
- package/agent/extensions/pi-web-access/promise-try.d.ts +7 -7
- package/agent/extensions/pi-web-access/query-rewrite.ts +51 -51
- package/agent/extensions/pi-web-access/render-search-error.ts +170 -170
- package/agent/extensions/pi-web-access/rsc-extract.ts +338 -338
- package/agent/extensions/pi-web-access/search-types.ts +20 -20
- package/agent/extensions/pi-web-access/source-check.ts +282 -282
- package/agent/extensions/pi-web-access/ssrf-protection.ts +526 -526
- package/agent/extensions/pi-web-access/storage.ts +521 -521
- package/agent/extensions/pi-web-access/summary-model-scope.ts +125 -125
- package/agent/extensions/pi-web-access/test/auth-fetch.test.mjs +208 -208
- package/agent/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +840 -840
- package/agent/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +441 -441
- package/agent/extensions/pi-web-access/test/config-path.test.mjs +283 -283
- package/agent/extensions/pi-web-access/test/content-find.test.mjs +25 -25
- package/agent/extensions/pi-web-access/test/credential-source.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +210 -210
- package/agent/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +552 -552
- package/agent/extensions/pi-web-access/test/declared-web-links.test.mjs +212 -212
- package/agent/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +40 -40
- package/agent/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +334 -334
- package/agent/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +95 -95
- package/agent/extensions/pi-web-access/test/fetch-modes.test.mjs +53 -53
- package/agent/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +92 -92
- package/agent/extensions/pi-web-access/test/fetch-params.test.mjs +86 -86
- package/agent/extensions/pi-web-access/test/fetch-render-call.test.mjs +34 -34
- package/agent/extensions/pi-web-access/test/fetch-routing.test.mjs +173 -173
- package/agent/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +257 -257
- package/agent/extensions/pi-web-access/test/gemini-api-transport.test.mjs +170 -170
- package/agent/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +133 -133
- package/agent/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +178 -178
- package/agent/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +148 -148
- package/agent/extensions/pi-web-access/test/get-search-content.test.mjs +223 -223
- package/agent/extensions/pi-web-access/test/github-extract.test.mjs +378 -378
- package/agent/extensions/pi-web-access/test/github-issue-pr.test.mjs +565 -565
- package/agent/extensions/pi-web-access/test/inline-content-config.test.mjs +99 -99
- package/agent/extensions/pi-web-access/test/lazy-extract-load.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/local-video-oversize.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +50 -50
- package/agent/extensions/pi-web-access/test/page-query.test.mjs +51 -51
- package/agent/extensions/pi-web-access/test/pdf-config.test.mjs +140 -140
- package/agent/extensions/pi-web-access/test/pdf-extract.test.mjs +500 -500
- package/agent/extensions/pi-web-access/test/proxy-transport.test.mjs +286 -286
- package/agent/extensions/pi-web-access/test/query-rewrite.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/rsc-fallback.test.mjs +102 -102
- package/agent/extensions/pi-web-access/test/search-error-render.test.mjs +152 -152
- package/agent/extensions/pi-web-access/test/search-providers.test.mjs +274 -274
- package/agent/extensions/pi-web-access/test/source-check.test.mjs +179 -179
- package/agent/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +205 -205
- package/agent/extensions/pi-web-access/test/ssrf-protection.test.mjs +456 -456
- package/agent/extensions/pi-web-access/test/summary-model-scope.test.mjs +106 -106
- package/agent/extensions/pi-web-access/test/tool-registration-config.test.mjs +182 -182
- package/agent/extensions/pi-web-access/test/web-search-answer-render.test.mjs +66 -66
- package/agent/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +64 -64
- package/agent/extensions/pi-web-access/tsconfig.json +11 -11
- package/agent/extensions/pi-web-access/utils.ts +451 -451
- package/agent/extensions/pi-web-access/video-extract.ts +392 -392
- package/agent/extensions/pi-web-access/youtube-extract.ts +328 -328
- package/agent/extensions/shared/activity-status.ts +31 -31
- package/agent/extensions/shared/child-session.test.ts +270 -270
- package/agent/extensions/shared/child-session.ts +148 -148
- package/agent/extensions/shared/context-utilization.test.ts +48 -48
- package/agent/extensions/shared/context-utilization.ts +47 -47
- package/agent/extensions/shared/dashboard-state.ts +99 -99
- package/agent/extensions/shared/install.ps1 +27 -27
- package/agent/extensions/shared/install.sh +24 -24
- package/agent/extensions/shared/tool-call-timeout.test.ts +117 -117
- package/agent/extensions/shared/tool-call-timeout.ts +104 -104
- package/agent/extensions/skillsconf/README.md +74 -74
- package/agent/extensions/skillsconf/index.ts +92 -92
- package/agent/extensions/skillsconf/install.ps1 +27 -27
- package/agent/extensions/skillsconf/install.sh +24 -24
- package/agent/extensions/skillsconf/package-lock.json +1809 -1809
- package/agent/extensions/skillsconf/package.json +18 -18
- package/agent/extensions/skillsconf/src/delete-skill.test.ts +64 -64
- package/agent/extensions/skillsconf/src/delete-skill.ts +45 -45
- package/agent/extensions/skillsconf/src/filter.test.ts +80 -80
- package/agent/extensions/skillsconf/src/filter.ts +74 -74
- package/agent/extensions/skillsconf/src/fuzzy.ts +26 -26
- package/agent/extensions/skillsconf/src/persistence.test.ts +72 -72
- package/agent/extensions/skillsconf/src/persistence.ts +169 -169
- package/agent/extensions/skillsconf/src/ui/SkillConfView.test.ts +337 -337
- package/agent/extensions/skillsconf/src/ui/SkillConfView.ts +758 -758
- package/agent/extensions/skillsconf/src/ui/text-input.ts +91 -91
- package/agent/extensions/skillsconf/src/ui/tui-helpers.ts +144 -144
- package/agent/extensions/skillsconf/tsconfig.json +15 -15
- package/agent/extensions/statusline/index.ts +273 -282
- package/agent/extensions/statusline/install.ps1 +27 -27
- package/agent/extensions/statusline/install.sh +24 -24
- package/agent/extensions/subagents/by-the-way.test.ts +29 -29
- package/agent/extensions/subagents/claude.test.ts +119 -119
- package/agent/extensions/subagents/codex.test.ts +102 -102
- package/agent/extensions/subagents/context-usage.test.ts +107 -107
- package/agent/extensions/subagents/docs/design-plan.md +568 -568
- package/agent/extensions/subagents/docs/effect-v4-extension-guide.md +354 -354
- package/agent/extensions/subagents/docs/effect-v4-notes.md +571 -571
- package/agent/extensions/subagents/index.ts +779 -779
- package/agent/extensions/subagents/install.ps1 +27 -27
- package/agent/extensions/subagents/install.sh +24 -24
- package/agent/extensions/subagents/manager.test.ts +276 -276
- package/agent/extensions/subagents/package-lock.json +2244 -2244
- package/agent/extensions/subagents/package.json +19 -19
- package/agent/extensions/subagents/result-delivery.test.ts +27 -27
- package/agent/extensions/subagents/src/backend.ts +73 -73
- package/agent/extensions/subagents/src/backends/claude.ts +701 -701
- package/agent/extensions/subagents/src/backends/codex.ts +1060 -1060
- package/agent/extensions/subagents/src/backends/pi.ts +575 -575
- package/agent/extensions/subagents/src/backends/stub.ts +300 -300
- package/agent/extensions/subagents/src/by-the-way.ts +21 -21
- package/agent/extensions/subagents/src/domain.ts +253 -253
- package/agent/extensions/subagents/src/format.ts +74 -74
- package/agent/extensions/subagents/src/manager.ts +736 -736
- package/agent/extensions/subagents/src/prompt.ts +92 -92
- package/agent/extensions/subagents/src/result-delivery.ts +20 -20
- package/agent/extensions/subagents/src/runtime.ts +53 -53
- package/agent/extensions/subagents/src/ui/takeover.ts +583 -583
- package/agent/extensions/subagents/src/ui/transcript.ts +201 -201
- package/agent/extensions/subagents/takeover.test.ts +29 -29
- package/agent/extensions/subagents/tsconfig.json +7 -7
- package/agent/extensions/todo/AGENTS.md +38 -38
- package/agent/extensions/todo/LICENSE +21 -21
- package/agent/extensions/todo/config.ts +55 -55
- package/agent/extensions/todo/index.ts +151 -151
- package/agent/extensions/todo/install.ps1 +27 -27
- package/agent/extensions/todo/install.sh +24 -24
- package/agent/extensions/todo/locales/de.json +17 -17
- package/agent/extensions/todo/locales/en.json +15 -15
- package/agent/extensions/todo/locales/es.json +17 -17
- package/agent/extensions/todo/locales/fr.json +17 -17
- package/agent/extensions/todo/locales/pt-BR.json +17 -17
- package/agent/extensions/todo/locales/pt.json +17 -17
- package/agent/extensions/todo/locales/ru.json +17 -17
- package/agent/extensions/todo/locales/uk.json +17 -17
- package/agent/extensions/todo/locales/zh.json +17 -17
- package/agent/extensions/todo/package-lock.json +3358 -3358
- package/agent/extensions/todo/package.json +67 -67
- package/agent/extensions/todo/state/i18n-bridge.ts +64 -64
- package/agent/extensions/todo/state/invariants.ts +20 -20
- package/agent/extensions/todo/state/replay.ts +38 -38
- package/agent/extensions/todo/state/selectors.ts +107 -107
- package/agent/extensions/todo/state/state-reducer.ts +326 -326
- package/agent/extensions/todo/state/state.ts +18 -18
- package/agent/extensions/todo/state/store.ts +82 -82
- package/agent/extensions/todo/state/task-graph.ts +57 -57
- package/agent/extensions/todo/todo-overlay.ts +200 -200
- package/agent/extensions/todo/todo.ts +155 -155
- package/agent/extensions/todo/tool/response-envelope.ts +109 -109
- package/agent/extensions/todo/tool/types.ts +206 -206
- package/agent/extensions/todo/view/format.ts +177 -177
- package/agent/extensions/trim-context/README.md +54 -54
- package/agent/extensions/trim-context/index.ts +487 -487
- package/agent/extensions/trim-context/install.ps1 +27 -27
- package/agent/extensions/trim-context/install.sh +24 -24
- package/agent/keybindings.json +7 -7
- package/agent/version.txt +1 -1
- package/bin/kiln.js +20 -13
- package/package.json +1 -1
- package/agent/extensions/taste/index.ts +0 -443
- package/agent/extensions/taste/install.ps1 +0 -27
- package/agent/extensions/taste/install.sh +0 -24
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { test } from "node:test";
|
|
7
|
-
|
|
8
|
-
import { findModelWithProviderRouting, loadEnabledModelPatterns, modelMatchesEnabledPatterns } from "../summary-model-scope.ts";
|
|
9
|
-
|
|
10
|
-
const queryRewriteSrc = readFileSync(new URL("../query-rewrite.ts", import.meta.url), "utf8");
|
|
11
|
-
|
|
12
|
-
test("summary model scope matches nested provider model ids and thinking suffixes", () => {
|
|
13
|
-
assert.equal(
|
|
14
|
-
modelMatchesEnabledPatterns(
|
|
15
|
-
{ provider: "openrouter", id: "nvidia/nemotron-3-super-120b-a12b:free" },
|
|
16
|
-
["openrouter/nvidia/nemotron-3-super-120b-a12b:free"],
|
|
17
|
-
),
|
|
18
|
-
true,
|
|
19
|
-
);
|
|
20
|
-
assert.equal(
|
|
21
|
-
modelMatchesEnabledPatterns(
|
|
22
|
-
{ provider: "openrouter", id: "anthropic/claude-sonnet-4" },
|
|
23
|
-
["openrouter/*:low"],
|
|
24
|
-
),
|
|
25
|
-
true,
|
|
26
|
-
);
|
|
27
|
-
assert.equal(
|
|
28
|
-
modelMatchesEnabledPatterns(
|
|
29
|
-
{ provider: "openrouter", id: "ai21/jamba-large-1.7" },
|
|
30
|
-
["openrouter/nvidia/*"],
|
|
31
|
-
),
|
|
32
|
-
false,
|
|
33
|
-
);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test("preferred models resolve through routed providers", () => {
|
|
37
|
-
const routedModel = { provider: "openrouter", id: "anthropic/claude-haiku-4-5" };
|
|
38
|
-
const registry = {
|
|
39
|
-
find: () => undefined,
|
|
40
|
-
getAvailable: () => [routedModel],
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
assert.equal(
|
|
44
|
-
findModelWithProviderRouting(registry, "anthropic", "claude-haiku-4-5"),
|
|
45
|
-
routedModel,
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("model resolution preserves the direct registry fallback", () => {
|
|
50
|
-
const configuredModel = { provider: "anthropic", id: "claude-haiku-4-5" };
|
|
51
|
-
const registry = {
|
|
52
|
-
find: () => configuredModel,
|
|
53
|
-
getAvailable: () => [],
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
assert.equal(
|
|
57
|
-
findModelWithProviderRouting(registry, "anthropic", "claude-haiku-4-5"),
|
|
58
|
-
configuredModel,
|
|
59
|
-
);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("routed model resolution follows available-model ordering", () => {
|
|
63
|
-
const firstRoute = { provider: "openrouter", id: "anthropic/claude-haiku-4-5" };
|
|
64
|
-
const secondRoute = { provider: "requesty", id: "anthropic/claude-haiku-4-5" };
|
|
65
|
-
const registry = {
|
|
66
|
-
find: () => undefined,
|
|
67
|
-
getAvailable: () => [firstRoute, secondRoute],
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
assert.equal(
|
|
71
|
-
findModelWithProviderRouting(registry, "anthropic", "claude-haiku-4-5"),
|
|
72
|
-
firstRoute,
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("enabledModels loading uses trusted project settings over global settings", async () => {
|
|
77
|
-
const agentDir = await mkdtemp(join(tmpdir(), "pi-web-access-agent-"));
|
|
78
|
-
const projectDir = await mkdtemp(join(tmpdir(), "pi-web-access-project-"));
|
|
79
|
-
await writeFile(join(agentDir, "settings.json"), JSON.stringify({ enabledModels: ["global/model"] }));
|
|
80
|
-
await mkdir(join(projectDir, ".pi"));
|
|
81
|
-
await writeFile(join(projectDir, ".pi", "settings.json"), JSON.stringify({ enabledModels: ["project/model"] }));
|
|
82
|
-
|
|
83
|
-
const previous = process.env.PI_CODING_AGENT_DIR;
|
|
84
|
-
process.env.PI_CODING_AGENT_DIR = agentDir;
|
|
85
|
-
try {
|
|
86
|
-
assert.deepEqual(
|
|
87
|
-
loadEnabledModelPatterns({ cwd: projectDir, isProjectTrusted: () => true }),
|
|
88
|
-
["project/model"],
|
|
89
|
-
);
|
|
90
|
-
assert.deepEqual(
|
|
91
|
-
loadEnabledModelPatterns({ cwd: projectDir, isProjectTrusted: () => false }),
|
|
92
|
-
["global/model"],
|
|
93
|
-
);
|
|
94
|
-
} finally {
|
|
95
|
-
if (previous === undefined) {
|
|
96
|
-
delete process.env.PI_CODING_AGENT_DIR;
|
|
97
|
-
} else {
|
|
98
|
-
process.env.PI_CODING_AGENT_DIR = previous;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test("query rewrite defaults use the refreshed model order", () => {
|
|
104
|
-
assert.match(queryRewriteSrc, /id: "gpt-5-mini"/);
|
|
105
|
-
assert.doesNotMatch(queryRewriteSrc, /gpt-4\.1-mini/);
|
|
106
|
-
});
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { test } from "node:test";
|
|
7
|
+
|
|
8
|
+
import { findModelWithProviderRouting, loadEnabledModelPatterns, modelMatchesEnabledPatterns } from "../summary-model-scope.ts";
|
|
9
|
+
|
|
10
|
+
const queryRewriteSrc = readFileSync(new URL("../query-rewrite.ts", import.meta.url), "utf8");
|
|
11
|
+
|
|
12
|
+
test("summary model scope matches nested provider model ids and thinking suffixes", () => {
|
|
13
|
+
assert.equal(
|
|
14
|
+
modelMatchesEnabledPatterns(
|
|
15
|
+
{ provider: "openrouter", id: "nvidia/nemotron-3-super-120b-a12b:free" },
|
|
16
|
+
["openrouter/nvidia/nemotron-3-super-120b-a12b:free"],
|
|
17
|
+
),
|
|
18
|
+
true,
|
|
19
|
+
);
|
|
20
|
+
assert.equal(
|
|
21
|
+
modelMatchesEnabledPatterns(
|
|
22
|
+
{ provider: "openrouter", id: "anthropic/claude-sonnet-4" },
|
|
23
|
+
["openrouter/*:low"],
|
|
24
|
+
),
|
|
25
|
+
true,
|
|
26
|
+
);
|
|
27
|
+
assert.equal(
|
|
28
|
+
modelMatchesEnabledPatterns(
|
|
29
|
+
{ provider: "openrouter", id: "ai21/jamba-large-1.7" },
|
|
30
|
+
["openrouter/nvidia/*"],
|
|
31
|
+
),
|
|
32
|
+
false,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("preferred models resolve through routed providers", () => {
|
|
37
|
+
const routedModel = { provider: "openrouter", id: "anthropic/claude-haiku-4-5" };
|
|
38
|
+
const registry = {
|
|
39
|
+
find: () => undefined,
|
|
40
|
+
getAvailable: () => [routedModel],
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
assert.equal(
|
|
44
|
+
findModelWithProviderRouting(registry, "anthropic", "claude-haiku-4-5"),
|
|
45
|
+
routedModel,
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("model resolution preserves the direct registry fallback", () => {
|
|
50
|
+
const configuredModel = { provider: "anthropic", id: "claude-haiku-4-5" };
|
|
51
|
+
const registry = {
|
|
52
|
+
find: () => configuredModel,
|
|
53
|
+
getAvailable: () => [],
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
assert.equal(
|
|
57
|
+
findModelWithProviderRouting(registry, "anthropic", "claude-haiku-4-5"),
|
|
58
|
+
configuredModel,
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("routed model resolution follows available-model ordering", () => {
|
|
63
|
+
const firstRoute = { provider: "openrouter", id: "anthropic/claude-haiku-4-5" };
|
|
64
|
+
const secondRoute = { provider: "requesty", id: "anthropic/claude-haiku-4-5" };
|
|
65
|
+
const registry = {
|
|
66
|
+
find: () => undefined,
|
|
67
|
+
getAvailable: () => [firstRoute, secondRoute],
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
assert.equal(
|
|
71
|
+
findModelWithProviderRouting(registry, "anthropic", "claude-haiku-4-5"),
|
|
72
|
+
firstRoute,
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("enabledModels loading uses trusted project settings over global settings", async () => {
|
|
77
|
+
const agentDir = await mkdtemp(join(tmpdir(), "pi-web-access-agent-"));
|
|
78
|
+
const projectDir = await mkdtemp(join(tmpdir(), "pi-web-access-project-"));
|
|
79
|
+
await writeFile(join(agentDir, "settings.json"), JSON.stringify({ enabledModels: ["global/model"] }));
|
|
80
|
+
await mkdir(join(projectDir, ".pi"));
|
|
81
|
+
await writeFile(join(projectDir, ".pi", "settings.json"), JSON.stringify({ enabledModels: ["project/model"] }));
|
|
82
|
+
|
|
83
|
+
const previous = process.env.PI_CODING_AGENT_DIR;
|
|
84
|
+
process.env.PI_CODING_AGENT_DIR = agentDir;
|
|
85
|
+
try {
|
|
86
|
+
assert.deepEqual(
|
|
87
|
+
loadEnabledModelPatterns({ cwd: projectDir, isProjectTrusted: () => true }),
|
|
88
|
+
["project/model"],
|
|
89
|
+
);
|
|
90
|
+
assert.deepEqual(
|
|
91
|
+
loadEnabledModelPatterns({ cwd: projectDir, isProjectTrusted: () => false }),
|
|
92
|
+
["global/model"],
|
|
93
|
+
);
|
|
94
|
+
} finally {
|
|
95
|
+
if (previous === undefined) {
|
|
96
|
+
delete process.env.PI_CODING_AGENT_DIR;
|
|
97
|
+
} else {
|
|
98
|
+
process.env.PI_CODING_AGENT_DIR = previous;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("query rewrite defaults use the refreshed model order", () => {
|
|
104
|
+
assert.match(queryRewriteSrc, /id: "gpt-5-mini"/);
|
|
105
|
+
assert.doesNotMatch(queryRewriteSrc, /gpt-4\.1-mini/);
|
|
106
|
+
});
|
|
@@ -1,182 +1,182 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { test } from "node:test";
|
|
7
|
-
import { Value } from "typebox/value";
|
|
8
|
-
|
|
9
|
-
import initializeExtension from "../index.ts";
|
|
10
|
-
|
|
11
|
-
const indexUrl = new URL("../index.ts", import.meta.url).href;
|
|
12
|
-
const indexSrc = readFileSync(new URL("../index.ts", import.meta.url), "utf8");
|
|
13
|
-
const readmeSrc = readFileSync(new URL("../README.md", import.meta.url), "utf8");
|
|
14
|
-
|
|
15
|
-
function runRegistration(config) {
|
|
16
|
-
return runRegistrationWithConfig(JSON.stringify(config) + "\n");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function runRegistrationWithConfig(configText) {
|
|
20
|
-
const root = mkdtempSync(join(tmpdir(), "pi-web-access-tool-names-"));
|
|
21
|
-
writeFileSync(join(root, "web-search.json"), configText, "utf8");
|
|
22
|
-
return spawnSync(process.execPath, ["--input-type=module"], {
|
|
23
|
-
input: `
|
|
24
|
-
const { default: initializeExtension } = await import(${JSON.stringify(indexUrl)});
|
|
25
|
-
const tools = [];
|
|
26
|
-
const commands = [];
|
|
27
|
-
initializeExtension({
|
|
28
|
-
registerTool(tool) { tools.push({ name: tool.name, description: tool.description, promptSnippet: tool.promptSnippet, parameters: tool.parameters }); },
|
|
29
|
-
registerCommand(name) { commands.push(name); },
|
|
30
|
-
registerShortcut() {},
|
|
31
|
-
on() {},
|
|
32
|
-
});
|
|
33
|
-
console.log(JSON.stringify({ tools, commands }));
|
|
34
|
-
`,
|
|
35
|
-
encoding: "utf8",
|
|
36
|
-
env: { ...process.env, PI_CODING_AGENT_DIR: root, XDG_CONFIG_HOME: "", HOME: join(root, "home"), USERPROFILE: join(root, "home") },
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function registered(config) {
|
|
41
|
-
const child = runRegistration(config);
|
|
42
|
-
assert.equal(child.status, 0, child.stderr);
|
|
43
|
-
return JSON.parse(child.stdout);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function registeredToolNames(config) {
|
|
47
|
-
return registered(config).tools.map(tool => tool.name);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function registeredTool(config, name) {
|
|
51
|
-
return registered(config).tools.find(tool => tool.name === name);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function registeredCommandNames(config) {
|
|
55
|
-
return registered(config).commands;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function registrationError(config) {
|
|
59
|
-
const child = runRegistration(config);
|
|
60
|
-
assert.notEqual(child.status, 0, child.stdout);
|
|
61
|
-
return child.stderr;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
test("malformed config falls back during extension registration", () => {
|
|
65
|
-
const child = runRegistrationWithConfig("{");
|
|
66
|
-
assert.equal(child.status, 0, child.stderr);
|
|
67
|
-
const registered = JSON.parse(child.stdout);
|
|
68
|
-
assert.deepEqual(registered.tools.map(tool => tool.name), ["web_search", "source_check", "fetch_content", "get_search_content"]);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test("search tools constrain numResults to integer values from 1 through 20", () => {
|
|
72
|
-
for (const name of ["web_search", "source_check"]) {
|
|
73
|
-
const schema = registeredTool({}, name).parameters.properties.numResults;
|
|
74
|
-
assert.equal(schema.type, "integer");
|
|
75
|
-
assert.equal(schema.minimum, 1);
|
|
76
|
-
assert.equal(schema.maximum, 20);
|
|
77
|
-
for (const value of [0, -1, 1.5, 21, Number.NaN, Number.POSITIVE_INFINITY]) {
|
|
78
|
-
assert.equal(Value.Check(schema, value), false, `${name} accepts ${value}`);
|
|
79
|
-
}
|
|
80
|
-
for (const value of [1, 5, 20]) {
|
|
81
|
-
assert.equal(Value.Check(schema, value), true, `${name} rejects ${value}`);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("tool registration gates support legacy and per-tool config", () => {
|
|
87
|
-
assert.deepEqual(registeredToolNames({ webSearch: { enabled: false } }), ["fetch_content", "get_search_content"]);
|
|
88
|
-
assert.deepEqual(registeredToolNames({
|
|
89
|
-
webSearch: { enabled: false },
|
|
90
|
-
tools: { webSearch: { enabled: true }, sourceCheck: { enabled: true }, fetchContent: { enabled: false } },
|
|
91
|
-
}), ["web_search", "source_check", "get_search_content"]);
|
|
92
|
-
assert.deepEqual(registeredToolNames({
|
|
93
|
-
tools: { sourceCheck: { enabled: false }, getSearchContent: { enabled: false } },
|
|
94
|
-
}), ["web_search", "fetch_content"]);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("command registration gates default to enabled", () => {
|
|
98
|
-
assert.deepEqual(registeredCommandNames({}), ["google-account", "search"]);
|
|
99
|
-
assert.deepEqual(registeredCommandNames({
|
|
100
|
-
commands: { websearch: { enabled: false }, search: { enabled: false } },
|
|
101
|
-
}), ["google-account"]);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("fetch_content schema exposes auth profile opt-in", () => {
|
|
105
|
-
const schema = registeredTool({}, "fetch_content").parameters.properties.auth;
|
|
106
|
-
assert.ok(schema);
|
|
107
|
-
assert.deepEqual(schema.anyOf.map(option => option.type), ["string", "boolean"]);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("registered tools do not advertise disabled get_search_content", () => {
|
|
111
|
-
const fetchTool = registeredTool({ tools: { getSearchContent: { enabled: false } } }, "fetch_content");
|
|
112
|
-
assert.ok(fetchTool);
|
|
113
|
-
assert.doesNotMatch(fetchTool.description, /get_search_content/);
|
|
114
|
-
assert.match(fetchTool.description, /retrieval tool is not registered/);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test("web activity shortcut renders through the supported string-array API", async () => {
|
|
118
|
-
const shortcuts = [];
|
|
119
|
-
initializeExtension({
|
|
120
|
-
registerTool() {},
|
|
121
|
-
registerCommand() {},
|
|
122
|
-
registerShortcut(name, shortcut) { shortcuts.push({ name, shortcut }); },
|
|
123
|
-
on() {},
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const activityShortcut = shortcuts.find(({ shortcut }) => shortcut.description === "Toggle web search activity");
|
|
127
|
-
assert.ok(activityShortcut, "activity shortcut was not registered");
|
|
128
|
-
const widgets = [];
|
|
129
|
-
const ctx = {
|
|
130
|
-
ui: {
|
|
131
|
-
theme: { fg: (_color, text) => text },
|
|
132
|
-
setWidget(key, content) { widgets.push({ key, content }); },
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
await activityShortcut.shortcut.handler(ctx);
|
|
137
|
-
assert.equal(widgets[0].key, "web-activity");
|
|
138
|
-
assert.ok(Array.isArray(widgets[0].content), "activity widget content must be a string array");
|
|
139
|
-
assert.ok(widgets[0].content.length > 0);
|
|
140
|
-
|
|
141
|
-
await activityShortcut.shortcut.handler(ctx);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test("tool names can be configured without changing defaults", () => {
|
|
145
|
-
assert.deepEqual(registeredToolNames({}), ["web_search", "source_check", "fetch_content", "get_search_content"]);
|
|
146
|
-
assert.deepEqual(registeredToolNames({
|
|
147
|
-
toolNames: {
|
|
148
|
-
webSearch: "research_web",
|
|
149
|
-
sourceCheck: "verify_sources",
|
|
150
|
-
fetchContent: "grab_content",
|
|
151
|
-
getSearchContent: "open_content",
|
|
152
|
-
},
|
|
153
|
-
}), ["research_web", "verify_sources", "grab_content", "open_content"]);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test("tool name config rejects invalid and duplicate registered names", () => {
|
|
157
|
-
assert.match(registrationError({ toolNames: { webSearch: "1bad" } }), /toolNames\.webSearch/);
|
|
158
|
-
assert.match(registrationError({ toolNames: { webSearch: "same_name", fetchContent: "same_name" } }), /duplicates/);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
test("webSearch.enabled false registers only fetch tools and ignores disabled-name duplicates", () => {
|
|
162
|
-
assert.deepEqual(registeredToolNames({
|
|
163
|
-
webSearch: { enabled: false },
|
|
164
|
-
toolNames: {
|
|
165
|
-
webSearch: "content_only",
|
|
166
|
-
sourceCheck: "content_only",
|
|
167
|
-
fetchContent: "grab_content",
|
|
168
|
-
getSearchContent: "open_content",
|
|
169
|
-
},
|
|
170
|
-
}), ["grab_content", "open_content"]);
|
|
171
|
-
assert.match(registrationError({
|
|
172
|
-
webSearch: { enabled: false },
|
|
173
|
-
toolNames: { fetchContent: "same_name", getSearchContent: "same_name" },
|
|
174
|
-
}), /duplicates/);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test("README documents registration gates and toolNames", () => {
|
|
178
|
-
assert.match(readmeSrc, /"tools": \{/);
|
|
179
|
-
assert.match(readmeSrc, /"commands": \{/);
|
|
180
|
-
assert.match(readmeSrc, /Pi restart is required for tool and command registration changes/);
|
|
181
|
-
assert.match(readmeSrc, /`toolNames` can opt into alternate public tool names/);
|
|
182
|
-
});
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { test } from "node:test";
|
|
7
|
+
import { Value } from "typebox/value";
|
|
8
|
+
|
|
9
|
+
import initializeExtension from "../index.ts";
|
|
10
|
+
|
|
11
|
+
const indexUrl = new URL("../index.ts", import.meta.url).href;
|
|
12
|
+
const indexSrc = readFileSync(new URL("../index.ts", import.meta.url), "utf8");
|
|
13
|
+
const readmeSrc = readFileSync(new URL("../README.md", import.meta.url), "utf8");
|
|
14
|
+
|
|
15
|
+
function runRegistration(config) {
|
|
16
|
+
return runRegistrationWithConfig(JSON.stringify(config) + "\n");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function runRegistrationWithConfig(configText) {
|
|
20
|
+
const root = mkdtempSync(join(tmpdir(), "pi-web-access-tool-names-"));
|
|
21
|
+
writeFileSync(join(root, "web-search.json"), configText, "utf8");
|
|
22
|
+
return spawnSync(process.execPath, ["--input-type=module"], {
|
|
23
|
+
input: `
|
|
24
|
+
const { default: initializeExtension } = await import(${JSON.stringify(indexUrl)});
|
|
25
|
+
const tools = [];
|
|
26
|
+
const commands = [];
|
|
27
|
+
initializeExtension({
|
|
28
|
+
registerTool(tool) { tools.push({ name: tool.name, description: tool.description, promptSnippet: tool.promptSnippet, parameters: tool.parameters }); },
|
|
29
|
+
registerCommand(name) { commands.push(name); },
|
|
30
|
+
registerShortcut() {},
|
|
31
|
+
on() {},
|
|
32
|
+
});
|
|
33
|
+
console.log(JSON.stringify({ tools, commands }));
|
|
34
|
+
`,
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
env: { ...process.env, PI_CODING_AGENT_DIR: root, XDG_CONFIG_HOME: "", HOME: join(root, "home"), USERPROFILE: join(root, "home") },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function registered(config) {
|
|
41
|
+
const child = runRegistration(config);
|
|
42
|
+
assert.equal(child.status, 0, child.stderr);
|
|
43
|
+
return JSON.parse(child.stdout);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function registeredToolNames(config) {
|
|
47
|
+
return registered(config).tools.map(tool => tool.name);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function registeredTool(config, name) {
|
|
51
|
+
return registered(config).tools.find(tool => tool.name === name);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function registeredCommandNames(config) {
|
|
55
|
+
return registered(config).commands;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function registrationError(config) {
|
|
59
|
+
const child = runRegistration(config);
|
|
60
|
+
assert.notEqual(child.status, 0, child.stdout);
|
|
61
|
+
return child.stderr;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
test("malformed config falls back during extension registration", () => {
|
|
65
|
+
const child = runRegistrationWithConfig("{");
|
|
66
|
+
assert.equal(child.status, 0, child.stderr);
|
|
67
|
+
const registered = JSON.parse(child.stdout);
|
|
68
|
+
assert.deepEqual(registered.tools.map(tool => tool.name), ["web_search", "source_check", "fetch_content", "get_search_content"]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("search tools constrain numResults to integer values from 1 through 20", () => {
|
|
72
|
+
for (const name of ["web_search", "source_check"]) {
|
|
73
|
+
const schema = registeredTool({}, name).parameters.properties.numResults;
|
|
74
|
+
assert.equal(schema.type, "integer");
|
|
75
|
+
assert.equal(schema.minimum, 1);
|
|
76
|
+
assert.equal(schema.maximum, 20);
|
|
77
|
+
for (const value of [0, -1, 1.5, 21, Number.NaN, Number.POSITIVE_INFINITY]) {
|
|
78
|
+
assert.equal(Value.Check(schema, value), false, `${name} accepts ${value}`);
|
|
79
|
+
}
|
|
80
|
+
for (const value of [1, 5, 20]) {
|
|
81
|
+
assert.equal(Value.Check(schema, value), true, `${name} rejects ${value}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("tool registration gates support legacy and per-tool config", () => {
|
|
87
|
+
assert.deepEqual(registeredToolNames({ webSearch: { enabled: false } }), ["fetch_content", "get_search_content"]);
|
|
88
|
+
assert.deepEqual(registeredToolNames({
|
|
89
|
+
webSearch: { enabled: false },
|
|
90
|
+
tools: { webSearch: { enabled: true }, sourceCheck: { enabled: true }, fetchContent: { enabled: false } },
|
|
91
|
+
}), ["web_search", "source_check", "get_search_content"]);
|
|
92
|
+
assert.deepEqual(registeredToolNames({
|
|
93
|
+
tools: { sourceCheck: { enabled: false }, getSearchContent: { enabled: false } },
|
|
94
|
+
}), ["web_search", "fetch_content"]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("command registration gates default to enabled", () => {
|
|
98
|
+
assert.deepEqual(registeredCommandNames({}), ["google-account", "search"]);
|
|
99
|
+
assert.deepEqual(registeredCommandNames({
|
|
100
|
+
commands: { websearch: { enabled: false }, search: { enabled: false } },
|
|
101
|
+
}), ["google-account"]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("fetch_content schema exposes auth profile opt-in", () => {
|
|
105
|
+
const schema = registeredTool({}, "fetch_content").parameters.properties.auth;
|
|
106
|
+
assert.ok(schema);
|
|
107
|
+
assert.deepEqual(schema.anyOf.map(option => option.type), ["string", "boolean"]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("registered tools do not advertise disabled get_search_content", () => {
|
|
111
|
+
const fetchTool = registeredTool({ tools: { getSearchContent: { enabled: false } } }, "fetch_content");
|
|
112
|
+
assert.ok(fetchTool);
|
|
113
|
+
assert.doesNotMatch(fetchTool.description, /get_search_content/);
|
|
114
|
+
assert.match(fetchTool.description, /retrieval tool is not registered/);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("web activity shortcut renders through the supported string-array API", async () => {
|
|
118
|
+
const shortcuts = [];
|
|
119
|
+
initializeExtension({
|
|
120
|
+
registerTool() {},
|
|
121
|
+
registerCommand() {},
|
|
122
|
+
registerShortcut(name, shortcut) { shortcuts.push({ name, shortcut }); },
|
|
123
|
+
on() {},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const activityShortcut = shortcuts.find(({ shortcut }) => shortcut.description === "Toggle web search activity");
|
|
127
|
+
assert.ok(activityShortcut, "activity shortcut was not registered");
|
|
128
|
+
const widgets = [];
|
|
129
|
+
const ctx = {
|
|
130
|
+
ui: {
|
|
131
|
+
theme: { fg: (_color, text) => text },
|
|
132
|
+
setWidget(key, content) { widgets.push({ key, content }); },
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
await activityShortcut.shortcut.handler(ctx);
|
|
137
|
+
assert.equal(widgets[0].key, "web-activity");
|
|
138
|
+
assert.ok(Array.isArray(widgets[0].content), "activity widget content must be a string array");
|
|
139
|
+
assert.ok(widgets[0].content.length > 0);
|
|
140
|
+
|
|
141
|
+
await activityShortcut.shortcut.handler(ctx);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("tool names can be configured without changing defaults", () => {
|
|
145
|
+
assert.deepEqual(registeredToolNames({}), ["web_search", "source_check", "fetch_content", "get_search_content"]);
|
|
146
|
+
assert.deepEqual(registeredToolNames({
|
|
147
|
+
toolNames: {
|
|
148
|
+
webSearch: "research_web",
|
|
149
|
+
sourceCheck: "verify_sources",
|
|
150
|
+
fetchContent: "grab_content",
|
|
151
|
+
getSearchContent: "open_content",
|
|
152
|
+
},
|
|
153
|
+
}), ["research_web", "verify_sources", "grab_content", "open_content"]);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("tool name config rejects invalid and duplicate registered names", () => {
|
|
157
|
+
assert.match(registrationError({ toolNames: { webSearch: "1bad" } }), /toolNames\.webSearch/);
|
|
158
|
+
assert.match(registrationError({ toolNames: { webSearch: "same_name", fetchContent: "same_name" } }), /duplicates/);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("webSearch.enabled false registers only fetch tools and ignores disabled-name duplicates", () => {
|
|
162
|
+
assert.deepEqual(registeredToolNames({
|
|
163
|
+
webSearch: { enabled: false },
|
|
164
|
+
toolNames: {
|
|
165
|
+
webSearch: "content_only",
|
|
166
|
+
sourceCheck: "content_only",
|
|
167
|
+
fetchContent: "grab_content",
|
|
168
|
+
getSearchContent: "open_content",
|
|
169
|
+
},
|
|
170
|
+
}), ["grab_content", "open_content"]);
|
|
171
|
+
assert.match(registrationError({
|
|
172
|
+
webSearch: { enabled: false },
|
|
173
|
+
toolNames: { fetchContent: "same_name", getSearchContent: "same_name" },
|
|
174
|
+
}), /duplicates/);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("README documents registration gates and toolNames", () => {
|
|
178
|
+
assert.match(readmeSrc, /"tools": \{/);
|
|
179
|
+
assert.match(readmeSrc, /"commands": \{/);
|
|
180
|
+
assert.match(readmeSrc, /Pi restart is required for tool and command registration changes/);
|
|
181
|
+
assert.match(readmeSrc, /`toolNames` can opt into alternate public tool names/);
|
|
182
|
+
});
|