@a-t-h-i/bot-lobby 0.6.56 → 0.6.57
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/package.json +1 -1
- package/src/execution/agent-runner.ts +3 -0
- package/src/execution/delegation.ts +3 -1
- package/src/execution/pi-runner.ts +5 -2
- package/src/lobby/planner.ts +1 -1
- package/src/lobby/pr-review.ts +1 -1
- package/src/lobby/quickfix.ts +2 -1
- package/src/master/goal-check.ts +1 -0
- package/src/master/master.ts +1 -1
- package/src/master/research.ts +1 -1
- package/src/pi/auto-compaction.ts +23 -5
- package/src/pi/delegation.ts +5 -3
- package/src/pi/grants.ts +10 -0
- package/src/pi/model-support.ts +2 -2
- package/src/pi/quiet.ts +2 -0
- package/src/schemas/configuration.ts +37 -13
- package/webui/dist/assets/{TerminalView-BVehQ7yB.js → TerminalView-C8VC7KXy.js} +1 -1
- package/webui/dist/assets/index-Bs1_77_1.js +114 -0
- package/webui/dist/build.json +5 -5
- package/webui/dist/index.html +1 -1
- package/webui/dist/assets/index-BKiKxUUG.js +0 -114
package/package.json
CHANGED
|
@@ -49,6 +49,8 @@ export interface AgentRequest {
|
|
|
49
49
|
mcpTools?: string[];
|
|
50
50
|
/** False when the agent's settings turn its auto-compaction off. */
|
|
51
51
|
autoCompact?: boolean;
|
|
52
|
+
/** Tokens at which this agent compacts, when its settings set it. */
|
|
53
|
+
compactAt?: number;
|
|
52
54
|
delegationQuota?: { used: number; consults?: number };
|
|
53
55
|
/** See PiRunOptions.expert. */
|
|
54
56
|
expert?: { model?: string; thinking: string };
|
|
@@ -186,6 +188,7 @@ async function runAgentOnce(request: AgentRequest, run: ProcessRunner, attempt:
|
|
|
186
188
|
mcpTools: request.mcpTools,
|
|
187
189
|
...(request.skills ? { skills: request.skills } : {}),
|
|
188
190
|
...(request.autoCompact === false ? { autoCompact: false } : {}),
|
|
191
|
+
...(request.compactAt ? { compactAt: request.compactAt } : {}),
|
|
189
192
|
task: request.instruction,
|
|
190
193
|
systemPrompt,
|
|
191
194
|
tools: toolsFor(request),
|
|
@@ -16,6 +16,7 @@ import { runPiAgent, type PiRunOptions, type ProcessRunner } from "./pi-runner.t
|
|
|
16
16
|
import { startDeskServer } from "../desk/ipc.ts";
|
|
17
17
|
import { DESK_ENV, DeskSession, deskSessionAt, PEER_TOOLS } from "../desk/session.ts";
|
|
18
18
|
import { BOARD_ENV } from "../desk/board.ts";
|
|
19
|
+
import { mcpGrant } from "../pi/grants.ts";
|
|
19
20
|
|
|
20
21
|
export const MAX_CHILDREN = 5;
|
|
21
22
|
export const DELEGATE_TOOL = "delegate_subtasks";
|
|
@@ -95,7 +96,8 @@ export async function delegationHost(options: PiRunOptions, run: ProcessRunner)
|
|
|
95
96
|
const quota = options.delegationQuota ?? { used: 0 };
|
|
96
97
|
const consults = canConsult(agent, config.workflow.consultExpert);
|
|
97
98
|
const tools = [...new Set([...baseTools, "codemode", "tool_search", ...(canDelegate(agent, quota.used) ? [DELEGATE_TOOL] : []), ...(consults ? [EXPERT_TOOL] : [])])];
|
|
98
|
-
|
|
99
|
+
// A caller that passes its profile's grant (even an absent one, meaning every connected tool) wins over the role's.
|
|
100
|
+
const mcpTools = mcpGrant("mcpTools" in options ? options.mcpTools : agentProfile(config, agent.domain, agent.role).mcpTools, !editable);
|
|
99
101
|
const policy: AgentPolicy = { tools, mcpTools, readOnly: !editable, depth };
|
|
100
102
|
if (depth > 1) return { tools, mcpTools, env: { ...options.env, [AGENT_ENV]: JSON.stringify(policy), [DELEGATION_ENV]: "" }, note: options.env?.[EXPERT_ENV] ? "You are advising a worker: read what you need, answer its question, and change nothing." : "You are a child agent. Finish only your assigned brief and report evidence to your parent; you cannot delegate further.", close: async () => {}, onStart: options.onStart, children: [] as AgentRun[] };
|
|
101
103
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentRun } from "../schemas/findings.ts";
|
|
2
2
|
import type { Domain, Role } from "../schemas/agent.ts";
|
|
3
3
|
import { delegationHost } from "./delegation.ts";
|
|
4
|
-
import { AUTO_COMPACT_ENV } from "../pi/quiet.ts";
|
|
4
|
+
import { AUTO_COMPACT_ENV, COMPACT_AT_ENV } from "../pi/quiet.ts";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { spawn, type ChildProcess } from "node:child_process";
|
|
7
7
|
import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -53,6 +53,8 @@ export interface PiRunOptions {
|
|
|
53
53
|
env?: Record<string, string>;
|
|
54
54
|
/** False when the agent's settings turn its auto-compaction off. */
|
|
55
55
|
autoCompact?: boolean;
|
|
56
|
+
/** Tokens at which the agent compacts its context; absent uses the built-in threshold. */
|
|
57
|
+
compactAt?: number;
|
|
56
58
|
/** Kill the agent after this long without any output; 0 disables. */
|
|
57
59
|
stallTimeoutMs?: number;
|
|
58
60
|
/** Silence allowed while one tool call is in flight (tests, builds); 0 disables. */
|
|
@@ -656,7 +658,8 @@ function writePromptFile(prompt: string): { file: string; cleanup: () => void }
|
|
|
656
658
|
/** Run one isolated subagent and normalise its outcome. */
|
|
657
659
|
export async function runPiAgent(given: PiRunOptions, run: ProcessRunner = spawnPiProcess): Promise<PiRunResult> {
|
|
658
660
|
if (given.harness) return runHarnessAgent({ ...given, harness: given.harness });
|
|
659
|
-
const
|
|
661
|
+
const compactEnv = { ...(given.autoCompact === false ? { [AUTO_COMPACT_ENV]: "0" } : {}), ...(given.compactAt ? { [COMPACT_AT_ENV]: String(given.compactAt) } : {}) };
|
|
662
|
+
const options = Object.keys(compactEnv).length ? { ...given, env: { ...given.env, ...compactEnv } } : given;
|
|
660
663
|
const host = await delegationHost(options, run);
|
|
661
664
|
let prompt: ReturnType<typeof writePromptFile> | undefined;
|
|
662
665
|
try {
|
package/src/lobby/planner.ts
CHANGED
|
@@ -1008,7 +1008,7 @@ export class PlanningSession {
|
|
|
1008
1008
|
model,
|
|
1009
1009
|
thinking,
|
|
1010
1010
|
mcpTools: profile.mcpTools,
|
|
1011
|
-
...(profile.autoCompact === false ? { autoCompact: false } : {}),
|
|
1011
|
+
...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.compactAt ? { compactAt: profile.compactAt } : {}),
|
|
1012
1012
|
// Seats may run on a harness; the planner itself stays on pi (its settings cannot name one).
|
|
1013
1013
|
...(profile.harness ? { harness: profile.harness } : {}),
|
|
1014
1014
|
onChildRun: (child) => {
|
package/src/lobby/pr-review.ts
CHANGED
|
@@ -279,7 +279,7 @@ export class PullReviews {
|
|
|
279
279
|
model,
|
|
280
280
|
thinking,
|
|
281
281
|
mcpTools: profile.mcpTools,
|
|
282
|
-
...(profile.autoCompact === false ? { autoCompact: false } : {}),
|
|
282
|
+
...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.compactAt ? { compactAt: profile.compactAt } : {}),
|
|
283
283
|
...(profile.harness ? { harness: profile.harness } : {}),
|
|
284
284
|
onChildRun: (child) => {
|
|
285
285
|
this.deps.feed?.step(REVIEW_SOURCE, `child ${child.runId.slice(0, 8)}: ${child.step ?? child.status}`, child.runId);
|
package/src/lobby/quickfix.ts
CHANGED
|
@@ -98,6 +98,7 @@ export interface QuickFixProfile {
|
|
|
98
98
|
autoCompact?: boolean;
|
|
99
99
|
/** The third-party harness it runs on; absent runs it on pi. */
|
|
100
100
|
harness?: HarnessRun;
|
|
101
|
+
compactAt?: number;
|
|
101
102
|
/** Where the job goes when its model runs out of usage or is unavailable. */
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -346,7 +347,7 @@ export class QuickFixQueue {
|
|
|
346
347
|
model,
|
|
347
348
|
thinking,
|
|
348
349
|
mcpTools: profile.mcpTools,
|
|
349
|
-
...(profile.autoCompact === false ? { autoCompact: false } : {}),
|
|
350
|
+
...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.compactAt ? { compactAt: profile.compactAt } : {}),
|
|
350
351
|
...(profile.harness ? { harness: profile.harness } : {}),
|
|
351
352
|
delegationQuota: quota,
|
|
352
353
|
agent: { runId: job.id, taskId: job.id, domain: "backend", role: "worker" },
|
package/src/master/goal-check.ts
CHANGED
|
@@ -101,6 +101,7 @@ export async function runGoalCheck(request: GoalCheckRequest, run: ProcessRunner
|
|
|
101
101
|
instruction: goalCheckInstruction(request),
|
|
102
102
|
context: { task: request.request },
|
|
103
103
|
systemPrompt: goalCheckPrompt(profile.instructions),
|
|
104
|
+
mcpTools: profile.mcpTools,
|
|
104
105
|
...(profile.model ? { model: profile.model } : {}),
|
|
105
106
|
thinking: profile.thinking,
|
|
106
107
|
cwd: request.cwd,
|
package/src/master/master.ts
CHANGED
|
@@ -59,7 +59,7 @@ export interface ScoutRequest {
|
|
|
59
59
|
/** Model, thinking and grants for one run, from settings. */
|
|
60
60
|
function profileFields(config: BotLobbyConfig, resolver: ProfileResolver | undefined, domain: Domain, role: AgentRequest["role"]) {
|
|
61
61
|
const profile = profileFor(config, resolver, domain, role);
|
|
62
|
-
return { model: profile.model, mcpTools: profile.mcpTools, ...(profile.skills ? { skills: profile.skills } : {}), ...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.harness ? { harness: profile.harness } : {}), thinking: profile.thinking };
|
|
62
|
+
return { model: profile.model, mcpTools: profile.mcpTools, ...(profile.skills ? { skills: profile.skills } : {}), ...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.compactAt ? { compactAt: profile.compactAt } : {}), ...(profile.harness ? { harness: profile.harness } : {}), thinking: profile.thinking };
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function scoutInstruction(request: ScoutRequest, domain: Domain): string {
|
package/src/master/research.ts
CHANGED
|
@@ -70,7 +70,7 @@ export async function runResearch(request: ResearchRequest, run: ProcessRunner =
|
|
|
70
70
|
model: profile.model,
|
|
71
71
|
mcpTools: profile.mcpTools,
|
|
72
72
|
...(profile.skills ? { skills: profile.skills } : {}),
|
|
73
|
-
...(profile.autoCompact === false ? { autoCompact: false } : {}),
|
|
73
|
+
...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.compactAt ? { compactAt: profile.compactAt } : {}),
|
|
74
74
|
...(profile.harness ? { harness: profile.harness } : {}),
|
|
75
75
|
thinking: profile.thinking,
|
|
76
76
|
cwd: request.cwd,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { compact, CONFIG_DIR_NAME, DEFAULT_COMPACTION_SETTINGS, estimateTokens, findCutPoint, type ExtensionAPI, type ExtensionContext, type TurnEndEvent } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { contextMarks, freshContextOn, staleCompaction } from "./fresh-context.ts";
|
|
3
|
-
import { AUTO_COMPACT_ENV, isSubagentProcess } from "./quiet.ts";
|
|
3
|
+
import { AUTO_COMPACT_ENV, COMPACT_AT_ENV, isSubagentProcess } from "./quiet.ts";
|
|
4
4
|
import { dataRoot, detectProjectRoot, loadConfig } from "../state/project.ts";
|
|
5
|
+
import { normalizeCompactAt } from "../schemas/configuration.ts";
|
|
5
6
|
import { describeShared, DIGEST_INSTRUCTION, parseDigest, shareDigest, type DigestItem } from "../knowledge/oracle-digest.ts";
|
|
6
7
|
|
|
7
8
|
const CHECKPOINT = "Write a concise checkpoint with: Requirements and constraints; Decisions; Files changed; Verification and evidence; Failed approaches (do not repeat); Unfinished work and next action; Outstanding children and their assignments. Preserve concrete file references and distinguish verified facts from guesses. The parent remains responsible for integration and verification.";
|
|
@@ -9,6 +10,8 @@ const CHECKPOINT = "Write a concise checkpoint with: Requirements and constraint
|
|
|
9
10
|
export interface AutoCompactionOptions {
|
|
10
11
|
/** Whether this agent compacts on its own: a subagent by its environment, the oracle by its settings. */
|
|
11
12
|
enabled?: () => boolean;
|
|
13
|
+
/** The token count set in this agent's settings to compact at; by default its environment, or the oracle's settings. */
|
|
14
|
+
target?: () => number | undefined;
|
|
12
15
|
/** Where the oracle's shared knowledge goes; by default the project's knowledge files. */
|
|
13
16
|
share?: (items: DigestItem[], ctx: ExtensionContext) => string;
|
|
14
17
|
}
|
|
@@ -22,6 +25,15 @@ function enabledBySettings(): boolean {
|
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
|
|
28
|
+
function targetBySettings(): number | undefined {
|
|
29
|
+
if (isSubagentProcess()) return normalizeCompactAt(Number(process.env[COMPACT_AT_ENV]));
|
|
30
|
+
try {
|
|
31
|
+
return loadConfig().master.compactAt;
|
|
32
|
+
} catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
function shareWithAgents(items: DigestItem[], ctx: ExtensionContext): string {
|
|
26
38
|
const root = detectProjectRoot(ctx.cwd, CONFIG_DIR_NAME);
|
|
27
39
|
return describeShared(shareDigest(dataRoot(root, CONFIG_DIR_NAME), items));
|
|
@@ -29,18 +41,24 @@ function shareWithAgents(items: DigestItem[], ctx: ExtensionContext): string {
|
|
|
29
41
|
|
|
30
42
|
export const CONTEXT_TARGET = 64_000;
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
/**
|
|
45
|
+
* When to compact: a threshold set in Settings, else 64K or 60% of the window, whichever is smaller. Either way it
|
|
46
|
+
* stays below the window less pi's reserve, so the checkpoint still has room to be written.
|
|
47
|
+
*/
|
|
48
|
+
export function compactionThreshold(window: number, reserve = DEFAULT_COMPACTION_SETTINGS.reserveTokens, target?: number): number {
|
|
49
|
+
const room = window - Math.min(reserve, Math.floor(window / 2));
|
|
50
|
+
return Math.max(1, Math.min(target ?? Math.min(CONTEXT_TARGET, Math.floor(window * 0.6)), room));
|
|
34
51
|
}
|
|
35
52
|
|
|
36
53
|
/**
|
|
37
54
|
* Compact at a settled tool boundary, below pi's own threshold (pi 1.3 still sets that only per model in settings, and
|
|
38
|
-
* ctx.compact() would abort the turn we need to continue). Each agent's settings can turn it off. Compactions pi
|
|
55
|
+
* ctx.compact() would abort the turn we need to continue). Each agent's settings can turn it off or set the token count it starts at. Compactions pi
|
|
39
56
|
* starts itself get the same checkpoint through `session_before_compact`. The oracle's checkpoint also lists what it learned that is worth keeping, tagged by agent, and
|
|
40
57
|
* that goes into the knowledge base: its own, and the designer's, backend's and QA's where it concerns them.
|
|
41
58
|
*/
|
|
42
59
|
export function registerAutoCompaction(pi: ExtensionAPI, summarize: typeof compact = compact, options: AutoCompactionOptions = {}): void {
|
|
43
60
|
const enabled = options.enabled ?? enabledBySettings;
|
|
61
|
+
const target = options.target ?? targetBySettings;
|
|
44
62
|
const share = options.share ?? shareWithAgents;
|
|
45
63
|
const oracle = !isSubagentProcess();
|
|
46
64
|
let busy = false;
|
|
@@ -53,7 +71,7 @@ export function registerAutoCompaction(pi: ExtensionAPI, summarize: typeof compa
|
|
|
53
71
|
const configured = pi.getSettings().compaction;
|
|
54
72
|
const override = configured?.modelOverrides?.[`${ctx.model.provider}/${ctx.model.id}`];
|
|
55
73
|
const reserve = Math.min(override?.reserveTokens ?? configured?.reserveTokens ?? DEFAULT_COMPACTION_SETTINGS.reserveTokens, Math.floor(ctx.model.contextWindow / 2));
|
|
56
|
-
const threshold = compactionThreshold(ctx.model.contextWindow, reserve);
|
|
74
|
+
const threshold = compactionThreshold(ctx.model.contextWindow, reserve, target());
|
|
57
75
|
const estimate = event.context.contextMessages.reduce((total, message) => total + estimateTokens(message), 0) + Math.ceil(ctx.getSystemPrompt().length / 4);
|
|
58
76
|
const usage = ctx.getContextUsage();
|
|
59
77
|
if (Math.max(estimate, usage?.tokens ?? 0) < threshold) return;
|
package/src/pi/delegation.ts
CHANGED
|
@@ -27,8 +27,9 @@ export function registerAgentPermissions(pi: ExtensionAPI): void {
|
|
|
27
27
|
if (!info) return { block: true, reason: `Unknown tool ${event.toolName}.` };
|
|
28
28
|
if (["list_mcp_resources", "list_mcp_resource_templates", "read_mcp_resource"].includes(event.toolName)) {
|
|
29
29
|
const server = (event.input as { server?: unknown }).server;
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
// The oracle with no list in its settings may use every connected server.
|
|
31
|
+
const grants = policy?.mcpTools ?? loadConfig().master.mcpTools;
|
|
32
|
+
if (typeof server === "string" && (!grants || grants.some((tool) => tool.startsWith(`mcp__${server.replace(/[^A-Za-z0-9_]/g, "_")}__`))) && info?.exposure !== "hidden") return;
|
|
32
33
|
return { block: true, reason: "Specify an MCP server with an explicit tool grant to read its resources." };
|
|
33
34
|
}
|
|
34
35
|
if (policy) {
|
|
@@ -36,7 +37,8 @@ export function registerAgentPermissions(pi: ExtensionAPI): void {
|
|
|
36
37
|
return { block: true, reason: `This agent is not granted ${event.toolName}.` };
|
|
37
38
|
}
|
|
38
39
|
if (event.toolName.startsWith("mcp__")) {
|
|
39
|
-
|
|
40
|
+
const granted = loadConfig().master.mcpTools;
|
|
41
|
+
if ((!granted || granted.includes(event.toolName)) && info?.exposure !== "hidden") return;
|
|
40
42
|
return { block: true, reason: `Grant ${event.toolName} to the master in bot-lobby settings first.` };
|
|
41
43
|
}
|
|
42
44
|
if (event.parentToolCallId && !pi.getActiveTools().includes(event.toolName)) return { block: true, reason: `${event.toolName} is not active for this agent.` };
|
package/src/pi/grants.ts
CHANGED
|
@@ -55,6 +55,16 @@ export function grantableTools(pi: ExtensionAPI | undefined = source): Grantable
|
|
|
55
55
|
.sort((a, b) => a.server.localeCompare(b.server) || a.name.localeCompare(b.name));
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* The MCP tools a run may call: its settings' list as given, or, when the
|
|
60
|
+
* settings name none, every tool pi has connected now (only the read-only ones
|
|
61
|
+
* for an agent that must not change anything).
|
|
62
|
+
*/
|
|
63
|
+
export function mcpGrant(granted: readonly string[] | undefined, readOnly: boolean, pi: ExtensionAPI | undefined = source): string[] {
|
|
64
|
+
if (granted) return [...granted];
|
|
65
|
+
return grantableTools(pi).filter((tool) => !readOnly || tool.readOnly).map((tool) => tool.name);
|
|
66
|
+
}
|
|
67
|
+
|
|
58
68
|
/**
|
|
59
69
|
* The skills an agent working in `cwd` would find: the session's own (its
|
|
60
70
|
* skill commands, which include packages and settings paths) and pi's default
|
package/src/pi/model-support.ts
CHANGED
|
@@ -94,7 +94,7 @@ export function createProfileResolver(config: BotLobbyConfig, options: ResolverO
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
type RunProfile = { model?: string; thinking: string; instructions?: string; mcpTools?: string[]; skills?: string[]; autoCompact?: boolean; harness?: HarnessRun };
|
|
97
|
+
type RunProfile = { model?: string; thinking: string; instructions?: string; mcpTools?: string[]; skills?: string[]; autoCompact?: boolean; compactAt?: number; harness?: HarnessRun };
|
|
98
98
|
|
|
99
99
|
/** Unset models run on the session's; thinking is clamped to the model, with a one-time warning. */
|
|
100
100
|
function resolveRunProfile(profile: RunProfile, label: string, options: ResolverOptions): RunProfile {
|
|
@@ -133,7 +133,7 @@ export function resolvePanelProfile(config: BotLobbyConfig, member: PanelMember,
|
|
|
133
133
|
*/
|
|
134
134
|
export function resolveReviewProfile(config: BotLobbyConfig, options: ResolverOptions): RunProfile {
|
|
135
135
|
const profile = agentProfile(config, "qa", "reviewer");
|
|
136
|
-
return resolveRunProfile({ model: profile.model, thinking: profile.thinking, ...(profile.instructions ? { instructions: profile.instructions } : {}), ...(profile.mcpTools ? { mcpTools: profile.mcpTools } : {}), ...(profile.skills ? { skills: profile.skills } : {}), ...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.harness ? { harness: profile.harness } : {}) }, kindLabel("qa"), options);
|
|
136
|
+
return resolveRunProfile({ model: profile.model, thinking: profile.thinking, ...(profile.instructions ? { instructions: profile.instructions } : {}), ...(profile.mcpTools ? { mcpTools: profile.mcpTools } : {}), ...(profile.skills ? { skills: profile.skills } : {}), ...(profile.autoCompact === false ? { autoCompact: false } : {}), ...(profile.compactAt ? { compactAt: profile.compactAt } : {}), ...(profile.harness ? { harness: profile.harness } : {}) }, kindLabel("qa"), options);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
/** Every configured subagent whose thinking level its model does not support, for `/bot-lobby config`. */
|
package/src/pi/quiet.ts
CHANGED
|
@@ -60,6 +60,8 @@ export function webToolsFor(active: string[], taskActive: boolean, hidden: reado
|
|
|
60
60
|
|
|
61
61
|
/** Set to "0" in a subagent's environment when its settings turn auto-compaction off. */
|
|
62
62
|
export const AUTO_COMPACT_ENV = "BOT_LOBBY_AUTO_COMPACT";
|
|
63
|
+
/** The token count at which a subagent compacts, from its settings. */
|
|
64
|
+
export const COMPACT_AT_ENV = "BOT_LOBBY_COMPACT_AT";
|
|
63
65
|
|
|
64
66
|
/** True inside a bot-lobby subagent process (marked in `spawnPiProcess`). */
|
|
65
67
|
export function isSubagentProcess(): boolean {
|
|
@@ -28,12 +28,14 @@ export interface AgentModelConfig extends HarnessChoice {
|
|
|
28
28
|
thinking: string;
|
|
29
29
|
/** Free-form instructions layered on top of this agent's built-in prompt. */
|
|
30
30
|
instructions?: string;
|
|
31
|
-
/** Exact native MCP tool names this profile may call; empty
|
|
31
|
+
/** Exact native MCP tool names this profile may call; absent gives it every tool pi has connected (read-only ones for read-only agents), empty gives it none. */
|
|
32
32
|
mcpTools?: string[];
|
|
33
33
|
/** Names of the skills this agent may load; absent gives it every skill pi finds, empty gives it none. */
|
|
34
34
|
skills?: string[];
|
|
35
35
|
/** Compact this agent's context on its own as it fills (on unless false); the oracle's also updates the knowledge base. */
|
|
36
36
|
autoCompact?: boolean;
|
|
37
|
+
/** Context size, in tokens, at which auto-compaction starts; absent uses the built-in threshold. */
|
|
38
|
+
compactAt?: number;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
/** Scouts pick a model only; their thinking is fixed at `SCOUT_THINKING`. */
|
|
@@ -46,6 +48,8 @@ export interface ScoutConfig extends HarnessChoice {
|
|
|
46
48
|
maxToolCalls: number;
|
|
47
49
|
/** Compact a scout's context on its own as it fills (on unless false). */
|
|
48
50
|
autoCompact?: boolean;
|
|
51
|
+
/** See AgentModelConfig.compactAt. */
|
|
52
|
+
compactAt?: number;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
/** Subagent kinds with their own settings entry. */
|
|
@@ -380,6 +384,26 @@ export function normalizeMcpTools(value: unknown): string[] {
|
|
|
380
384
|
return Array.isArray(value) ? [...new Set(value.filter((tool): tool is string => typeof tool === "string" && /^mcp__[A-Za-z0-9_]+__[A-Za-z0-9_]+$/.test(tool)))] : [];
|
|
381
385
|
}
|
|
382
386
|
|
|
387
|
+
/** `{ mcpTools }` when an entry lists its tools (even none), else nothing, so the agent keeps every connected tool. */
|
|
388
|
+
function mcpToolsField(value: unknown): { mcpTools?: string[] } {
|
|
389
|
+
return Array.isArray(value) ? { mcpTools: normalizeMcpTools(value) } : {};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** The smallest and largest auto-compaction thresholds Settings accepts, in tokens. */
|
|
393
|
+
export const COMPACT_AT_MIN = 4_000;
|
|
394
|
+
export const COMPACT_AT_MAX = 2_000_000;
|
|
395
|
+
|
|
396
|
+
/** A whole number of tokens within the accepted range, or absent for the built-in threshold. */
|
|
397
|
+
export function normalizeCompactAt(value: unknown): number | undefined {
|
|
398
|
+
return typeof value === "number" && Number.isFinite(value) && value >= COMPACT_AT_MIN && value <= COMPACT_AT_MAX ? Math.round(value) : undefined;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** Auto-compaction off and its threshold, when an entry sets them. */
|
|
402
|
+
function compactFields(entry: { autoCompact?: unknown; compactAt?: unknown } | undefined): { autoCompact?: false; compactAt?: number } {
|
|
403
|
+
const compactAt = normalizeCompactAt(entry?.compactAt);
|
|
404
|
+
return { ...(entry?.autoCompact === false ? { autoCompact: false } : {}), ...(compactAt ? { compactAt } : {}) };
|
|
405
|
+
}
|
|
406
|
+
|
|
383
407
|
/**
|
|
384
408
|
* Merge one agent's override over its default; legacy `inherit` or unknown
|
|
385
409
|
* thinking falls back to the default level. Only subagents may name a
|
|
@@ -389,21 +413,19 @@ export function normalizeMcpTools(value: unknown): string[] {
|
|
|
389
413
|
function normalizeAgent(base: AgentModelConfig, override: Partial<AgentModelConfig> | undefined, harness = true): AgentModelConfig {
|
|
390
414
|
const merged = { ...base, ...(override ?? {}) };
|
|
391
415
|
const thinking = isThinkingLevel(merged.thinking) ? merged.thinking : base.thinking;
|
|
392
|
-
const mcpTools = normalizeMcpTools(merged.mcpTools);
|
|
393
416
|
const choice = harness ? harnessChoiceFields(merged) : {};
|
|
394
|
-
return { model: merged.model, thinking, ...(
|
|
417
|
+
return { model: merged.model, thinking, ...mcpToolsField(merged.mcpTools), ...skillsField(merged.skills), ...(typeof merged.instructions === "string" ? { instructions: merged.instructions } : {}), ...compactFields(merged), ...choice };
|
|
395
418
|
}
|
|
396
419
|
|
|
397
420
|
/** Scouts keep a model and a tool-call cap; any thinking value in the file is dropped. */
|
|
398
421
|
function normalizeScout(override: Partial<ScoutConfig> | undefined): ScoutConfig {
|
|
399
422
|
const base = DEFAULT_CONFIG.scout;
|
|
400
|
-
const mcpTools = normalizeMcpTools(override?.mcpTools);
|
|
401
423
|
return {
|
|
402
424
|
model: typeof override?.model === "string" && override.model.trim() ? override.model : base.model,
|
|
403
425
|
maxToolCalls: typeof override?.maxToolCalls === "number" && Number.isFinite(override.maxToolCalls) && override.maxToolCalls >= 0 ? Math.round(override.maxToolCalls) : base.maxToolCalls,
|
|
404
|
-
...(mcpTools
|
|
426
|
+
...mcpToolsField(override?.mcpTools),
|
|
405
427
|
...skillsField(override?.skills),
|
|
406
|
-
...(override
|
|
428
|
+
...compactFields(override),
|
|
407
429
|
...harnessChoiceFields(override ?? {}),
|
|
408
430
|
};
|
|
409
431
|
}
|
|
@@ -559,12 +581,14 @@ export interface AgentProfile {
|
|
|
559
581
|
model?: string;
|
|
560
582
|
thinking: string;
|
|
561
583
|
instructions?: string;
|
|
562
|
-
/** Exact native MCP tool names this profile may call; empty grants none. */
|
|
584
|
+
/** Exact native MCP tool names this profile may call; absent keeps every connected tool, empty grants none. */
|
|
563
585
|
mcpTools?: string[];
|
|
564
586
|
/** Skill names it may load; absent keeps every skill pi finds. */
|
|
565
587
|
skills?: string[];
|
|
566
588
|
/** False when its settings turn auto-compaction off. */
|
|
567
589
|
autoCompact?: boolean;
|
|
590
|
+
/** Tokens at which auto-compaction starts, when set. */
|
|
591
|
+
compactAt?: number;
|
|
568
592
|
/** The third-party harness it runs on; absent runs it on pi. */
|
|
569
593
|
harness?: HarnessRun;
|
|
570
594
|
}
|
|
@@ -575,14 +599,14 @@ function harnessField(config: BotLobbyConfig, entry: HarnessChoice): { harness?:
|
|
|
575
599
|
return harness ? { harness } : {};
|
|
576
600
|
}
|
|
577
601
|
|
|
578
|
-
/**
|
|
579
|
-
function compactField(entry: { autoCompact?: boolean }): { autoCompact?: false } {
|
|
580
|
-
return entry.autoCompact === false ? { autoCompact: false } : {};
|
|
602
|
+
/** Auto-compaction off and its threshold, as an entry sets them. */
|
|
603
|
+
function compactField(entry: { autoCompact?: boolean; compactAt?: number }): { autoCompact?: false; compactAt?: number } {
|
|
604
|
+
return { ...(entry.autoCompact === false ? { autoCompact: false } : {}), ...(entry.compactAt ? { compactAt: entry.compactAt } : {}) };
|
|
581
605
|
}
|
|
582
606
|
|
|
583
607
|
/** The MCP tools and skills an entry grants, leaving out what it does not name. */
|
|
584
608
|
function grantFields(entry: { mcpTools?: string[]; skills?: string[] }): { mcpTools?: string[]; skills?: string[] } {
|
|
585
|
-
return { ...(entry.mcpTools
|
|
609
|
+
return { ...(entry.mcpTools ? { mcpTools: entry.mcpTools } : {}), ...(entry.skills ? { skills: entry.skills } : {}) };
|
|
586
610
|
}
|
|
587
611
|
|
|
588
612
|
/** The settings entry a domain/role run draws from. */
|
|
@@ -618,7 +642,7 @@ export function lobbyAgentConfig(config: BotLobbyConfig, kind: LobbyAgentKind):
|
|
|
618
642
|
}
|
|
619
643
|
|
|
620
644
|
/** Profile for a lobby agent run, from settings alone; `model` is undefined while unset. */
|
|
621
|
-
export function lobbyAgentProfile(config: BotLobbyConfig, kind: LobbyAgentKind): { model?: string; thinking: string; instructions?: string; mcpTools?: string[]; skills?: string[]; autoCompact?: boolean; harness?: HarnessRun } {
|
|
645
|
+
export function lobbyAgentProfile(config: BotLobbyConfig, kind: LobbyAgentKind): { model?: string; thinking: string; instructions?: string; mcpTools?: string[]; skills?: string[]; autoCompact?: boolean; compactAt?: number; harness?: HarnessRun } {
|
|
622
646
|
const entry = lobbyAgentConfig(config, kind);
|
|
623
647
|
return { model: modelOf(entry.model), thinking: entry.thinking, instructions: entry.instructions, ...grantFields(entry), ...compactField(entry), ...harnessField(config, entry) };
|
|
624
648
|
}
|
|
@@ -627,7 +651,7 @@ export function lobbyAgentProfile(config: BotLobbyConfig, kind: LobbyAgentKind):
|
|
|
627
651
|
* A planning panel seat's profile: the domain's (or the researcher's) model,
|
|
628
652
|
* thinking, custom instructions and grants.
|
|
629
653
|
*/
|
|
630
|
-
export function panelMemberProfile(config: BotLobbyConfig, member: PanelMember): { model?: string; thinking: string; instructions?: string; mcpTools?: string[]; skills?: string[]; autoCompact?: boolean; harness?: HarnessRun } {
|
|
654
|
+
export function panelMemberProfile(config: BotLobbyConfig, member: PanelMember): { model?: string; thinking: string; instructions?: string; mcpTools?: string[]; skills?: string[]; autoCompact?: boolean; compactAt?: number; harness?: HarnessRun } {
|
|
631
655
|
const entry = member === "researcher" ? config.researcher : config.agents[member];
|
|
632
656
|
return { model: modelOf(entry.model), thinking: entry.thinking, instructions: entry.instructions, ...grantFields(entry), ...compactField(entry), ...harnessField(config, entry) };
|
|
633
657
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as e,i as t,n,o as r,r as i,t as a}from"./index-
|
|
1
|
+
import{a as e,i as t,n,o as r,r as i,t as a}from"./index-Bs1_77_1.js";var o=r(e(),1),s=Object.defineProperty,c=Object.getOwnPropertyDescriptor,l=(e,t)=>{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},u=(e,t,n,r)=>{for(var i=r>1?void 0:r?c(t,n):t,a=e.length-1,o;a>=0;a--)(o=e[a])&&(i=(r?o(t,n,i):o(i))||i);return r&&i&&s(t,n,i),i},d=(e,t)=>(n,r)=>t(n,r,e),f=`Terminal input`,p={get:()=>f,set:e=>f=e},m=`Too much output to announce, navigate to rows manually to read`,h={get:()=>m,set:e=>m=e};function g(e){return e.replace(/\r?\n/g,`\r`)}function _(e,t){return t?`\x1B[200~`+e+`\x1B[201~`:e}function ee(e,t){e.clipboardData&&e.clipboardData.setData(`text/plain`,t.selectionText),e.preventDefault()}function te(e,t,n,r){e.stopPropagation(),e.clipboardData&&ne(e.clipboardData.getData(`text/plain`),t,n,r)}function ne(e,t,n,r){e=g(e),e=_(e,n.decPrivateModes.bracketedPasteMode&&r.rawOptions.ignoreBracketedPasteMode!==!0),n.triggerDataEvent(e,!0),t.value=``}function re(e,t,n){let r=n.getBoundingClientRect(),i=e.clientX-r.left-10,a=e.clientY-r.top-10;t.style.width=`20px`,t.style.height=`20px`,t.style.left=`${i}px`,t.style.top=`${a}px`,t.style.zIndex=`1000`,t.focus()}function ie(e,t,n,r,i){re(e,t,n),i&&r.rightClickSelect(e),t.value=r.selectionText,t.select()}function ae(e){return e>65535?(e-=65536,String.fromCharCode((e>>10)+55296)+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)}function oe(e,t=0,n=e.length){let r=``;for(let i=t;i<n;++i){let t=e[i];t>65535?(t-=65536,r+=String.fromCharCode((t>>10)+55296)+String.fromCharCode(t%1024+56320)):r+=String.fromCharCode(t)}return r}var se=class{constructor(){this._interim=0}clear(){this._interim=0}decode(e,t){let n=e.length;if(!n)return 0;let r=0,i=0;if(this._interim){let n=e.charCodeAt(i++);56320<=n&&n<=57343?t[r++]=(this._interim-55296)*1024+n-56320+65536:(t[r++]=this._interim,t[r++]=n),this._interim=0}for(let a=i;a<n;++a){let i=e.charCodeAt(a);if(55296<=i&&i<=56319){if(++a>=n)return this._interim=i,r;let o=e.charCodeAt(a);56320<=o&&o<=57343?t[r++]=(i-55296)*1024+o-56320+65536:(t[r++]=i,t[r++]=o);continue}i!==65279&&(t[r++]=i)}return r}},ce=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(e,t){let n=e.length;if(!n)return 0;let r=0,i,a,o,s,c=0,l=0;if(this.interim[0]){let i=!1,a=this.interim[0];a&=(a&224)==192?31:(a&240)==224?15:7;let o=0,s;for(;(s=this.interim[++o]&63)&&o<4;)a<<=6,a|=s;let c=(this.interim[0]&224)==192?2:(this.interim[0]&240)==224?3:4,u=c-o;for(;l<u;){if(l>=n)return 0;if(s=e[l++],(s&192)!=128){l--,i=!0;break}this.interim[o++]=s,a<<=6,a|=s&63}i||(c===2?a<128?l--:t[r++]=a:c===3?a<2048||a>=55296&&a<=57343||a===65279||(t[r++]=a):a<65536||a>1114111||(t[r++]=a)),this.interim.fill(0)}let u=n-4,d=l;for(;d<n;){for(;d<u&&!((i=e[d])&128)&&!((a=e[d+1])&128)&&!((o=e[d+2])&128)&&!((s=e[d+3])&128);)t[r++]=i,t[r++]=a,t[r++]=o,t[r++]=s,d+=4;if(i=e[d++],i<128)t[r++]=i;else if((i&224)==192){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(c=(i&31)<<6|a&63,c<128){d--;continue}t[r++]=c}else if((i&240)==224){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,r;if(o=e[d++],(o&192)!=128){d--;continue}if(c=(i&15)<<12|(a&63)<<6|o&63,c<2048||c>=55296&&c<=57343||c===65279)continue;t[r++]=c}else if((i&248)==240){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,r;if(o=e[d++],(o&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,this.interim[2]=o,r;if(s=e[d++],(s&192)!=128){d--;continue}if(c=(i&7)<<18|(a&63)<<12|(o&63)<<6|s&63,c<65536||c>1114111)continue;t[r++]=c}}return r}},v=``,le=` `,ue=class e{constructor(){this.fg=0,this.bg=0,this.extended=new de}static toColorRGB(e){return[e>>>16&255,e>>>8&255,e&255]}static fromColorRGB(e){return(e[0]&255)<<16|(e[1]&255)<<8|e[2]&255}clone(){let t=new e;return t.fg=this.fg,t.bg=this.bg,t.extended=this.extended.clone(),t}isInverse(){return this.fg&67108864}isBold(){return this.fg&134217728}isUnderline(){return this.hasExtendedAttrs()&&this.extended.underlineStyle!==0?1:this.fg&268435456}isBlink(){return this.fg&536870912}isInvisible(){return this.fg&1073741824}isItalic(){return this.bg&67108864}isDim(){return this.bg&134217728}isStrikethrough(){return this.fg&2147483648}isProtected(){return this.bg&536870912}isOverline(){return this.bg&1073741824}getFgColorMode(){return this.fg&50331648}getBgColorMode(){return this.bg&50331648}isFgRGB(){return(this.fg&50331648)==50331648}isBgRGB(){return(this.bg&50331648)==50331648}isFgPalette(){return(this.fg&50331648)==16777216||(this.fg&50331648)==33554432}isBgPalette(){return(this.bg&50331648)==16777216||(this.bg&50331648)==33554432}isFgDefault(){return!(this.fg&50331648)}isBgDefault(){return!(this.bg&50331648)}isAttributeDefault(){return this.fg===0&&this.bg===0}getFgColor(){switch(this.fg&50331648){case 16777216:case 33554432:return this.fg&255;case 50331648:return this.fg&16777215;default:return-1}}getBgColor(){switch(this.bg&50331648){case 16777216:case 33554432:return this.bg&255;case 50331648:return this.bg&16777215;default:return-1}}hasExtendedAttrs(){return this.bg&268435456}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(this.bg&268435456&&~this.extended.underlineColor)switch(this.extended.underlineColor&50331648){case 16777216:case 33554432:return this.extended.underlineColor&255;case 50331648:return this.extended.underlineColor&16777215;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return this.bg&268435456&&~this.extended.underlineColor?this.extended.underlineColor&50331648:this.getFgColorMode()}isUnderlineColorRGB(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==50331648:this.isFgRGB()}isUnderlineColorPalette(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==16777216||(this.extended.underlineColor&50331648)==33554432:this.isFgPalette()}isUnderlineColorDefault(){return this.bg&268435456&&~this.extended.underlineColor?!(this.extended.underlineColor&50331648):this.isFgDefault()}getUnderlineStyle(){return this.fg&268435456?this.bg&268435456?this.extended.underlineStyle:1:0}getUnderlineVariantOffset(){return this.extended.underlineVariantOffset}},de=class e{constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}get ext(){return this._urlId?this._ext&-469762049|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(this._ext&469762048)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return this._ext&67108863}set underlineColor(e){this._ext&=-67108864,this._ext|=e&67108863}get urlId(){return this._urlId}set urlId(e){this._urlId=e}get underlineVariantOffset(){let e=(this._ext&3758096384)>>29;return e<0?e^4294967288:e}set underlineVariantOffset(e){this._ext&=536870911,this._ext|=e<<29&3758096384}clone(){return new e(this._ext,this._urlId)}isEmpty(){return this.underlineStyle===0&&this._urlId===0}},y=class e extends ue{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new de,this.combinedData=``}static fromCharData(t){let n=new e;return n.setFromCharData(t),n}isCombined(){return this.content&2097152}getWidth(){return this.content>>22}getChars(){return this.content&2097152?this.combinedData:this.content&2097151?ae(this.content&2097151):``}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):this.content&2097151}setFromCharData(e){this.fg=e[0],this.bg=0;let t=!1;if(e[1].length>2)t=!0;else if(e[1].length===2){let n=e[1].charCodeAt(0);if(55296<=n&&n<=56319){let r=e[1].charCodeAt(1);56320<=r&&r<=57343?this.content=(n-55296)*1024+r-56320+65536|e[2]<<22:t=!0}else t=!0}else this.content=e[1].charCodeAt(0)|e[2]<<22;t&&(this.combinedData=e[1],this.content=2097152|e[2]<<22)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}},fe=`di$target`,pe=`di$dependencies`,me=new Map;function b(e){return e[pe]||[]}function x(e){if(me.has(e))return me.get(e);let t=function(e,n,r){if(arguments.length!==3)throw Error(`@IServiceName-decorator can only be used to decorate a parameter`);he(t,e,r)};return t._id=e,me.set(e,t),t}function he(e,t,n){t[fe]===t?t[pe].push({id:e,index:n}):(t[pe]=[{id:e,index:n}],t[fe]=t)}var S=x(`BufferService`),ge=x(`CoreMouseService`),_e=x(`CoreService`),C=x(`CharsetService`),ve=x(`InstantiationService`),w=x(`LogService`),T=x(`OptionsService`),ye=x(`OscLinkService`),be=x(`UnicodeService`),xe=x(`DecorationService`),Se=class{constructor(e,t,n){this._bufferService=e,this._optionsService=t,this._oscLinkService=n}provideLinks(e,t){let n=this._bufferService.buffer.lines.get(e-1);if(!n){t(void 0);return}let r=[],i=this._optionsService.rawOptions.linkHandler,a=new y,o=n.getTrimmedLength(),s=-1,c=-1,l=!1;for(let t=0;t<o;t++)if(c!==-1||n.hasContent(t)){if(n.loadCell(t,a),a.hasExtendedAttrs()&&a.extended.urlId){if(c===-1){c=t,s=a.extended.urlId;continue}l=a.extended.urlId!==s}else c!==-1&&(l=!0);if(l||c!==-1&&t===o-1){let n=this._oscLinkService.getLinkData(s)?.uri;if(n){let a={start:{x:c+1,y:e},end:{x:t+ +(!l&&t===o-1),y:e}},s=!1;if(!i?.allowNonHttpProtocols)try{let e=new URL(n);[`http:`,`https:`].includes(e.protocol)||(s=!0)}catch{s=!0}s||r.push({text:n,range:a,activate:(e,t)=>i?i.activate(e,t,a):Ce(e,t),hover:(e,t)=>i?.hover?.(e,t,a),leave:(e,t)=>i?.leave?.(e,t,a)})}l=!1,a.hasExtendedAttrs()&&a.extended.urlId?(c=t,s=a.extended.urlId):(c=-1,s=-1)}}t(r)}};Se=u([d(0,S),d(1,T),d(2,ye)],Se);function Ce(e,t){if(confirm(`Do you want to navigate to ${t}?
|
|
2
2
|
|
|
3
3
|
WARNING: This link could potentially be dangerous`)){let e=window.open();if(e){try{e.opener=null}catch{}e.location.href=t}else console.warn(`Opening link blocked as opener could not be cleared`)}}var we=x(`CharSizeService`),Te=x(`CoreBrowserService`),Ee=x(`MouseService`),De=x(`RenderService`),Oe=x(`SelectionService`),ke=x(`CharacterJoinerService`),Ae=x(`ThemeService`),je=x(`LinkProviderService`),Me=new class{constructor(){this.listeners=[],this.unexpectedErrorHandler=function(e){setTimeout(()=>{throw e.stack?Re.isErrorNoTelemetry(e)?new Re(e.message+`
|
|
4
4
|
|