@selesai/code 0.13.30-beta.0 β 0.13.31
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 +7 -1
- package/README.md +8 -2
- package/dist/core/settings-manager-auto-handoff.test.js +11 -0
- package/dist/core/settings-manager.d.ts +10 -0
- package/dist/core/settings-manager.js +6 -0
- package/dist/defaults/settings.json +5 -0
- package/dist/extensions/capability-gateway/index.ts +17 -4
- package/dist/extensions/capability-gateway/integration.test.ts +26 -3
- package/dist/extensions/capability-gateway/routing.test.ts +11 -5
- package/dist/extensions/capability-gateway/routing.ts +6 -6
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.js +12 -0
- package/dist/modes/interactive/interactive-mode.js +18 -0
- package/dist/skills/code-review-and-quality/SKILL.md +396 -0
- package/dist/skills/code-simplification/SKILL.md +331 -0
- package/dist/skills/incremental-implementation/SKILL.md +249 -0
- package/dist/skills/planning-and-task-breakdown/SKILL.md +257 -0
- package/dist/skills/references/agent-skills-LICENSE +21 -0
- package/dist/skills/references/definition-of-done.md +67 -0
- package/dist/skills/references/performance-checklist.md +236 -0
- package/dist/skills/references/security-checklist.md +248 -0
- package/docs/settings.md +8 -7
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@selesai/code` will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [0.13.
|
|
5
|
+
## [0.13.31] - 2026-09-23
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- **Jev capability tie-breaking is now on by default.** Toggle ambiguous-tool tie-breaking in `/settings`. It requires Token-In credentials; without them, Jev is not called and Selesai prompts you to run `/tokenin add`. Deterministic routing remains the fallback.
|
|
9
|
+
|
|
10
|
+
## [0.13.30] - 2026-09-23
|
|
6
11
|
|
|
7
12
|
### Added
|
|
13
|
+
- **Four default skills from `addyosmani/agent-skills`.** `planning-and-task-breakdown`, `incremental-implementation`, `code-review-and-quality`, and `code-simplification` now ship as bundled skills and seed into the agent directory like the rest. Their shared reference files (`definition-of-done.md`, `security-checklist.md`, `performance-checklist.md`) ship in `src/skills/references/` with the upstream MIT license, and the links in the skills that cite them were rebased to that location.
|
|
8
14
|
- **Jev advisory routing (opt-in beta).** The new bundled `jev-advisory-routing` extension can make a bounded, read-only durable-memory lookup after an explicit memory cue, and suggest one discovered skill/workflow or a proportionate verification level. Both routes are disabled by default; neither writes memory, loads a skill, starts a workflow, runs a command, or weakens required checks.
|
|
9
15
|
- **Jev capability tie-breaking (opt-in beta).** The capability gateway can use Jev only to break an ambiguous lexical hint between two or three optional tools. It never receives the full catalog, tool schemas, or conversation history; unavailable, malformed, low-confidence, and `none` decisions preserve deterministic behavior.
|
|
10
16
|
|
package/README.md
CHANGED
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
-
Selesai is a terminal-first **AI coding agent** that takes software tasks from prompt to verified result. It is a maintained, extension-first fork of the [Pi coding agent](https://github.com/earendil-works/pi), with subagents, adaptive workflows, live research, recovery tools, a richer TUI, and **
|
|
16
|
+
Selesai is a terminal-first **AI coding agent** that takes software tasks from prompt to verified result. It is a maintained, extension-first fork of the [Pi coding agent](https://github.com/earendil-works/pi), with subagents, adaptive workflows, live research, recovery tools, a richer TUI, and **32 built-in skills** shipped together in one install.
|
|
17
17
|
|
|
18
18
|
Use your preferred model provider, connect a local or OpenAI-compatible endpoint, or get a ready-to-use token from **[token.in](https://token.selesai.in)**. Selesai keeps Pi's small, hackable core while reducing the setup and extension work needed before an agent can be productive.
|
|
19
19
|
|
|
20
20
|
| | |
|
|
21
21
|
| --- | --- |
|
|
22
|
-
| **Ready out of the box** | One package bundles coordinated extensions, tools, themes, and
|
|
22
|
+
| **Ready out of the box** | One package bundles coordinated extensions, tools, themes, and 32 skills across 9 meaningful categories. |
|
|
23
23
|
| **Delegates and parallelizes** | Focused subagents can research, review, build, or run independent workstreams with foreground, background, parallel, and chained execution. |
|
|
24
24
|
| **Adapts to the task** | The workflow chooses the smallest useful pathβfrom a direct edit to reconnaissance, implementation, review, fixes, and validation. |
|
|
25
25
|
| **Researches with current sources** | Built-in web research, public GitHub code search, and interactive questions help the agent resolve uncertainty before it acts. |
|
|
@@ -113,6 +113,8 @@ Skills ship inside `@selesai/code` and are discovered when Selesai starts. Invok
|
|
|
113
113
|
|
|
114
114
|
### π Planning & orchestration
|
|
115
115
|
|
|
116
|
+
- `planning-and-task-breakdown` β turn a spec into ordered, implementable tasks with acceptance criteria.
|
|
117
|
+
- `incremental-implementation` β land work in thin, verifiable slices with per-increment checks.
|
|
116
118
|
- `pi-subagents` β delegation patterns for parallel, asynchronous, and chained work.
|
|
117
119
|
|
|
118
120
|
### π§Ή Code simplicity β the ponytail family
|
|
@@ -127,6 +129,8 @@ Skills ship inside `@selesai/code` and are discovered when Selesai starts. Invok
|
|
|
127
129
|
### π οΈ Codebase quality
|
|
128
130
|
|
|
129
131
|
- `improve-codebase` β inspect and improve architecture, maintainability, and overall codebase quality.
|
|
132
|
+
- `code-review-and-quality` β five-axis review, severity labels, and change sizing before merge.
|
|
133
|
+
- `code-simplification` β remove accumulated complexity without changing behavior.
|
|
130
134
|
|
|
131
135
|
### β
Completion & output discipline
|
|
132
136
|
|
|
@@ -146,6 +150,8 @@ Skills ship inside `@selesai/code` and are discovered when Selesai starts. Invok
|
|
|
146
150
|
|
|
147
151
|
- `agent-browser` β browser and Electron automation, scraping, and QA workflows.
|
|
148
152
|
|
|
153
|
+
`planning-and-task-breakdown`, `incremental-implementation`, `code-review-and-quality`, and `code-simplification` are adapted from [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) (MIT). Their shared reference material ships in `src/skills/references/`, with the upstream license alongside it.
|
|
154
|
+
|
|
149
155
|
---
|
|
150
156
|
|
|
151
157
|
## What Selesai adds to Pi
|
|
@@ -39,4 +39,15 @@ describe("auto handoff settings", () => {
|
|
|
39
39
|
await manager.flush();
|
|
40
40
|
expect(manager.getAutoHandoffThresholdTokens()).toBe(128_500);
|
|
41
41
|
});
|
|
42
|
+
it("defaults Jev capability routing on and persists the /settings toggle", async () => {
|
|
43
|
+
const manager = SettingsManager.inMemory();
|
|
44
|
+
expect(manager.getCapabilityGatewayJevEnabled()).toBe(true);
|
|
45
|
+
manager.setCapabilityGatewayJevEnabled(false);
|
|
46
|
+
await manager.flush();
|
|
47
|
+
expect(manager.getCapabilityGatewayJevEnabled()).toBe(false);
|
|
48
|
+
expect(manager.getGlobalSettings().capabilityGateway?.routing?.jev?.enabled).toBe(false);
|
|
49
|
+
manager.setCapabilityGatewayJevEnabled(true);
|
|
50
|
+
await manager.flush();
|
|
51
|
+
expect(manager.getCapabilityGatewayJevEnabled()).toBe(true);
|
|
52
|
+
});
|
|
42
53
|
});
|
|
@@ -64,6 +64,13 @@ export interface AutoHandoffSettings {
|
|
|
64
64
|
enabled?: boolean;
|
|
65
65
|
thresholdTokens?: number;
|
|
66
66
|
}
|
|
67
|
+
export interface CapabilityGatewaySettings {
|
|
68
|
+
routing?: {
|
|
69
|
+
jev?: {
|
|
70
|
+
enabled?: boolean;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
67
74
|
export type DefaultProjectTrust = "ask" | "always" | "never";
|
|
68
75
|
export type TransportSetting = Transport;
|
|
69
76
|
/**
|
|
@@ -130,6 +137,7 @@ export interface Settings {
|
|
|
130
137
|
markdown?: MarkdownSettings;
|
|
131
138
|
warnings?: WarningSettings;
|
|
132
139
|
autoHandoff?: AutoHandoffSettings;
|
|
140
|
+
capabilityGateway?: CapabilityGatewaySettings;
|
|
133
141
|
sessionDir?: string;
|
|
134
142
|
extensionHost?: Record<string, "selesai" | "pi">;
|
|
135
143
|
httpProxy?: string;
|
|
@@ -361,6 +369,8 @@ export declare class SettingsManager {
|
|
|
361
369
|
getWarnings(): WarningSettings;
|
|
362
370
|
setWarnings(warnings: WarningSettings): void;
|
|
363
371
|
getAutoHandoffEnabled(): boolean;
|
|
372
|
+
getCapabilityGatewayJevEnabled(): boolean;
|
|
373
|
+
setCapabilityGatewayJevEnabled(enabled: boolean): void;
|
|
364
374
|
setAutoHandoffEnabled(enabled: boolean): void;
|
|
365
375
|
getAutoHandoffThresholdTokens(): number;
|
|
366
376
|
setAutoHandoffThresholdTokens(tokens: number): void;
|
|
@@ -1087,6 +1087,12 @@ export class SettingsManager {
|
|
|
1087
1087
|
getAutoHandoffEnabled() {
|
|
1088
1088
|
return this.settings.autoHandoff?.enabled ?? DEFAULT_AUTO_HANDOFF_SETTINGS.enabled;
|
|
1089
1089
|
}
|
|
1090
|
+
getCapabilityGatewayJevEnabled() {
|
|
1091
|
+
return this.settings.capabilityGateway?.routing?.jev?.enabled ?? true;
|
|
1092
|
+
}
|
|
1093
|
+
setCapabilityGatewayJevEnabled(enabled) {
|
|
1094
|
+
this.setGlobalSettings({ capabilityGateway: { routing: { jev: { enabled } } } });
|
|
1095
|
+
}
|
|
1090
1096
|
setAutoHandoffEnabled(enabled) {
|
|
1091
1097
|
if (!this.globalSettings.autoHandoff) {
|
|
1092
1098
|
this.globalSettings.autoHandoff = {};
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* - A deterministic router activates a uniquely matched tool before the run.
|
|
17
17
|
* Skills and ambiguous matches remain discoverable through the catalog
|
|
18
18
|
* without injecting fuzzy hints into the model context.
|
|
19
|
-
* -
|
|
19
|
+
* - Default-on Jev-assisted routing (capabilityGateway.routing.jev in settings.json)
|
|
20
20
|
* is only a bounded tie-breaker: when the deterministic router returns an
|
|
21
21
|
* ambiguous lexical hint among optional tools, the gateway offers just those
|
|
22
22
|
* hinted tools (two or three) and the current prompt to the Jev decisions
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
* hinted canonical tool name; the gateway revalidates the choice against the
|
|
25
25
|
* live catalog and activates it for the current run only. No hint, a unique
|
|
26
26
|
* activation, a skill match, or an already-activated tool never reaches Jev.
|
|
27
|
-
* Every Jev failure is an ordinary abstention that leaves
|
|
28
|
-
* behavior in place
|
|
27
|
+
* Every Jev failure is an ordinary abstention that leaves deterministic
|
|
28
|
+
* behavior in place. Without Token-In credentials, no Jev request is sent and
|
|
29
|
+
* the user is prompted to add an account with `/tokenin add`.
|
|
29
30
|
* - Temporary activations reset at agent_settled, restoring the baseline
|
|
30
31
|
* active-tool set; a tool_execution_start for one of them records whether the
|
|
31
32
|
* activation was actually used (content-free tool name + source only).
|
|
@@ -146,6 +147,7 @@ export default function capabilityGatewayExtension(pi: ExtensionAPI): void {
|
|
|
146
147
|
// Tools this gateway activated for the current run, and whether they were invoked.
|
|
147
148
|
// Cleared at agent_settled with the activations themselves.
|
|
148
149
|
const activations = new Map<string, { source: ActivationSource; used: boolean }>();
|
|
150
|
+
let tokenInSetupPrompted = false;
|
|
149
151
|
|
|
150
152
|
/** Activate one tool for the current run, keeping the rest of the loadout untouched. */
|
|
151
153
|
function activateTool(name: string, source: ActivationSource): void {
|
|
@@ -313,7 +315,7 @@ export default function capabilityGatewayExtension(pi: ExtensionAPI): void {
|
|
|
313
315
|
});
|
|
314
316
|
|
|
315
317
|
// ------------------------------------------------------------------
|
|
316
|
-
// Routing: the deterministic catalog router first;
|
|
318
|
+
// Routing: the deterministic catalog router first; default-on Jev routing is
|
|
317
319
|
// only a bounded tie-breaker for its ambiguous/hint result.
|
|
318
320
|
// ------------------------------------------------------------------
|
|
319
321
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
@@ -344,6 +346,17 @@ export default function capabilityGatewayExtension(pi: ExtensionAPI): void {
|
|
|
344
346
|
emitTelemetry(pi, "route", { source: "jev", outcome: "attempt", candidates: candidates.length });
|
|
345
347
|
const jevRoute = await routeToJevTool(candidates, event.prompt, ctx, config);
|
|
346
348
|
if (!jevRoute.selected) {
|
|
349
|
+
if (
|
|
350
|
+
!tokenInSetupPrompted &&
|
|
351
|
+
config.provider === "tokenin" &&
|
|
352
|
+
(jevRoute.reason === "no-credential" || jevRoute.reason === "no-template")
|
|
353
|
+
) {
|
|
354
|
+
tokenInSetupPrompted = true;
|
|
355
|
+
ctx.ui.notify(
|
|
356
|
+
"Jev tool tie-breaking needs a Token-In account. Add one with /tokenin add; deterministic routing will keep working meanwhile.",
|
|
357
|
+
"warning",
|
|
358
|
+
);
|
|
359
|
+
}
|
|
347
360
|
emitTelemetry(pi, "route", {
|
|
348
361
|
source: "jev",
|
|
349
362
|
outcome: JEV_UNAVAILABLE_REASONS.has(jevRoute.reason) ? "unavailable" : "abstained",
|
|
@@ -333,7 +333,7 @@ describe("capability gateway integration", () => {
|
|
|
333
333
|
});
|
|
334
334
|
|
|
335
335
|
// ---------------------------------------------------------------------------
|
|
336
|
-
// Jev-assisted routing
|
|
336
|
+
// Default-on Jev-assisted routing: capabilityGateway.routing.jev.
|
|
337
337
|
// ---------------------------------------------------------------------------
|
|
338
338
|
|
|
339
339
|
describe("capability gateway Jev routing", () => {
|
|
@@ -518,14 +518,37 @@ describe("capability gateway Jev routing", () => {
|
|
|
518
518
|
);
|
|
519
519
|
});
|
|
520
520
|
|
|
521
|
-
it("
|
|
521
|
+
it("tries Jev by default but abstains safely without Token-In", async () => {
|
|
522
522
|
allowNetwork();
|
|
523
|
-
const
|
|
523
|
+
const unavailable = stubJev("grep_app_search");
|
|
524
524
|
const h = await createGatewaySession({ enabled: true, extensions: [GATEWAY_DIR, GREP_APP_DIR] });
|
|
525
525
|
harnesses.push(h);
|
|
526
526
|
|
|
527
527
|
await route(h, HINT_PROMPT);
|
|
528
528
|
|
|
529
|
+
expect(unavailable.fetchMock).not.toHaveBeenCalled();
|
|
530
|
+
expect(h.session.getActiveToolNames()).not.toContain("grep_app_search");
|
|
531
|
+
expect(routeEvents(h)).toContainEqual(expect.objectContaining({ source: "jev", outcome: "attempt" }));
|
|
532
|
+
expect(routeEvents(h)).toContainEqual(
|
|
533
|
+
expect.objectContaining({
|
|
534
|
+
source: "jev",
|
|
535
|
+
outcome: "unavailable",
|
|
536
|
+
reason: expect.stringMatching(/^no-(template|credential)$/),
|
|
537
|
+
}),
|
|
538
|
+
);
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it("does not attempt Jev when explicitly disabled", async () => {
|
|
542
|
+
const disabled = stubJev("grep_app_search");
|
|
543
|
+
const h = await createGatewaySession({
|
|
544
|
+
enabled: true,
|
|
545
|
+
extensions: [GATEWAY_DIR, GREP_APP_DIR],
|
|
546
|
+
jev: { enabled: false },
|
|
547
|
+
});
|
|
548
|
+
harnesses.push(h);
|
|
549
|
+
|
|
550
|
+
await route(h, HINT_PROMPT);
|
|
551
|
+
|
|
529
552
|
expect(disabled.fetchMock).not.toHaveBeenCalled();
|
|
530
553
|
expect(h.session.getActiveToolNames()).not.toContain("grep_app_search");
|
|
531
554
|
expect(routeEvents(h)).toEqual([]);
|
|
@@ -115,10 +115,10 @@ describe("gateway Jev configuration", () => {
|
|
|
115
115
|
return path;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
it("
|
|
118
|
+
it("defaults Jev routing on with short pre-turn settings when settings are missing or malformed", () => {
|
|
119
119
|
expect(readGatewayJevConfig(join(settingsDir, "absent.json"))).toEqual(DEFAULT_GATEWAY_JEV_CONFIG);
|
|
120
120
|
expect(DEFAULT_GATEWAY_JEV_CONFIG).toMatchObject({
|
|
121
|
-
enabled:
|
|
121
|
+
enabled: true,
|
|
122
122
|
provider: "tokenin",
|
|
123
123
|
model: "jev-1.13",
|
|
124
124
|
timeoutMs: DEFAULT_GATEWAY_JEV_TIMEOUT_MS,
|
|
@@ -133,7 +133,7 @@ describe("gateway Jev configuration", () => {
|
|
|
133
133
|
);
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
it("reads
|
|
136
|
+
it("reads explicit route settings over the default-on gateway config", () => {
|
|
137
137
|
const path = write({
|
|
138
138
|
capabilityGateway: {
|
|
139
139
|
routing: {
|
|
@@ -174,7 +174,7 @@ describe("gateway Jev configuration", () => {
|
|
|
174
174
|
expect(read).not.toHaveProperty("contextChars");
|
|
175
175
|
});
|
|
176
176
|
|
|
177
|
-
it("rejects wrong types
|
|
177
|
+
it("rejects wrong types while allowing an omitted enabled flag to inherit true", () => {
|
|
178
178
|
const path = write({
|
|
179
179
|
capabilityGateway: {
|
|
180
180
|
routing: {
|
|
@@ -190,7 +190,13 @@ describe("gateway Jev configuration", () => {
|
|
|
190
190
|
},
|
|
191
191
|
},
|
|
192
192
|
});
|
|
193
|
-
expect(readGatewayJevConfig(path)).toEqual(DEFAULT_GATEWAY_JEV_CONFIG);
|
|
193
|
+
expect(readGatewayJevConfig(path)).toEqual({ ...DEFAULT_GATEWAY_JEV_CONFIG, enabled: false });
|
|
194
|
+
|
|
195
|
+
const omittedEnabled = write({ capabilityGateway: { routing: { jev: { timeoutMs: 500 } } } });
|
|
196
|
+
expect(readGatewayJevConfig(omittedEnabled).enabled).toBe(true);
|
|
197
|
+
|
|
198
|
+
const disabled = write({ capabilityGateway: { routing: { jev: { enabled: false } } } });
|
|
199
|
+
expect(readGatewayJevConfig(disabled).enabled).toBe(false);
|
|
194
200
|
});
|
|
195
201
|
|
|
196
202
|
it("derives the shared connection settings and hard-caps the pre-turn timeout", () => {
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* an abstention that leaves the deterministic behavior in place. The transport and validation half
|
|
13
13
|
* lives in the shared `../jev/decisions.ts` client.
|
|
14
14
|
*
|
|
15
|
-
* Configuration (
|
|
16
|
-
* not inherit `jevAdvisory` route policy; only the Jev provider/model
|
|
17
|
-
* Jev consumer defaults to the same deployment:
|
|
15
|
+
* Configuration (enabled by default, but requires Token-In credentials). The gateway reads its
|
|
16
|
+
* own settings area β it does not inherit `jevAdvisory` route policy; only the Jev provider/model
|
|
17
|
+
* identity is shared so every Jev consumer defaults to the same deployment:
|
|
18
18
|
*
|
|
19
19
|
* "capabilityGateway": {
|
|
20
20
|
* "routing": { "jev": { "enabled": true, "timeoutMs": 1000, "minConfidence": 0.6 } }
|
|
@@ -68,7 +68,7 @@ export interface GatewayJevConfig {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export const DEFAULT_GATEWAY_JEV_CONFIG: GatewayJevConfig = {
|
|
71
|
-
enabled:
|
|
71
|
+
enabled: true,
|
|
72
72
|
// The Jev deployment identity, shared with every other Jev consumer.
|
|
73
73
|
provider: DEFAULT_JEV_ADVISORY_CONFIG.provider,
|
|
74
74
|
model: DEFAULT_JEV_ADVISORY_CONFIG.model,
|
|
@@ -99,13 +99,13 @@ export function readGatewayJevConfig(settingsPath: string = getSettingsPath()):
|
|
|
99
99
|
if (isRecord(jev)) raw = jev;
|
|
100
100
|
}
|
|
101
101
|
} catch {
|
|
102
|
-
// Missing or malformed settings: the
|
|
102
|
+
// Missing or malformed settings: use the default-on route preference.
|
|
103
103
|
}
|
|
104
104
|
if (!raw) return DEFAULT_GATEWAY_JEV_CONFIG;
|
|
105
105
|
|
|
106
106
|
const baseUrl = raw.baseUrl;
|
|
107
107
|
return {
|
|
108
|
-
enabled: raw.enabled === true,
|
|
108
|
+
enabled: raw.enabled === undefined ? DEFAULT_GATEWAY_JEV_CONFIG.enabled : raw.enabled === true,
|
|
109
109
|
provider: stringOr(raw.provider, DEFAULT_GATEWAY_JEV_CONFIG.provider),
|
|
110
110
|
model: stringOr(raw.model, DEFAULT_GATEWAY_JEV_CONFIG.model),
|
|
111
111
|
baseUrl: typeof baseUrl === "string" && baseUrl.trim() !== "" ? baseUrl : undefined,
|
|
@@ -15,6 +15,7 @@ export interface SettingsConfig {
|
|
|
15
15
|
autoCompact: boolean;
|
|
16
16
|
autoHandoffEnabled: boolean;
|
|
17
17
|
autoHandoffThresholdTokens: number;
|
|
18
|
+
capabilityGatewayJevEnabled: boolean;
|
|
18
19
|
showImages: boolean;
|
|
19
20
|
imageWidthCells: number;
|
|
20
21
|
autoResizeImages: boolean;
|
|
@@ -62,6 +63,7 @@ export interface SettingsCallbacks {
|
|
|
62
63
|
onAutoCompactChange: (enabled: boolean) => void;
|
|
63
64
|
onAutoHandoffEnabledChange: (enabled: boolean) => void;
|
|
64
65
|
onAutoHandoffThresholdTokensChange: (tokens: number) => void;
|
|
66
|
+
onCapabilityGatewayJevChange: (enabled: boolean) => boolean;
|
|
65
67
|
onShowImagesChange: (enabled: boolean) => void;
|
|
66
68
|
onImageWidthCellsChange: (width: number) => void;
|
|
67
69
|
onAutoResizeImagesChange: (enabled: boolean) => void;
|
|
@@ -363,6 +363,13 @@ export class SettingsSelectorComponent extends Container {
|
|
|
363
363
|
currentValue: String(config.autoHandoffThresholdTokens),
|
|
364
364
|
values: ["64000", "96000", "128000", "160000", "192000", "256000", "512000"],
|
|
365
365
|
},
|
|
366
|
+
{
|
|
367
|
+
id: "capability-gateway-jev",
|
|
368
|
+
label: "Jev tool tie-breaking",
|
|
369
|
+
description: "Use Token-In Jev only for ambiguous optional-tool matches. Requires Token-In credentials; add one with /tokenin add.",
|
|
370
|
+
currentValue: config.capabilityGatewayJevEnabled ? "true" : "false",
|
|
371
|
+
values: ["true", "false"],
|
|
372
|
+
},
|
|
366
373
|
{
|
|
367
374
|
id: "steering-mode",
|
|
368
375
|
label: "Steering mode",
|
|
@@ -731,6 +738,11 @@ export class SettingsSelectorComponent extends Container {
|
|
|
731
738
|
case "auto-handoff-threshold":
|
|
732
739
|
callbacks.onAutoHandoffThresholdTokensChange(parseInt(newValue, 10));
|
|
733
740
|
break;
|
|
741
|
+
case "capability-gateway-jev":
|
|
742
|
+
if (!callbacks.onCapabilityGatewayJevChange(newValue === "true")) {
|
|
743
|
+
this.settingsList.updateValue(id, config.capabilityGatewayJevEnabled ? "true" : "false");
|
|
744
|
+
}
|
|
745
|
+
break;
|
|
734
746
|
case "show-images":
|
|
735
747
|
callbacks.onShowImagesChange(newValue === "true");
|
|
736
748
|
break;
|
|
@@ -3785,6 +3785,7 @@ export class InteractiveMode {
|
|
|
3785
3785
|
autoCompact: this.session.autoCompactionEnabled,
|
|
3786
3786
|
autoHandoffEnabled: this.settingsManager.getAutoHandoffEnabled(),
|
|
3787
3787
|
autoHandoffThresholdTokens: this.settingsManager.getAutoHandoffThresholdTokens(),
|
|
3788
|
+
capabilityGatewayJevEnabled: this.settingsManager.getCapabilityGatewayJevEnabled(),
|
|
3788
3789
|
defaultModel: (() => {
|
|
3789
3790
|
const defaultProvider = this.settingsManager.getDefaultProvider();
|
|
3790
3791
|
const defaultModelId = this.settingsManager.getDefaultModel();
|
|
@@ -3850,6 +3851,23 @@ export class InteractiveMode {
|
|
|
3850
3851
|
onAutoHandoffThresholdTokensChange: (tokens) => {
|
|
3851
3852
|
this.settingsManager.setAutoHandoffThresholdTokens(tokens);
|
|
3852
3853
|
},
|
|
3854
|
+
onCapabilityGatewayJevChange: (enabled) => {
|
|
3855
|
+
if (enabled && !this.session.modelRuntime.getProviderAuthStatus("tokenin").configured) {
|
|
3856
|
+
this.showStatus("Token-In is required for Jev routing; starting /tokenin add");
|
|
3857
|
+
done();
|
|
3858
|
+
void this.session
|
|
3859
|
+
.prompt("/tokenin add")
|
|
3860
|
+
.then(() => {
|
|
3861
|
+
if (this.session.modelRuntime.getProviderAuthStatus("tokenin").configured) {
|
|
3862
|
+
this.settingsManager.setCapabilityGatewayJevEnabled(true);
|
|
3863
|
+
}
|
|
3864
|
+
})
|
|
3865
|
+
.catch((error) => this.showError(`Could not start Token-In setup: ${String(error)}`));
|
|
3866
|
+
return false;
|
|
3867
|
+
}
|
|
3868
|
+
this.settingsManager.setCapabilityGatewayJevEnabled(enabled);
|
|
3869
|
+
return true;
|
|
3870
|
+
},
|
|
3853
3871
|
onShowImagesChange: (enabled) => {
|
|
3854
3872
|
this.settingsManager.setShowImages(enabled);
|
|
3855
3873
|
for (const child of this.chatContainer.children) {
|