diff --git a/ts/packages/agentServer/protocol/src/index.ts b/ts/packages/agentServer/protocol/src/index.ts index 8087d9efd..182fe9781 100644 --- a/ts/packages/agentServer/protocol/src/index.ts +++ b/ts/packages/agentServer/protocol/src/index.ts @@ -7,6 +7,8 @@ export { AgentServerChannelName, ConversationInfo, JoinConversationResult, + UserIdentity, + DefaultUserIdentity, getDispatcherChannelName, getClientIOChannelName, registerClientType, diff --git a/ts/packages/agentServer/protocol/src/protocol.ts b/ts/packages/agentServer/protocol/src/protocol.ts index 0de8d3d50..6861854a4 100644 --- a/ts/packages/agentServer/protocol/src/protocol.ts +++ b/ts/packages/agentServer/protocol/src/protocol.ts @@ -27,6 +27,18 @@ export type JoinConversationResult = { pendingInteractions?: PendingInteractionRequest[]; }; +/** + * Identity of the OS user the agent-server process is running as. + * Used by clients that can't do Office SSO (e.g. the Excel add-in) so + * they can show the user's initial instead of a generic "U" avatar. + * This is a convenience signal, not a security claim. + */ +export type UserIdentity = { + username: string; // OS username, e.g. "robgruen" + displayName: string; // Git user.name if set, else username + initial: string; // Single uppercase character for avatars +}; + export type AgentServerInvokeFunctions = { joinConversation: ( options?: DispatcherConnectOptions, @@ -40,6 +52,17 @@ export type AgentServerInvokeFunctions = { ) => Promise; deleteConversation: (conversationId: string) => Promise; shutdown: () => Promise; + getUserIdentity: () => Promise; +}; + +/** + * Fallback UserIdentity for clients that fail to reach the server. Keeps + * the UI from having to guard for undefined everywhere. + */ +export const DefaultUserIdentity: UserIdentity = { + username: "user", + displayName: "user", + initial: "U", }; export const AgentServerChannelName = "agent-server"; diff --git a/ts/packages/agentServer/server/package.json b/ts/packages/agentServer/server/package.json index 0f17f1e48..e3373232c 100644 --- a/ts/packages/agentServer/server/package.json +++ b/ts/packages/agentServer/server/package.json @@ -33,6 +33,7 @@ "tsc": "tsc -b" }, "dependencies": { + "@azure/identity": "^4.10.0", "@typeagent/agent-rpc": "workspace:*", "@typeagent/agent-server-client": "workspace:*", "@typeagent/agent-server-protocol": "workspace:*", diff --git a/ts/packages/agentServer/server/src/server.ts b/ts/packages/agentServer/server/src/server.ts index ce36adb1f..df111361c 100644 --- a/ts/packages/agentServer/server/src/server.ts +++ b/ts/packages/agentServer/server/src/server.ts @@ -23,6 +23,7 @@ import { AgentServerInvokeFunctions, AgentServerChannelName, DispatcherConnectOptions, + UserIdentity, getDispatcherChannelName, getClientIOChannelName, } from "@typeagent/agent-server-protocol"; @@ -34,11 +35,112 @@ import { removeServerPid, } from "@typeagent/agent-server-client"; import registerDebug from "debug"; +import os from "node:os"; +import { DefaultAzureCredential } from "@azure/identity"; + const envPath = new URL("../../../../.env", import.meta.url); dotenv.config({ path: envPath }); const debugStartup = registerDebug("agent-server:startup"); +// User identity resolution. Precedence: +// 1. TYPEAGENT_USER_NAME env var (dev override / CI) +// 2. Claims from the Azure AD token DefaultAzureCredential acquires for +// the Cognitive Services scope — this is the same credential the +// agent-server uses to talk to Azure OpenAI, so if the server can talk +// to the model at all, the token's `name`/`upn` claims give us the +// real user. Works without any extra setup (no git config, no Office +// SSO). +// 3. OS username as a last resort. +// +// The Azure step is async and involves a network call, so we resolve it +// after startup and overwrite the cached identity when it arrives. The +// first few RPC calls may see the OS-username fallback; subsequent calls +// see the real display name. +function parseJwtClaims(token: string): Record | undefined { + const [, payload] = token.split("."); + if (!payload) return undefined; + const b64 = payload.replace(/-/g, "+").replace(/_/g, "/"); + const padded = b64 + "=".repeat((4 - (b64.length % 4)) % 4); + try { + return JSON.parse(Buffer.from(padded, "base64").toString("utf-8")); + } catch { + return undefined; + } +} + +function identityFromClaims( + claims: Record, + fallbackUsername: string, +): UserIdentity | undefined { + // Azure AD `name` is typically "First Last" or "Last, First". Prefer + // just the first name so the chat header stays compact. Split on + // whitespace or comma and take the first non-empty part. + const fullName = + typeof claims.name === "string" && claims.name.trim() + ? claims.name.trim() + : undefined; + if (!fullName) return undefined; + // "Last, First" → prefer "First" after the comma; otherwise first token. + const firstName = fullName.includes(",") + ? (fullName.split(",")[1]?.trim().split(/\s+/)[0] ?? fullName) + : (fullName.split(/\s+/)[0] ?? fullName); + const upn = + (typeof claims.upn === "string" && claims.upn) || + (typeof claims.preferred_username === "string" && + claims.preferred_username) || + (typeof claims.unique_name === "string" && claims.unique_name) || + undefined; + const initial = (firstName[0] ?? "U").toUpperCase(); + return { + username: upn || fallbackUsername, + displayName: firstName, + initial, + }; +} + +async function resolveIdentityFromAzureToken( + fallbackUsername: string, +): Promise { + try { + const token = await new DefaultAzureCredential().getToken( + "https://cognitiveservices.azure.com/.default", + ); + if (!token?.token) return undefined; + const claims = parseJwtClaims(token.token); + if (!claims) return undefined; + return identityFromClaims(claims, fallbackUsername); + } catch { + return undefined; + } +} + +function initialIdentity(): UserIdentity { + const username = os.userInfo().username || "user"; + const envName = process.env.TYPEAGENT_USER_NAME?.trim(); + const displayName = envName || username; + const initial = (displayName[0] ?? "U").toUpperCase(); + return { username, displayName, initial }; +} + +let userIdentity: UserIdentity = initialIdentity(); + +// Kick off the token-based resolution asynchronously. Env override wins +// if set, so skip the network call in that case. +if (!process.env.TYPEAGENT_USER_NAME?.trim()) { + const fallbackUsername = userIdentity.username; + resolveIdentityFromAzureToken(fallbackUsername) + .then((resolved) => { + if (resolved) { + userIdentity = resolved; + debugStartup( + `resolved user identity from Azure token: ${resolved.displayName}`, + ); + } + }) + .catch(() => {}); +} + async function main() { debugStartup(`pid=${process.pid} resolving instance dir + traceId`); const [instanceDir, traceId] = await Promise.all([ @@ -289,6 +391,7 @@ async function main() { ); }, shutdown: shutdownServer, + getUserIdentity: async () => userIdentity, }; // Clean up all conversations on WebSocket disconnect diff --git a/ts/packages/agents/onboarding/src/packaging/packagingHandler.ts b/ts/packages/agents/onboarding/src/packaging/packagingHandler.ts index 7f902eada..c86fb73a4 100644 --- a/ts/packages/agents/onboarding/src/packaging/packagingHandler.ts +++ b/ts/packages/agents/onboarding/src/packaging/packagingHandler.ts @@ -23,6 +23,14 @@ import { getPackagingModel } from "../lib/llm.js"; import { spawn } from "child_process"; import path from "path"; import fs from "fs/promises"; +import { fileURLToPath } from "node:url"; + +// `` derived from this file's location. +// Compiled file path: /packages/agents/onboarding/dist/src/packaging/packagingHandler.js +const TYPEAGENT_REPO_ROOT = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + "../../../../../..", +); export async function executePackagingAction( action: TypeAgentAction, @@ -411,10 +419,16 @@ async function registerWithDispatcher( integrationName: string, agentDir: string, ): Promise { - // Add agent to defaultAgentProvider config.json - const configPath = path.resolve( - agentDir, - "../../../../defaultAgentProvider/data/config.json", + // Add agent to defaultAgentProvider config.json. Anchor the config path + // at the TypeAgent monorepo root rather than walking up from agentDir — + // agents scaffolded outside the monorepo (e.g. in SecretAgents) sit at + // a different depth than `/packages/agents/`. + const configPath = path.join( + TYPEAGENT_REPO_ROOT, + "packages", + "defaultAgentProvider", + "data", + "config.json", ); try { @@ -426,10 +440,31 @@ async function registerWithDispatcher( return `Agent "${integrationName}" is already registered in the dispatcher config.`; } - config.agents[integrationName] = { + const agentEntry: Record = { name: `${integrationName}-agent`, }; + // For agents outside the monorepo, the dispatcher needs an explicit + // path (it can't resolve via npm). Emit a relative path from the + // defaultAgentProvider package, matching the existing convention + // (e.g. excel: "../../SecretAgents/ts/packages/agents/excel"). + const insideMonorepo = path + .resolve(agentDir) + .startsWith(TYPEAGENT_REPO_ROOT + path.sep); + if (!insideMonorepo) { + const providerDir = path.join( + TYPEAGENT_REPO_ROOT, + "packages", + "defaultAgentProvider", + ); + agentEntry.path = path + .relative(providerDir, agentDir) + .replace(/\\/g, "/"); + agentEntry.execMode = "dispatcher"; + } + + config.agents[integrationName] = agentEntry; + await fs.writeFile( configPath, JSON.stringify(config, null, 2), diff --git a/ts/packages/agents/onboarding/src/scaffolder/scaffolderHandler.ts b/ts/packages/agents/onboarding/src/scaffolder/scaffolderHandler.ts index a8b3d5b87..39398d47b 100644 --- a/ts/packages/agents/onboarding/src/scaffolder/scaffolderHandler.ts +++ b/ts/packages/agents/onboarding/src/scaffolder/scaffolderHandler.ts @@ -216,6 +216,7 @@ async function handleScaffoldAgent( pascalName, pattern, subSchemaNames, + targetDir, ), null, 2, @@ -541,12 +542,49 @@ async function executeAction( `; } +// Map of TypeAgent workspace packages to their location relative to the +// monorepo root. Used to emit `file:` deps when scaffolding outside the +// monorepo (e.g. into a sibling SecretAgents repo) — `workspace:*` only +// resolves inside the originating pnpm workspace. +const TYPEAGENT_WORKSPACE_PACKAGES: Record = { + "@typeagent/agent-sdk": "packages/agentSdk", + aiclient: "packages/aiclient", + typechat: "packages/utils/typechatUtils", + "@typeagent/action-schema-compiler": "packages/actionSchemaCompiler", + "action-grammar-compiler": "packages/actionGrammarCompiler", +}; + +// AGENTS_DIR is `/packages/agents`; up two levels = repo root. +const TYPEAGENT_REPO_ROOT = path.resolve(AGENTS_DIR, "..", ".."); + +function getWorkspaceDepValue( + depName: string, + targetDir: string | undefined, +): string { + // If we're scaffolding inside the main TypeAgent workspace, plain + // `workspace:*` works. Outside it (e.g. SecretAgents), pnpm cannot + // resolve the workspace alias — emit a `file:` path relative to + // `targetDir` so install picks up the source on disk. + const insideMonorepo = + targetDir === undefined || + path.resolve(targetDir).startsWith(TYPEAGENT_REPO_ROOT + path.sep); + if (insideMonorepo) return "workspace:*"; + + const pkgPath = TYPEAGENT_WORKSPACE_PACKAGES[depName]; + if (!pkgPath) return "workspace:*"; // unknown — best-effort fallback + const absolute = path.join(TYPEAGENT_REPO_ROOT, pkgPath); + let rel = path.relative(targetDir, absolute).replace(/\\/g, "/"); + if (!rel.startsWith(".")) rel = "./" + rel; + return `file:${rel}`; +} + function buildPackageJson( name: string, packageName: string, pascalName: string, pattern: AgentPattern = "schema-grammar", subSchemaNames?: string[], + targetDir?: string, ) { const scripts: Record = { asc: `asc -i ./src/${name}Schema.ts -o ./dist/${name}Schema.pas.json -t ${pascalName}Actions`, @@ -570,6 +608,8 @@ function buildPackageJson( scripts.build = `concurrently ${buildTargets.join(" ")}`; + const depFor = (n: string) => getWorkspaceDepValue(n, targetDir); + return { name: packageName, version: "0.0.1", @@ -584,18 +624,23 @@ function buildPackageJson( }, scripts, dependencies: { - "@typeagent/agent-sdk": "workspace:*", + "@typeagent/agent-sdk": depFor("@typeagent/agent-sdk"), ...(pattern === "llm-streaming" - ? { aiclient: "workspace:*", typechat: "workspace:*" } + ? { + aiclient: depFor("aiclient"), + typechat: depFor("typechat"), + } : pattern === "external-api" - ? { aiclient: "workspace:*" } + ? { aiclient: depFor("aiclient") } : pattern === "websocket-bridge" ? { ws: "^8.18.0" } : {}), }, devDependencies: { - "@typeagent/action-schema-compiler": "workspace:*", - "action-grammar-compiler": "workspace:*", + "@typeagent/action-schema-compiler": depFor( + "@typeagent/action-schema-compiler", + ), + "action-grammar-compiler": depFor("action-grammar-compiler"), concurrently: "^9.1.2", rimraf: "^6.0.1", typescript: "~5.4.5", @@ -857,6 +902,7 @@ function buildExternalApiHandler(name: string, pascalName: string): string { import { ActionContext, AppAgent, + SessionContext, TypeAgentAction, ActionResult, } from "@typeagent/agent-sdk"; @@ -899,8 +945,9 @@ async function initializeAgentContext(): Promise { } async function updateAgentContext( - enable: boolean, - _context: ActionContext, + _enable: boolean, + _context: SessionContext, + _schemaName: string, ): Promise { // Optionally authenticate eagerly when the agent is enabled. } @@ -909,7 +956,7 @@ async function executeAction( action: TypeAgentAction<${pascalName}Actions>, context: ActionContext, ): Promise { - const { client } = context.agentContext; + const { client } = context.sessionContext.agentContext; // TODO: map each action to a client.callApi() call. return createActionResultFromTextDisplay( \`Executing \${action.actionName} — not yet implemented.\`, @@ -1030,6 +1077,7 @@ function buildWebSocketBridgeHandler(name: string, pascalName: string): string { import { ActionContext, AppAgent, + SessionContext, TypeAgentAction, ActionResult, } from "@typeagent/agent-sdk"; @@ -1105,10 +1153,11 @@ async function initializeAgentContext(): Promise { async function updateAgentContext( _enable: boolean, - _context: ActionContext, + _context: SessionContext, + _schemaName: string, ): Promise {} -async function closeAgentContext(context: ActionContext): Promise { +async function closeAgentContext(context: SessionContext): Promise { await context.agentContext.bridge.stop(); } @@ -1116,7 +1165,7 @@ async function executeAction( action: TypeAgentAction<${pascalName}Actions>, context: ActionContext, ): Promise { - const { bridge } = context.agentContext; + const { bridge } = context.sessionContext.agentContext; if (!bridge.connected) { return { error: \`Host plugin not connected. Make sure the ${name} plugin is running on port \${BRIDGE_PORT}.\`, @@ -1300,6 +1349,7 @@ function buildViewUiHandler(name: string, pascalName: string): string { import { ActionContext, AppAgent, + SessionContext, TypeAgentAction, ActionResult, } from "@typeagent/agent-sdk"; @@ -1324,22 +1374,23 @@ async function initializeAgentContext(): Promise { async function updateAgentContext( enable: boolean, - context: ActionContext, + context: SessionContext, + _schemaName: string, ): Promise { if (enable) { - await context.sessionContext.agentIO.openLocalView( - context.sessionContext.requestId, + await context.agentIO.openLocalView( + context.requestId, VIEW_PORT, ); } else { - await context.sessionContext.agentIO.closeLocalView( - context.sessionContext.requestId, + await context.agentIO.closeLocalView( + context.requestId, VIEW_PORT, ); } } -async function closeAgentContext(_context: ActionContext): Promise { +async function closeAgentContext(_context: SessionContext): Promise { // TODO: stop the local HTTP server } diff --git a/ts/packages/agents/onboarding/src/testing/runTests.ts b/ts/packages/agents/onboarding/src/testing/runTests.ts index dd6d6ca38..03bfee468 100644 --- a/ts/packages/agents/onboarding/src/testing/runTests.ts +++ b/ts/packages/agents/onboarding/src/testing/runTests.ts @@ -53,7 +53,19 @@ if (!fs.existsSync(testCasesFile)) { const testCases = JSON.parse(fs.readFileSync(testCasesFile, "utf-8")); console.log(`Loaded ${testCases.length} test cases for "${integrationName}"`); -const agentDir = path.resolve(AGENTS_DIR, integrationName); +// Prefer the path recorded by scaffoldAgent (supports custom outputDir), +// fall back to the default /packages/agents/ layout. +const scaffoldedToFile = path.join( + WORKSPACE_DIR, + "scaffolder", + "scaffolded-to.txt", +); +let agentDir = path.resolve(AGENTS_DIR, integrationName); +if (fs.existsSync(scaffoldedToFile)) { + const trimmed = fs.readFileSync(scaffoldedToFile, "utf-8").trim(); + if (trimmed.length > 0) agentDir = trimmed; +} +console.log(`Agent directory: ${agentDir}`); const packageName = `${integrationName}-agent`; const configs = { [integrationName]: { name: packageName, path: agentDir } }; const provider = createNpmAppAgentProvider(configs, import.meta.url); diff --git a/ts/packages/agents/onboarding/src/testing/testingHandler.ts b/ts/packages/agents/onboarding/src/testing/testingHandler.ts index df4716c8e..e4a8d5dc2 100644 --- a/ts/packages/agents/onboarding/src/testing/testingHandler.ts +++ b/ts/packages/agents/onboarding/src/testing/testingHandler.ts @@ -244,13 +244,20 @@ async function handleRunTests( ) .join("\n"); + if (failed === 0) { + // Auto-approve testing when every phrase round-trips. Otherwise the + // workflow gets stuck: approveRepair is the only path that flips + // testing to "approved", but it requires a proposed repair. + await updatePhase(integrationName, "testing", { status: "approved" }); + } + return createActionResultFromMarkdownDisplay( `## Test results: ${integrationName}\n\n` + `**Pass rate:** ${passRate}% (${passed}/${results.length})\n\n` + (failed > 0 ? `**Failing tests (first 10):**\n${failingSummary}\n\n` + `Use \`proposeRepair\` to get LLM-suggested schema/grammar fixes.` - : `All tests passed! Use \`approveRepair\` to finalize or proceed to packaging.`), + : `All tests passed — testing phase auto-approved. Run \`packageAgent\` to proceed.`), ); } @@ -541,9 +548,28 @@ const AGENTS_DIR = path.resolve( "../../../../../../packages/agents", ); -function getTestAgentProvider(integrationName: string) { +// Resolve the scaffolded agent directory. Prefers the path recorded in +// the workspace's `scaffolder/scaffolded-to.txt` (set by scaffoldAgent — +// supports custom outputDir, e.g. external repos like SecretAgents) and +// falls back to the default `/packages/agents/` layout. +async function resolveScaffoldedAgentDir( + integrationName: string, +): Promise { + const scaffoldedTo = await readArtifact( + integrationName, + "scaffolder", + "scaffolded-to.txt", + ); + if (scaffoldedTo) { + const trimmed = scaffoldedTo.trim(); + if (trimmed.length > 0) return trimmed; + } + return path.resolve(AGENTS_DIR, integrationName); +} + +async function getTestAgentProvider(integrationName: string) { const packageName = `${integrationName}-agent`; - const agentDir = path.resolve(AGENTS_DIR, integrationName); + const agentDir = await resolveScaffoldedAgentDir(integrationName); const configs: Record = { [integrationName]: { name: packageName, path: agentDir }, }; @@ -554,7 +580,7 @@ function getTestAgentProvider(integrationName: string) { async function createTestDispatcher(integrationName: string) { const instanceDir = getInstanceDir(); - const appAgentProviders = [getTestAgentProvider(integrationName)]; + const appAgentProviders = [await getTestAgentProvider(integrationName)]; const buffer: string[] = []; const clientIO = createCapturingClientIO(buffer); diff --git a/ts/packages/dispatcher/dispatcher/src/context/session.ts b/ts/packages/dispatcher/dispatcher/src/context/session.ts index 0fc8ed56f..8853b7b9f 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/session.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/session.ts @@ -249,13 +249,16 @@ const defaultSessionConfig: SessionConfig = { resolve: true, filter: true, clarify: false, // TODO: enable when it is ready. - // Default "throw": path navigation is ON, and unresolvable paths - // fail fast with a descriptive error. This matches the project - // pattern of making the reasoning loop — not silent fallbacks — - // handle LLM mistakes. Set to "off" to restore pre-feature - // behavior, "fallback-to-name" to recover via entity.name on - // miss, or "passthrough" to leave the literal placeholder. - pathNavigation: "throw", + // Default "fallback-to-name": path navigation is ON, and an + // unresolvable path silently substitutes entity.name (with a + // debug-log line via the typeagent:dispatcher:actions:entities + // namespace). This lets the action dispatch with a slightly- + // wrong-but-not-fatal value so the existing reasoning fallback + // can recover, instead of aborting the whole conversation at + // translation time. Set to "throw" to restore the strict mode + // that fails fast on a path miss, "off" to disable path navigation + // entirely, or "passthrough" to leave the literal placeholder. + pathNavigation: "fallback-to-name", }, }, execution: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts index 1a235a012..c7edd4c05 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts @@ -16,7 +16,8 @@ import { expandHome } from "../../../utils/fsUtils.js"; import { isChatHistoryInput } from "../../chatHistory.js"; import { setActivityContext } from "../../../execute/activityContext.js"; import { DispatcherActivityName } from "../../dispatcher/dispatcherUtils.js"; -import { clearReasoningSession } from "../../../reasoning/claude.js"; +import { clearReasoningSession as clearClaudeReasoningSession } from "../../../reasoning/claude.js"; +import { clearReasoningSession as clearCopilotReasoningSession } from "../../../reasoning/copilot.js"; class HistoryListCommandHandler implements CommandHandlerNoParams { public readonly description = "List history"; @@ -45,7 +46,8 @@ class HistoryClearCommandHandler implements CommandHandler { const systemContext = context.sessionContext.agentContext; const history = systemContext.chatHistory; history.clear(); - clearReasoningSession(systemContext); + clearClaudeReasoningSession(systemContext); + clearCopilotReasoningSession(systemContext); if (param.flags.activity) { setActivityContext(DispatcherActivityName, null, systemContext); } diff --git a/ts/packages/dispatcher/dispatcher/src/execute/pendingActions.ts b/ts/packages/dispatcher/dispatcher/src/execute/pendingActions.ts index 19848b522..53164007d 100644 --- a/ts/packages/dispatcher/dispatcher/src/execute/pendingActions.ts +++ b/ts/packages/dispatcher/dispatcher/src/execute/pendingActions.ts @@ -348,6 +348,9 @@ export function resolveEntityPlaceholders( ); } if (mode === "fallback-to-name") { + debugEntities( + `Entity path miss in "${value}" (failed at "${key}${walk.at}") — falling back to entity.name="${entity.name}"`, + ); return entity.name; } // "passthrough": leave the original placeholder untouched, which diff --git a/ts/packages/dispatcher/dispatcher/src/reasoning/copilot.ts b/ts/packages/dispatcher/dispatcher/src/reasoning/copilot.ts index 5f4a22bc0..56948062e 100644 --- a/ts/packages/dispatcher/dispatcher/src/reasoning/copilot.ts +++ b/ts/packages/dispatcher/dispatcher/src/reasoning/copilot.ts @@ -55,7 +55,29 @@ function withAbortSignal( }); } -const defaultModel = "gpt-4o"; +const FALLBACK_MODEL = "gpt-4o"; + +function resolveModel(): string { + return process.env.COPILOT_REASONING_MODEL?.trim() || FALLBACK_MODEL; +} + +function resolveReasoningEffort(): + | "low" + | "medium" + | "high" + | "xhigh" + | undefined { + const raw = process.env.COPILOT_REASONING_EFFORT?.trim().toLowerCase(); + if ( + raw === "low" || + raw === "medium" || + raw === "high" || + raw === "xhigh" + ) { + return raw; + } + return undefined; +} // Track Copilot clients per dispatcher instance (WeakMap for GC) const copilotClients = new WeakMap(); @@ -84,6 +106,15 @@ function setSessionId( copilotSessionIds.set(context.sessionContext.agentContext, sessionId); } +/** + * Clear the stored Copilot reasoning session ID for the given agent context. + * Call this before starting a new reasoning loop to avoid topic pollution + * from prior sessions. Exported so @history clear can invoke it. + */ +export function clearReasoningSession(agentContext: object): void { + copilotSessionIds.delete(agentContext); +} + /** * Generate a structured session ID based on the dispatcher session * (Mirrors Claude's session ID pattern) @@ -432,9 +463,13 @@ function getCopilotSessionConfig( }, }); + const model = resolveModel(); + const reasoningEffort = resolveReasoningEffort(); + return { clientName: "TypeAgent", - model: defaultModel, + model, + ...(reasoningEffort ? { reasoningEffort } : {}), streaming: true, tools: [discoverTool, executeTool], availableTools: [ @@ -726,7 +761,7 @@ async function executeReasoningWithTracing( sessionId: systemContext.session.getSessionDirPath() || "unknown", originalRequest, requestId, - model: defaultModel, + model: resolveModel(), planReuseEnabled: true, }); diff --git a/ts/packages/dispatcher/dispatcher/src/translation/actionSchemaJsonTranslator.ts b/ts/packages/dispatcher/dispatcher/src/translation/actionSchemaJsonTranslator.ts index 98390c548..d97713a4f 100644 --- a/ts/packages/dispatcher/dispatcher/src/translation/actionSchemaJsonTranslator.ts +++ b/ts/packages/dispatcher/dispatcher/src/translation/actionSchemaJsonTranslator.ts @@ -15,6 +15,7 @@ import { generateActionActionFunctionJsonSchemas, ActionObjectJsonSchema, ActionFunctionJsonSchema, + resolveTypeReference, } from "@typeagent/action-schema"; import { createJsonTranslatorWithValidator, @@ -50,6 +51,30 @@ function convertJsonSchemaOutput( return (jsonObject as any).response; } +// Fields that Excel agent schemas declare on every action (see CLAUDE.md +// "userRequest parameter" convention). The LLM learns the convention from +// those schemas and then emits `parameters.userRequest` for non-Excel agents +// too, whose schemas don't declare it — producing "Extraneous property" +// validation failures. Strip only these known cross-schema fields; other +// unknown properties still fail loudly so prompt/schema bugs stay visible. +const CROSS_SCHEMA_PARAM_ALLOWLIST = ["userRequest"]; + +function stripKnownParameterLeakage( + actionSchema: ActionSchemaTypeDefinition, + value: any, +) { + const parameters = value?.parameters; + if (!parameters || typeof parameters !== "object") return; + const paramsField = actionSchema.type.fields.parameters; + const resolved = resolveTypeReference(paramsField?.type); + if (!resolved || resolved.type !== "object") return; + for (const key of CROSS_SCHEMA_PARAM_ALLOWLIST) { + if (key in parameters && !(key in resolved.fields)) { + delete parameters[key]; + } + } +} + export function createActionSchemaJsonValidator( actionSchemaGroup: ActionSchemaGroup, generateOptions?: GenerateSchemaOptions, @@ -103,6 +128,7 @@ export function createActionSchemaJsonValidator( } if (schemaValidate) { + stripKnownParameterLeakage(actionSchema, value); validateAction(actionSchema, value); } // Return the unwrapped value with generateJsonSchema as the translated result diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index bee80972c..191f67b2b 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -554,7 +554,7 @@ importers: version: 24.37.5(typescript@5.4.5) ts-node: specifier: ^10.9.1 - version: 10.9.2(@types/node@20.19.39)(typescript@5.4.5) + version: 10.9.2(@types/node@25.5.2)(typescript@5.4.5) xml2js: specifier: ^0.6.2 version: 0.6.2 @@ -1172,6 +1172,9 @@ importers: packages/agentServer/server: dependencies: + '@azure/identity': + specifier: ^4.10.0 + version: 4.10.0 '@typeagent/agent-rpc': specifier: workspace:* version: link:../../agentRpc @@ -3082,7 +3085,7 @@ importers: version: link:../telemetry ts-node: specifier: ^10.9.1 - version: 10.9.2(@types/node@20.19.39)(typescript@5.4.5) + version: 10.9.2(@types/node@25.5.2)(typescript@5.4.5) typechat-utils: specifier: workspace:* version: link:../utils/typechatUtils @@ -3101,7 +3104,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) + version: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3110,7 +3113,7 @@ importers: version: 6.0.1 ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)))(typescript@5.4.5) + version: 29.4.9(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.4.5)))(typescript@5.4.5) typescript: specifier: ~5.4.5 version: 5.4.5 @@ -4430,7 +4433,7 @@ importers: devDependencies: '@electron-toolkit/tsconfig': specifier: ^1.0.1 - version: 1.0.1(@types/node@20.19.39) + version: 1.0.1(@types/node@25.5.2) '@fontsource/lato': specifier: ^5.2.5 version: 5.2.5 @@ -4463,10 +4466,10 @@ importers: version: 26.8.1(dmg-builder@26.8.1) electron-vite: specifier: ^4.0.1 - version: 4.0.1(vite@6.4.2(@types/node@20.19.39)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.0.1(vite@6.4.2(@types/node@25.5.2)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3)) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) + version: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.4.5)) less: specifier: ^4.2.0 version: 4.3.0 @@ -4484,7 +4487,7 @@ importers: version: 5.4.5 vite: specifier: ^6.4.2 - version: 6.4.2(@types/node@20.19.39)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3) + version: 6.4.2(@types/node@25.5.2)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3) packages/telemetry: dependencies: @@ -8049,9 +8052,6 @@ packages: '@types/node@20.19.25': resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} - '@types/node@20.19.39': - resolution: {integrity: sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==} - '@types/node@22.15.18': resolution: {integrity: sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==} @@ -15372,11 +15372,11 @@ snapshots: dependencies: '@azure-rest/core-client': 2.4.0 '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 + '@azure/core-auth': 1.10.1 '@azure/core-lro': 2.7.2 '@azure/core-rest-pipeline': 1.22.2 - '@azure/core-tracing': 1.2.0 - '@azure/logger': 1.2.0 + '@azure/core-tracing': 1.3.1 + '@azure/logger': 1.3.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -15384,9 +15384,9 @@ snapshots: '@azure-rest/core-client@2.4.0': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 + '@azure/core-auth': 1.10.1 '@azure/core-rest-pipeline': 1.22.2 - '@azure/core-tracing': 1.2.0 + '@azure/core-tracing': 1.3.1 '@typespec/ts-http-runtime': 0.2.2 tslib: 2.8.1 transitivePeerDependencies: @@ -15515,8 +15515,10 @@ snapshots: '@azure/core-auth@1.9.0': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.11.0 + '@azure/core-util': 1.13.1 tslib: 2.8.1 + transitivePeerDependencies: + - supports-color '@azure/core-client@1.10.1': dependencies: @@ -15533,11 +15535,11 @@ snapshots: '@azure/core-client@1.9.2': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 + '@azure/core-auth': 1.10.1 '@azure/core-rest-pipeline': 1.22.2 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.2.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -15568,8 +15570,8 @@ snapshots: '@azure/core-lro@3.2.0': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.2.0 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -15581,10 +15583,10 @@ snapshots: '@azure/core-rest-pipeline@1.20.0': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.2.0 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 '@typespec/ts-http-runtime': 0.2.2 tslib: 2.8.1 transitivePeerDependencies: @@ -15663,15 +15665,15 @@ snapshots: '@azure/identity@4.10.0': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 - '@azure/core-client': 1.9.2 - '@azure/core-rest-pipeline': 1.20.0 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.2.0 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 '@azure/msal-browser': 4.12.0 '@azure/msal-node': 3.5.3 - open: 10.1.0 + open: 10.1.2 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -15782,8 +15784,8 @@ snapshots: '@azure/opentelemetry-instrumentation-azure-sdk@1.0.0-beta.8': dependencies: - '@azure/core-tracing': 1.2.0 - '@azure/logger': 1.2.0 + '@azure/core-tracing': 1.3.1 + '@azure/logger': 1.3.0 '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) @@ -16382,9 +16384,9 @@ snapshots: dependencies: electron: 40.8.5 - '@electron-toolkit/tsconfig@1.0.1(@types/node@20.19.39)': + '@electron-toolkit/tsconfig@1.0.1(@types/node@25.5.2)': dependencies: - '@types/node': 20.19.39 + '@types/node': 25.5.2 '@electron/asar@3.4.1': dependencies: @@ -17221,41 +17223,6 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5))': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 20.19.25 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5))': dependencies: '@jest/console': 29.7.0 @@ -19491,10 +19458,6 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@20.19.39': - dependencies: - undici-types: 6.21.0 - '@types/node@22.15.18': dependencies: undici-types: 6.21.0 @@ -19506,7 +19469,6 @@ snapshots: '@types/node@25.5.2': dependencies: undici-types: 7.18.2 - optional: true '@types/normalize-package-data@2.4.4': {} @@ -20998,21 +20960,6 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - create-jest@29.7.0(@types/node@22.15.18)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): dependencies: '@jest/types': 29.6.3 @@ -21639,7 +21586,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron-vite@4.0.1(vite@6.4.2(@types/node@20.19.39)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3)): + electron-vite@4.0.1(vite@6.4.2(@types/node@25.5.2)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.4) @@ -21647,7 +21594,7 @@ snapshots: esbuild: 0.25.11 magic-string: 0.30.17 picocolors: 1.1.1 - vite: 6.4.2(@types/node@20.19.39)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3) + vite: 6.4.2(@types/node@25.5.2)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -23355,25 +23302,6 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest-cli@29.7.0(@types/node@22.15.18)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)) @@ -23505,37 +23433,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)): - dependencies: - '@babel/core': 7.28.4 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.4) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 20.19.25 - ts-node: 10.9.2(@types/node@20.19.39)(typescript@5.4.5) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): dependencies: '@babel/core': 7.28.4 @@ -23598,37 +23495,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)): - dependencies: - '@babel/core': 7.28.4 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.4) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 20.19.39 - ts-node: 10.9.2(@types/node@20.19.39)(typescript@5.4.5) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - jest-config@29.7.0(@types/node@22.15.18)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): dependencies: '@babel/core': 7.28.4 @@ -23951,18 +23817,6 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest@29.7.0(@types/node@22.15.18)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)) @@ -27225,12 +27079,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.28.4) - ts-jest@29.4.9(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)))(typescript@5.4.5): + ts-jest@29.4.9(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.4.5)))(typescript@5.4.5): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 29.7.0(@types/node@20.19.39)(ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5)) + jest: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.4.5)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -27303,24 +27157,6 @@ snapshots: yn: 3.1.1 optional: true - ts-node@10.9.2(@types/node@20.19.39)(typescript@5.4.5): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.39 - acorn: 8.15.0 - acorn-walk: 8.3.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.4 - make-error: 1.3.6 - typescript: 5.4.5 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -27357,7 +27193,6 @@ snapshots: typescript: 5.4.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true tslib@2.6.2: {} @@ -27488,8 +27323,7 @@ snapshots: undici-types@7.16.0: {} - undici-types@7.18.2: - optional: true + undici-types@7.18.2: {} undici-types@7.24.4: {} @@ -27658,23 +27492,6 @@ snapshots: tsx: 4.21.0 yaml: 2.8.3 - vite@6.4.2(@types/node@20.19.39)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3): - dependencies: - esbuild: 0.25.11 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.59.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 20.19.39 - fsevents: 2.3.3 - jiti: 2.5.1 - less: 4.3.0 - terser: 5.39.2 - tsx: 4.21.0 - yaml: 2.8.3 - vite@6.4.2(@types/node@25.5.2)(jiti@2.5.1)(less@4.3.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.3): dependencies: esbuild: 0.25.11