From 30ae0aca93dc583202862a1c08264c6b754f496f Mon Sep 17 00:00:00 2001 From: Robert Gruen Date: Fri, 31 Jul 2026 13:21:55 -0700 Subject: [PATCH 01/22] phase 1 done --- ts/docs/plans/agent-command-actions/PLAN.md | 165 +++++++++ ts/docs/plans/agent-command-actions/STATUS.md | 87 +++++ .../src/agent/browserActionHandler.mts | 303 ++++------------- .../src/osNotificationsActionHandler.ts | 2 + .../test/osNotificationsCommands.spec.ts | 24 ++ ts/packages/agents/playerLocal/package.json | 1 + .../src/agent/localPlayerCommands.ts | 319 +++++------------- .../src/agent/localPlayerHandlers.ts | 34 +- .../src/agent/localPlayerSchema.agr | 13 +- .../src/agent/localPlayerSchema.ts | 30 ++ .../test/localPlayerCommandActions.spec.ts | 136 ++++++++ .../test/localPlayerCommands.spec.ts | 41 +++ .../test/localPlayerGrammar.spec.ts | 76 +++++ .../agents/powershell/src/actionHandler.mts | 192 +++-------- .../selfhelp/src/selfHelpActionHandler.ts | 1 + .../selfhelp/test/selfHelpCommands.spec.ts | 25 ++ ts/pnpm-lock.yaml | 9 + ts/tools/actionBrowser/jest.config.cjs | 10 + ts/tools/actionBrowser/package.json | 5 + ts/tools/actionBrowser/src/cli.ts | 60 +++- ts/tools/actionBrowser/src/collect.ts | 176 +++++++++- ts/tools/actionBrowser/src/commands.ts | 175 +++++++--- ts/tools/actionBrowser/src/index.ts | 3 + ts/tools/actionBrowser/src/phrasings.ts | 28 ++ ts/tools/actionBrowser/src/render.ts | 43 ++- ts/tools/actionBrowser/src/types.ts | 29 ++ ts/tools/actionBrowser/test/collect.spec.ts | 42 +++ .../test/commandActionLinks.spec.ts | 141 ++++++++ ts/tools/actionBrowser/test/commands.spec.ts | 160 +++++++++ ts/tools/actionBrowser/test/phrasings.spec.ts | 25 ++ ts/tools/actionBrowser/test/render.spec.ts | 75 ++++ ts/tools/actionBrowser/test/tsconfig.json | 11 + ts/tools/actionBrowser/tsconfig.json | 2 +- 33 files changed, 1751 insertions(+), 692 deletions(-) create mode 100644 ts/docs/plans/agent-command-actions/PLAN.md create mode 100644 ts/docs/plans/agent-command-actions/STATUS.md create mode 100644 ts/packages/agents/osNotifications/test/osNotificationsCommands.spec.ts create mode 100644 ts/packages/agents/playerLocal/test/localPlayerCommandActions.spec.ts create mode 100644 ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts create mode 100644 ts/packages/agents/playerLocal/test/localPlayerGrammar.spec.ts create mode 100644 ts/packages/agents/selfhelp/test/selfHelpCommands.spec.ts create mode 100644 ts/tools/actionBrowser/jest.config.cjs create mode 100644 ts/tools/actionBrowser/test/collect.spec.ts create mode 100644 ts/tools/actionBrowser/test/commandActionLinks.spec.ts create mode 100644 ts/tools/actionBrowser/test/commands.spec.ts create mode 100644 ts/tools/actionBrowser/test/phrasings.spec.ts create mode 100644 ts/tools/actionBrowser/test/render.spec.ts create mode 100644 ts/tools/actionBrowser/test/tsconfig.json diff --git a/ts/docs/plans/agent-command-actions/PLAN.md b/ts/docs/plans/agent-command-actions/PLAN.md new file mode 100644 index 0000000000..9cb2036c91 --- /dev/null +++ b/ts/docs/plans/agent-command-actions/PLAN.md @@ -0,0 +1,165 @@ +# Natural-language actions for every TypeAgent `@` command + +Status: In progress. This document is the source of truth for giving every +bundled executable TypeAgent `@` command a behaviorally equivalent +natural-language action. Progress lives in [STATUS.md](./STATUS.md). + +## Goal and completion contract + +The coverage universe is every bundled command descriptor returned by the +default providers: bare commands, explicit leaf descriptors, inline defaults, +and string-referenced default aliases. Tables that only group children are +namespaces and do not require actions. + +No built-in command category is excluded. Agent and system commands, auth and +OAuth callbacks, configuration, diagnostics, developer tools, lifecycle +operations, browser controls, and platform-specific commands all remain in +scope. Environment-specific commands may return the same unavailable result as +their command path on an incompatible host. + +A command is covered only when: + +1. Its action is exported by a registered schema and resolves unambiguously. +2. Representative natural-language requests translate to that action with the + correct parameters and defaults. +3. Action and command preserve the same side effects, errors, readiness gates, + confirmations, and result behavior. +4. Both paths invoke the same command pipeline or typed helper. +5. Translation and command/action parity are tested. + +`CommandDescriptor.action` is metadata only. Adding a link never creates +natural-language support and does not count as completion by itself. + +## Verified baseline + +Phase 0 replaced the old leaf estimate with executable-endpoint enumeration. +The baseline on 2026-07-31 is: + +- 387 executable command endpoints +- 13 endpoints with valid action links (including inherited defaults) +- 374 endpoints with no action link +- 0 invalid declared links +- `mcpfilesystem` explicitly omitted because its action schema is generated at + runtime and has no static payload without server arguments + +## Mechanism and reference + +- SDK field: `packages/agentSdk/src/command.ts` (~L45) — + `CommandDescriptor.action?: string | { schema: string; actionName: string }`. + This is **metadata only**: it records the equivalent action so tooling can + cross-reference a typed command with its NL action. It does not itself wire + execution. +- Reference implementation to copy (the `@system conversation` / `@system +history` commands are the only 12 that already declare the link): + - Command handlers: `packages/dispatcher/dispatcher/src/context/system/handlers/conversationCommandHandlers.ts` + (each handler has `public readonly action = "newConversation"` etc.) and + `.../handlers/historyCommandHandler.ts`. + - Action schema: `.../system/schema/conversationActionSchema.ts`. + - Action handler: `.../system/action/conversationActionHandler.ts` — each + action **delegates to its equivalent `@conversation` command** so the logic + lives in exactly one place and the two paths cannot drift. + - Tests: `.../test/conversationGrammar.spec.ts` and + `.../test/conversationActionHandler.spec.ts`. +- Coverage verifier: + `node tools/actionBrowser/dist/cli.js --check`. During migration, + `--allow-missing` keeps missing actions visible without failing; invalid, + ambiguous, or dangling declarations always fail. +- Object links use the fully qualified `ActionConfig.schemaName`, for example + `{ schema: "browser.actionDiscovery", actionName: "inferActions" }`. A bare + action name is valid only when unique across the host's registered schemas. + +## Known corrections from review + +- localPlayer `play` was broader than `playFile`; `shuffle` and `mute` toggled + state while the old actions were explicit setters. The first implementation + slice resolved these with `play`, `toggleShuffle`, and `toggleMute` actions. +- Browser `extractKnowledge` has no registered `extractPageKnowledge` action; + `ask` points at an inactive `searchWebMemories` type; and `actions record` is + not equivalent to `createWebFlowFromRecording`. +- Calendar and email login actions are intercepted by readiness preflight when + signed out. Login must intentionally use the existing setup flow, and logout + must call `notifyReadinessChanged()`. +- Action Browser previously discarded schema identity and counted any nonempty + declaration as linked. Phase 0 now resolves exact registered actions before + counting or rendering links. + +## Action implementation rules + +Every new action type MUST follow the onboarding agent's **schema-authoring +guidelines**: the shared `schemaGuidelines` constant in +`packages/dispatcher/dispatcher/src/translation/schemaGuidelines.ts` (exported via +`agent-dispatcher/internal`; it is the exact system prompt the onboarding +`schemaGen` handler uses). In short: + +- Comments live **above** the declaration (no inline trailing comments), ordered + broad-context / aliases → `IMPORTANT`/`NOTE` hard constraints → a one-sentence + **identity line** immediately above the type/property (identity closest to the + declaration). +- The action-level block leads with user/agent example pairs, then rules, then + the one-sentence "what it does" directly above the type. +- Hard constraints embed a concrete `WRONG` / `RIGHT` example above the identity + line. +- Enum-like parameters are explicit unions of string literals (never bare + `string`); the identity line names the underlying enum and default. Don't + overfit examples to real user/benchmark data; prefer widening the right action + over "DO NOT use for" anti-examples. + +Pattern per new action: (1) add the interface to `Schema.ts` with comments +per `schemaGuidelines`; (2) add phrasings to `Schema.agr` (or lean on +schema translation); (3) implement it in the `executeAction` switch, delegating +to the **same** service/helper the command calls (no divergence); (4) add the +`readonly action` link on the command; (5) add grammar + action-handler tests +mirroring the conversation specs. + +Add metadata only after schema registration, execution, translation, and parity +tests exist. Agent commands and actions share a typed helper or service. System +actions delegate to `processCommandNoLock`, following conversation/history, +unless command-string serialization cannot preserve a value; in that case both +paths use a shared typed helper. + +## Phases + +1. **Coverage infrastructure.** Enumerate executable defaults, resolve links by + qualified schema, fail strict collection errors, report runtime-only + omissions, add missing/invalid counters, and generate the endpoint ledger. +2. **Exact existing equivalents.** Audit parameters, defaults, toggles, side + effects, and readiness before linking PowerShell, OS notifications, + self-help, exact localPlayer operations, and exact browser operations. +3. **Complete agent-host actions.** Add the known localPlayer and browser gaps, + auth/OAuth/indexing actions, browser configuration, PowerShell `show`, and + dispatcher diagnostics. No agent-host command remains excluded. +4. **Complete existing system families.** Finish `system.config`, + `system.conversation`, `system.describe`, `system.grammar`, `system.history`, + `system.notify`, and `system.settings`. +5. **Add remaining system families.** Register focused schemas for session, + memory, index, Copilot, collision, construction, feedback, demo, help, + diagnostics, and lifecycle commands. +6. **Closure.** Make strict coverage a permanent regression test and finish + only when missing, ambiguous, dangling, inactive, and unverified counts are + all zero. + +## Verification + +- Build before tests because Jest runs compiled output. +- After each host, run its focused grammar/translation and handler parity + specs, then `node tools/actionBrowser/dist/cli.js --check --allow-missing`. +- Regenerate the catalog and update STATUS from executable endpoints, never + from namespace groups or stale estimates. +- Before completion run `pnpm run test:local`, `pnpm run prettier`, and strict + coverage without `--allow-missing`. +- Smoke-test an exact link, parameterized action, toggle, auth/setup flow, + browser configuration, diagnostic, lifecycle command, default-off agent, and + unavailable platform/client result. + +## Decisions + +- All bundled executable commands are in scope; there are no permanent waivers. +- Fully qualified schema names are canonical in object links. Bare names are a + convenience only when unique within the host. +- Existing enablement, readiness, confirmation, and host-capability rules are + authoritative behavior and must not be weakened. +- Default-off agents stay off. Natural-language invocation follows the same + enable/readiness policy as the command, including enable-on-demand where + already supported. +- Temporary blockers remain visible in STATUS and prevent the zero-gap + milestone. diff --git a/ts/docs/plans/agent-command-actions/STATUS.md b/ts/docs/plans/agent-command-actions/STATUS.md new file mode 100644 index 0000000000..b1317f5a0c --- /dev/null +++ b/ts/docs/plans/agent-command-actions/STATUS.md @@ -0,0 +1,87 @@ +# Status: natural-language actions for every `@` command + +Tracks [PLAN.md](./PLAN.md). Counts come from strict executable-endpoint +collection, not manual estimates. + +## Baseline (2026-07-31) + +| Metric | Count | +| ------------------------------------ | ------------------: | +| Executable command endpoints | 387 | +| Valid linked endpoints | 13 | +| Missing action declarations | 374 | +| Invalid / dangling / ambiguous links | 0 | +| Runtime-only static omissions | 1 (`mcpfilesystem`) | + +## Current coverage + +| Metric | Count | +| ------------------------------------ | ------------------: | +| Executable command endpoints | 387 | +| Valid linked endpoints | 43 | +| Missing action declarations | 344 | +| Invalid / dangling / ambiguous links | 0 | +| Runtime-only static omissions | 1 (`mcpfilesystem`) | + +## Phase checklist + +- [x] Add schema-aware action-link resolution. +- [x] Reject unknown schemas/actions and ambiguous bare names. +- [x] Preserve qualified schema identity in rendered forward/reverse links. +- [x] Enumerate bare, inline-default, and string-default endpoints. +- [x] Exclude namespace-only groups from endpoint totals. +- [x] Fail strict manifest, authored-schema, and command-table collection. +- [x] Report runtime-only schema omissions explicitly. +- [x] Add missing/invalid endpoint counters and migration check mode. +- [ ] Generate and maintain the per-host endpoint ledger. +- [ ] Audit and link exact existing equivalents. +- [ ] Complete all remaining agent-host actions. +- [ ] Complete existing system action families. +- [ ] Add remaining system action families. +- [ ] Enable permanent zero-gap regression check. + +## Implemented hosts and slices + +| Host | Coverage completed in this milestone | +| --------------- | -------------------------------------------------------------------------------------------- | +| localPlayer | All 16 endpoints, including bare status default, general play, and mute/shuffle toggles. | +| osNotifications | `sync`, `test`. | +| selfhelp | Bare default and `ask`. | +| powershell | `list`, `run`, `delete`, `import`; `show` remains a new-action gap. | +| browser | `open`, `close`, `learn`, `actions match`, `actions infer`, and inherited `actions` default. | + +The current migration check is: + +```text +Command action coverage: 43 / 387 endpoints (344 missing, 0 invalid) +Runtime-only schemas omitted: mcpfilesystem +``` + +## Commands + +```powershell +pnpm --filter @typeagent/action-browser build +pnpm --filter @typeagent/action-browser test:local +node tools/actionBrowser/dist/cli.js --check --allow-missing +``` + +Strict completion command (expected to fail until all 344 remaining gaps +close): + +```powershell +node tools/actionBrowser/dist/cli.js --check +``` + +## Known blockers requiring new behavior + +| Host / command | Reason it cannot be linked yet | +| -------------------------- | ---------------------------------------------------------------- | +| browser `extractKnowledge` | Named action is not in a registered schema. | +| browser `ask` | Proposed action is outside active `BrowserActions`. | +| browser `actions record` | Starts recording; proposed action consumes a finished recording. | +| calendar/email login | Readiness setup intercepts execution while signed out. | +| calendar/email logout | Must refresh cached readiness after logout. | + +No built-in command is excluded. OAuth callbacks, dispatcher diagnostics, +PowerShell `show`, browser automation controls, recording stop, and every +system command remain in the endpoint ledger until covered. diff --git a/ts/packages/agents/browser/src/agent/browserActionHandler.mts b/ts/packages/agents/browser/src/agent/browserActionHandler.mts index 505a7581a4..2c5dcc0855 100644 --- a/ts/packages/agents/browser/src/agent/browserActionHandler.mts +++ b/ts/packages/agents/browser/src/agent/browserActionHandler.mts @@ -2360,8 +2360,17 @@ Select actions to create as WebFlows:`; action, context.sessionContext, ); - - return createActionResult(webFlowResult.displayText); + let displayText = webFlowResult.displayText; + if ( + action.actionName === "startGoalDrivenTask" && + (webFlowResult.data as any)?.result?.success && + (webFlowResult.data as any)?.traceId + ) { + displayText += + "\n\n**Would you like to save this as a reusable macro?**\n" + + `Use: \`@browser flows generate ${(webFlowResult.data as any).traceId}\` to create a WebFlow from this trace.`; + } + return createActionResult(displayText); } await browserCtrl.runBrowserAction( @@ -2779,6 +2788,7 @@ class CloseBrowserHandler implements CommandHandlerNoParams { class OpenWebPageHandler implements CommandHandler { public readonly description = "Show a new Web Content view"; + public readonly action = "openWebPage"; public readonly parameters = { args: { site: { @@ -2790,40 +2800,31 @@ class OpenWebPageHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const result = await openWebPage(context, { - actionName: "openWebPage", - schemaName: "browser", - parameters: { - site: params.args.site, - tab: "current", + return executeBrowserAction( + { + actionName: "openWebPage", + schemaName: "browser", + parameters: { + site: params.args.site, + tab: "current", + }, }, - }); - if (result.error) { - displayError(result.error, context); - return; - } - // Display result message if available - if ((result as any).displayContent) { - context.actionIO.setDisplay((result as any).displayContent); - } - // REVIEW: command doesn't set the activity context + context, + ); } } class CloseWebPageHandler implements CommandHandlerNoParams { public readonly description = "Close the new Web Content view"; + public readonly action = "closeWebPage"; public async run(context: ActionContext) { - const result = await closeWebPage(context); - if (result.error) { - displayError(result.error, context); - return; - } - // Display result message if available - if ((result as any).displayContent) { - context.actionIO.setDisplay((result as any).displayContent); - } - - // REVIEW: command doesn't clear the activity context + return executeBrowserAction( + { + actionName: "closeWebPage", + schemaName: "browser", + }, + context, + ); } } @@ -3214,182 +3215,48 @@ class AskAboutPageHandler implements CommandHandler { class DiscoverActionsHandler implements CommandHandlerNoParams { public readonly description = "Discover available actions on the current web page"; + public readonly action = { + schema: "browser.actionDiscovery", + actionName: "detectPageActions", + }; public async run(context: ActionContext) { - const agentContext = context.sessionContext.agentContext; - if (!agentContext.browserControl) { - displayError("No browser connection available.", context); - return; - } - - context.actionIO.appendDisplay("Analyzing page...", "temporary"); - - try { - // Run discovery — calls the LLM to detect page actions, - // auto-saves them to the WebFlowStore scoped to the domain, - // and returns site-scoped actions in data.actions. - const discoveryResult = await handleSchemaDiscoveryAction( - { - actionName: "detectPageActions", - parameters: {}, - } as any, - context.sessionContext, - ); - - const actions: any[] = discoveryResult.data?.actions || []; - - if (actions.length === 0) { - context.actionIO.setDisplay({ - type: "text", - content: "No actions found on this page.", - }); - return; - } - - let md = `### Actions available on this page (${actions.length})\n\n`; - for (const action of actions) { - const params = action.parameters - ? Object.keys(action.parameters) - : []; - const paramStr = - params.length > 0 ? ` *(${params.join(", ")})*` : ""; - md += `- **${action.name}**${paramStr}`; - if (action.description) { - md += ` — ${action.description}`; - } - md += "\n"; - } - - context.actionIO.setDisplay({ - type: "markdown", - content: md, - }); - } catch (error: any) { - displayError( - `Discovery failed: ${error?.message || error}`, - context, - ); - } + return executeBrowserAction( + { + schemaName: "browser.actionDiscovery", + actionName: "detectPageActions", + parameters: {}, + }, + context, + ); } } class InferActionsHandler implements CommandHandlerNoParams { public readonly description = "Analyze page and infer new actions that can be automated"; + public readonly action = { + schema: "browser.actionDiscovery", + actionName: "inferActions", + }; public async run(context: ActionContext) { - const agentContext = context.sessionContext.agentContext; - if (!agentContext.browserControl) { - displayError("No browser connection available.", context); - return; - } - - context.actionIO.appendDisplay( - "Analyzing page for possible actions...", - "temporary", + return executeBrowserAction( + { + schemaName: "browser.actionDiscovery", + actionName: "inferActions", + parameters: {}, + }, + context, ); - - try { - const result = await handleSchemaDiscoveryAction( - { - actionName: "inferActions", - parameters: {}, - } as any, - context.sessionContext, - ); - - const newActions = result.data?.newActions || []; - const existingActions = result.data?.existingActions || []; - - // Store inferred actions for follow-up - agentContext.lastInferredActions = newActions; - agentContext.lastInferredActionsPageUrl = result.data?.pageUrl; - - if (newActions.length > 0 && agentContext.choiceManager) { - // Register choice callback for number responses - const choiceId = agentContext.choiceManager.registerChoice( - async (response) => { - const selectedIndices = response as number[]; - if (selectedIndices.length === 0) { - return createActionResult( - "No actions selected. WebFlow creation cancelled.", - ); - } - - // Convert 0-based indices to 1-based for the handler - const oneBasedIndices = selectedIndices.map( - (i) => i + 1, - ); - - const createResult = await handleSchemaDiscoveryAction( - { - actionName: "createInferredFlows", - parameters: { - selectedIndices: oneBasedIndices, - inferredActions: newActions, - }, - } as any, - context.sessionContext, - undefined, - context.actionIO, - ); - - // Clear stored actions - agentContext.lastInferredActions = undefined; - agentContext.lastInferredActionsPageUrl = undefined; - agentContext.pendingInferChoiceId = undefined; - - return createActionResult(createResult.displayText); - }, - ); - agentContext.pendingInferChoiceId = choiceId; - debug( - `[InferChoice] Registered pending choice: ${choiceId}, newActions: ${newActions.length}`, - ); - - // Build display with choice prompt - let displayText = `Found ${newActions.length + existingActions.length} possible actions on this page: - -`; - let choiceIndex = 0; - - for (const existingAction of existingActions) { - displayText += `${choiceIndex + 1}. ${existingAction.name} - Already available ✓ -`; - choiceIndex++; - } - - for (const newAction of newActions) { - displayText += `${choiceIndex + 1}. ${newAction.name} - ${newAction.description} [NEW] -`; - choiceIndex++; - } - - displayText += ` - -To create WebFlows, say: "build flow 1" or "build flows 1,2" or "build all flows"`; - - context.actionIO.setDisplay({ - type: "markdown", - content: displayText, - }); - } else { - // No new actions or no choice manager - show original message - context.actionIO.setDisplay({ - type: "markdown", - content: result.displayText, - }); - } - } catch (error: any) { - displayError( - `Action inference failed: ${error?.message || error}`, - context, - ); - } } } class LearnHandler implements CommandHandler { public readonly description = "Learn a new action by demonstrating or describing it"; + public readonly action = { + schema: "browser.webFlows", + actionName: "startGoalDrivenTask", + }; public readonly parameters = { args: { goal: { @@ -3402,8 +3269,7 @@ class LearnHandler implements CommandHandler { }; public async run( context: ActionContext, - _params: ParsedCommandParams, - args: string[], + params: ParsedCommandParams, ) { const agentContext = context.sessionContext.agentContext; if (!agentContext.browserControl) { @@ -3411,7 +3277,7 @@ class LearnHandler implements CommandHandler { return; } - const goal = args.join(" ").trim(); + const goal = params.args.goal.trim(); if (!goal) { displayError( "Please provide a goal description. Example: @browser learn add item to cart", @@ -3420,48 +3286,17 @@ class LearnHandler implements CommandHandler { return; } - context.actionIO.appendDisplay( - `Starting goal-driven automation: "${goal}"...`, - "temporary", + return executeBrowserAction( + { + schemaName: "browser.webFlows", + actionName: "startGoalDrivenTask", + parameters: { + goal, + maxSteps: 30, + }, + }, + context, ); - - try { - const result = await handleWebFlowAction( - { - actionName: "startGoalDrivenTask", - parameters: { - goal, - maxSteps: 30, - }, - } as any, - context.sessionContext, - ); - - // If successful, offer to save as WebFlow - if ( - (result.data as any)?.result?.success && - (result.data as any)?.traceId - ) { - let md = result.displayText + "\n\n"; - md += "**Would you like to save this as a reusable macro?**\n"; - md += `Use: \`@browser flows generate ${(result.data as any).traceId}\` to create a WebFlow from this trace.`; - - context.actionIO.setDisplay({ - type: "markdown", - content: md, - }); - } else { - context.actionIO.setDisplay({ - type: "markdown", - content: result.displayText, - }); - } - } catch (error: any) { - displayError( - `Goal-driven task failed: ${error?.message || error}`, - context, - ); - } } } diff --git a/ts/packages/agents/osNotifications/src/osNotificationsActionHandler.ts b/ts/packages/agents/osNotifications/src/osNotificationsActionHandler.ts index fb6384df52..88327b2509 100644 --- a/ts/packages/agents/osNotifications/src/osNotificationsActionHandler.ts +++ b/ts/packages/agents/osNotifications/src/osNotificationsActionHandler.ts @@ -309,6 +309,7 @@ export async function buildAndRetrySync( class OsNotificationsSyncCommandHandler implements CommandHandlerNoParams { public readonly description = "Re-emit currently-present OS notifications through the agent pipeline. Windows only — Linux/macOS do not expose existing notifications."; + public readonly action = "syncOsNotifications"; public async run( actionContext: ActionContext, ): Promise { @@ -323,6 +324,7 @@ class OsNotificationsSyncCommandHandler implements CommandHandlerNoParams { class OsNotificationsTestCommandHandler implements CommandHandler { public readonly description = "Inject a synthetic notification through the agent pipeline (filters, rate limit, dismiss tracking) — useful for verifying the agent end-to-end without an OS notification source."; + public readonly action = "testOsNotification"; public readonly parameters = { args: { message: { diff --git a/ts/packages/agents/osNotifications/test/osNotificationsCommands.spec.ts b/ts/packages/agents/osNotifications/test/osNotificationsCommands.spec.ts new file mode 100644 index 0000000000..754ac1d859 --- /dev/null +++ b/ts/packages/agents/osNotifications/test/osNotificationsCommands.spec.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; +import { instantiate } from "../src/osNotificationsActionHandler.js"; + +describe("osNotifications command action links", () => { + it("links both commands to their shared action implementations", async () => { + const table = (await instantiate().getCommands!({} as any)) as + | CommandDescriptorTable + | CommandDescriptor; + expect( + "commands" in table && + (table.commands.sync as CommandDescriptor).action, + ).toBe("syncOsNotifications"); + expect( + "commands" in table && + (table.commands.test as CommandDescriptor).action, + ).toBe("testOsNotification"); + }); +}); diff --git a/ts/packages/agents/playerLocal/package.json b/ts/packages/agents/playerLocal/package.json index 1c98eaa499..75b4cba87d 100644 --- a/ts/packages/agents/playerLocal/package.json +++ b/ts/packages/agents/playerLocal/package.json @@ -40,6 +40,7 @@ "play-sound": "^1.1.6" }, "devDependencies": { + "@typeagent/action-grammar": "workspace:*", "@typeagent/action-grammar-compiler": "workspace:*", "@typeagent/action-schema-compiler": "workspace:*", "@types/debug": "^4.1.12", diff --git a/ts/packages/agents/playerLocal/src/agent/localPlayerCommands.ts b/ts/packages/agents/playerLocal/src/agent/localPlayerCommands.ts index b806036938..a310d4d122 100644 --- a/ts/packages/agents/playerLocal/src/agent/localPlayerCommands.ts +++ b/ts/packages/agents/playerLocal/src/agent/localPlayerCommands.ts @@ -12,60 +12,22 @@ import { CommandHandlerTable, getCommandInterface, } from "@typeagent/agent-sdk/helpers/command"; -import { - displayStatus, - displaySuccess, - displayWarn, - displayError, -} from "@typeagent/agent-sdk/helpers/display"; +import { displayError } from "@typeagent/agent-sdk/helpers/display"; import { LocalPlayerActionContext, - loadSettings, - saveSettings, + executeLocalPlayerAction, } from "./localPlayerHandlers.js"; -// Helper to get service with error handling -function getService(context: ActionContext) { - const service = context.sessionContext.agentContext.playerService; - if (!service) { - displayError( - "Local player not initialized. Enable it with: @config localPlayer on", - context, - ); - return undefined; - } - return service; -} - // Status command handler class StatusCommandHandler implements CommandHandlerNoParams { public readonly description = "Show local player status"; + public readonly action = "status"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const state = service.getState(); - - if (state.currentTrack) { - const status = state.isPlaying - ? "▶️ Playing" - : state.isPaused - ? "⏸️ Paused" - : "⏹️ Stopped"; - displaySuccess( - `${status}: ${state.currentTrack.name}\n` + - `Volume: ${state.volume}%${state.isMuted ? " (muted)" : ""}\n` + - `Shuffle: ${state.shuffle ? "On" : "Off"} | Repeat: ${state.repeat}\n` + - `Queue: ${state.currentIndex + 1}/${state.queue.length} tracks`, - context, - ); - } else { - displayWarn( - "No track loaded. Use '@localPlayer play' to start.", - context, - ); - } + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "status" }, + context, + ); } } @@ -82,86 +44,46 @@ const playParameters = { const playHandler: CommandHandler = { description: "Play an audio file or resume playback", + action: "play", parameters: playParameters, run: async ( context: ActionContext, params: ParsedCommandParams, ) => { - const service = getService(context); - if (!service) return; - - const fileName = params.args.file; - - if (fileName) { - const success = await service.playFile(fileName); - if (success) { - const state = service.getState(); - displaySuccess( - `▶️ Playing: ${state.currentTrack?.name}`, - context, - ); - } else { - displayError(`Could not find or play: ${fileName}`, context); - } - } else { - // Resume or play first file - const state = service.getState(); - if (state.isPaused) { - service.resume(); - displaySuccess( - `▶️ Resumed: ${state.currentTrack?.name}`, - context, - ); - } else if (state.queue.length > 0) { - await service.playFromQueue(state.currentIndex + 1); - displaySuccess( - `▶️ Playing: ${service.getState().currentTrack?.name}`, - context, - ); - } else { - // Play first file from folder - const success = await service.playFolder(); - if (success) { - displaySuccess( - `▶️ Playing: ${service.getState().currentTrack?.name}`, - context, - ); - } else { - displayWarn( - "No audio files found. Set music folder with: @localPlayer setfolder ", - context, - ); - } - } - } + return executeLocalPlayerAction( + { + schemaName: "localPlayer", + actionName: "play", + ...(params.args.file === undefined + ? {} + : { parameters: { fileName: params.args.file } }), + }, + context, + ); }, }; // Pause command class PauseCommandHandler implements CommandHandlerNoParams { public readonly description = "Pause playback"; + public readonly action = "pause"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - service.pause(); - displaySuccess("⏸️ Paused", context); + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "pause" }, + context, + ); } } // Resume command class ResumeCommandHandler implements CommandHandlerNoParams { public readonly description = "Resume playback"; + public readonly action = "resume"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - service.resume(); - const state = service.getState(); - displaySuccess( - `▶️ Resumed: ${state.currentTrack?.name || ""}`, + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "resume" }, context, ); } @@ -170,62 +92,52 @@ class ResumeCommandHandler implements CommandHandlerNoParams { // Stop command class StopCommandHandler implements CommandHandlerNoParams { public readonly description = "Stop playback"; + public readonly action = "stop"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - service.stop(); - displaySuccess("⏹️ Stopped", context); + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "stop" }, + context, + ); } } // Next command class NextCommandHandler implements CommandHandlerNoParams { public readonly description = "Play next track"; + public readonly action = "next"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const success = await service.next(); - if (success) { - const state = service.getState(); - displaySuccess(`⏭️ Next: ${state.currentTrack?.name}`, context); - } else { - displayWarn("No next track available", context); - } + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "next" }, + context, + ); } } // Previous command class PrevCommandHandler implements CommandHandlerNoParams { public readonly description = "Play previous track"; + public readonly action = "previous"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const success = await service.previous(); - if (success) { - const state = service.getState(); - displaySuccess(`⏮️ Previous: ${state.currentTrack?.name}`, context); - } else { - displayWarn("No previous track available", context); - } + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "previous" }, + context, + ); } } // Folder command - show current folder class FolderCommandHandler implements CommandHandlerNoParams { public readonly description = "Show current music folder"; + public readonly action = "showMusicFolder"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const folder = service.getMusicFolder(); - displayStatus(`📁 Music folder: ${folder}`, context); + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "showMusicFolder" }, + context, + ); } } @@ -240,123 +152,72 @@ const setFolderParameters = { const setFolderHandler: CommandHandler = { description: "Set the music folder path", + action: "setMusicFolder", parameters: setFolderParameters, run: async ( context: ActionContext, params: ParsedCommandParams, ) => { - const service = getService(context); - if (!service) return; - - const folderPath = params.args.path; - const success = service.setMusicFolder(folderPath); - - if (success) { - // Persist the music folder setting - const storage = context.sessionContext.agentContext.storage; - if (storage) { - const settings = await loadSettings(storage); - settings.musicFolder = folderPath; - await saveSettings(storage, settings); - } - - const files = service.listFiles(); - displaySuccess( - `📁 Music folder set to: ${folderPath}\nFound ${files.length} audio files`, - context, - ); - } else { - displayError(`Invalid folder path: ${folderPath}`, context); - } + return executeLocalPlayerAction( + { + schemaName: "localPlayer", + actionName: "setMusicFolder", + parameters: { folderPath: params.args.path }, + }, + context, + ); }, }; // List command class ListCommandHandler implements CommandHandlerNoParams { public readonly description = "List audio files in music folder"; + public readonly action = "listFiles"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const files = service.listFiles(); - - if (files.length === 0) { - displayWarn("No audio files found in music folder", context); - return; - } - - const fileList = files - .slice(0, 20) - .map((f, i) => `${i + 1}. ${f.name}`) - .join("\n"); - - let message = `🎵 Found ${files.length} audio files:\n${fileList}`; - if (files.length > 20) { - message += `\n...and ${files.length - 20} more`; - } - - displaySuccess(message, context); + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "listFiles" }, + context, + ); } } // Queue command class QueueCommandHandler implements CommandHandlerNoParams { public readonly description = "Show playback queue"; + public readonly action = "showQueue"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const queue = service.getQueue(); - const state = service.getState(); - - if (queue.length === 0) { - displayWarn("Queue is empty", context); - return; - } - - const queueList = queue - .slice(0, 20) - .map((track, i) => { - const current = i === state.currentIndex ? " ▶️" : ""; - return `${i + 1}. ${track.name}${current}`; - }) - .join("\n"); - - let message = `📋 Queue (${queue.length} tracks):\n${queueList}`; - if (queue.length > 20) { - message += `\n...and ${queue.length - 20} more`; - } - - displaySuccess(message, context); + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "showQueue" }, + context, + ); } } // Clear command class ClearCommandHandler implements CommandHandlerNoParams { public readonly description = "Clear playback queue"; + public readonly action = "clearQueue"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - service.clearQueue(); - displaySuccess("🗑️ Queue cleared", context); + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "clearQueue" }, + context, + ); } } // Shuffle command class ShuffleCommandHandler implements CommandHandlerNoParams { public readonly description = "Toggle shuffle mode"; + public readonly action = "toggleShuffle"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const state = service.getState(); - service.setShuffle(!state.shuffle); - displaySuccess(`🔀 Shuffle: ${!state.shuffle ? "On" : "Off"}`, context); + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "toggleShuffle" }, + context, + ); } } @@ -371,41 +232,39 @@ const volumeParameters = { const volumeHandler: CommandHandler = { description: "Set volume level (0-100)", + action: "setVolume", parameters: volumeParameters, run: async ( context: ActionContext, params: ParsedCommandParams, ) => { - const service = getService(context); - if (!service) return; - const level = parseInt(params.args.level, 10); if (isNaN(level) || level < 0 || level > 100) { displayError("Volume must be a number between 0 and 100", context); return; } - service.setVolume(level); - displaySuccess(`🔊 Volume: ${level}%`, context); + return executeLocalPlayerAction( + { + schemaName: "localPlayer", + actionName: "setVolume", + parameters: { level }, + }, + context, + ); }, }; // Mute command class MuteCommandHandler implements CommandHandlerNoParams { public readonly description = "Toggle mute"; + public readonly action = "toggleMute"; public async run(context: ActionContext) { - const service = getService(context); - if (!service) return; - - const state = service.getState(); - if (state.isMuted) { - service.unmute(); - displaySuccess(`🔊 Unmuted (Volume: ${state.volume}%)`, context); - } else { - service.mute(); - displaySuccess("🔇 Muted", context); - } + return executeLocalPlayerAction( + { schemaName: "localPlayer", actionName: "toggleMute" }, + context, + ); } } diff --git a/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts b/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts index f569ff775a..f2e45efef9 100644 --- a/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts +++ b/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts @@ -121,7 +121,7 @@ async function updateLocalPlayerContext( } } -async function executeLocalPlayerAction( +export async function executeLocalPlayerAction( action: TypeAgentAction, context: ActionContext, ) { @@ -135,6 +135,9 @@ async function executeLocalPlayerAction( try { switch (action.actionName) { + case "play": + return handlePlay(playerService, action.parameters?.fileName); + case "playFile": return handlePlayFile( playerService, @@ -172,6 +175,9 @@ async function executeLocalPlayerAction( case "previous": return handlePrevious(playerService); + case "toggleShuffle": + return handleToggleShuffle(playerService); + case "shuffle": return handleShuffle(playerService, action.parameters.on); @@ -187,6 +193,9 @@ async function executeLocalPlayerAction( action.parameters.amount, ); + case "toggleMute": + return handleToggleMute(playerService); + case "mute": return handleMute(playerService, action.parameters.isMuted); @@ -236,6 +245,21 @@ async function executeLocalPlayerAction( // Action handlers +async function handlePlay(service: LocalPlayerService, fileName?: string) { + if (fileName) { + return handlePlayFile(service, fileName); + } + + const state = service.getState(); + if (state.isPaused) { + return handleResume(service); + } + if (state.queue.length > 0) { + return handlePlayFromQueue(service, state.currentIndex + 1); + } + return handlePlayFolder(service); +} + async function handlePlayFile(service: LocalPlayerService, fileName: string) { const success = await service.playFile(fileName); if (success) { @@ -342,6 +366,10 @@ function handleShuffle(service: LocalPlayerService, on: boolean) { ); } +function handleToggleShuffle(service: LocalPlayerService) { + return handleShuffle(service, !service.getState().shuffle); +} + function handleRepeat( service: LocalPlayerService, mode: "off" | "one" | "all", @@ -379,6 +407,10 @@ function handleMute(service: LocalPlayerService, isMuted: boolean) { } } +function handleToggleMute(service: LocalPlayerService) { + return handleMute(service, !service.getState().isMuted); +} + function handleListFiles(service: LocalPlayerService, folderPath?: string) { const files = service.listFiles(folderPath); diff --git a/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.agr b/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.agr index 6ba1d3cc62..d9603bd2d9 100644 --- a/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.agr +++ b/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.agr @@ -14,7 +14,9 @@ import { LocalPlayerActions } from "./localPlayerSchema.ts"; | | | + | | + | | | | @@ -32,7 +34,10 @@ import { LocalPlayerActions } from "./localPlayerSchema.ts"; = (what('s | is) | show) (playing | status | now playing)? -> { actionName: "status" }; - = ; + = | ; + + = play ((the)? (music | audio))? + -> { actionName: "play" }; = play (the)? $(n:) (track | song)? -> { @@ -67,6 +72,12 @@ import { LocalPlayerActions } from "./localPlayerSchema.ts"; = set volume (to)? $(n:number) (percent)? -> { actionName: "setVolume", parameters: { level: n } }; + = toggle (the)? shuffle (mode)? + -> { actionName: "toggleShuffle" }; + + = toggle (the)? mute (state)? + -> { actionName: "toggleMute" }; + = mute (the)? (music | sound | audio)? -> { actionName: "mute", parameters: { isMuted: true } }; = unmute (the)? (music | sound | audio)? -> { actionName: "mute", parameters: { isMuted: false } }; diff --git a/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.ts b/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.ts index 644caa2080..1db252246b 100644 --- a/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.ts +++ b/ts/packages/agents/playerLocal/src/agent/localPlayerSchema.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. export type LocalPlayerActions = + | PlayAction | PlayFileAction | PlayFolderAction | PlayFromQueueAction @@ -11,10 +12,12 @@ export type LocalPlayerActions = | StopAction | NextAction | PreviousAction + | ToggleShuffleAction | ShuffleAction | RepeatAction | SetVolumeAction | ChangeVolumeAction + | ToggleMuteAction | MuteAction | ListFilesAction | SearchFilesAction @@ -27,6 +30,19 @@ export type LocalPlayerActions = export type LocalPlayerEntities = FilePath; export type FilePath = string; +// user: play music +// agent: { "actionName": "play" } +// user: play the file sunrise.mp3 +// agent: { "actionName": "play", "parameters": { "fileName": "sunrise.mp3" } } +// Play a named file, or resume/default playback when no file is named. +export interface PlayAction { + actionName: "play"; + parameters?: { + // The optional file name or path to play. + fileName?: string; + }; +} + // Play a specific audio file by path or name export interface PlayFileAction { actionName: "playFile"; @@ -86,6 +102,13 @@ export interface PreviousAction { actionName: "previous"; } +// user: toggle shuffle +// agent: { "actionName": "toggleShuffle" } +// Toggle shuffle to the opposite of its current state. +export interface ToggleShuffleAction { + actionName: "toggleShuffle"; +} + // Turn shuffle on or off export interface ShuffleAction { actionName: "shuffle"; @@ -121,6 +144,13 @@ export interface ChangeVolumeAction { }; } +// user: toggle mute +// agent: { "actionName": "toggleMute" } +// Toggle mute to the opposite of its current state. +export interface ToggleMuteAction { + actionName: "toggleMute"; +} + // Mute or unmute audio export interface MuteAction { actionName: "mute"; diff --git a/ts/packages/agents/playerLocal/test/localPlayerCommandActions.spec.ts b/ts/packages/agents/playerLocal/test/localPlayerCommandActions.spec.ts new file mode 100644 index 0000000000..3b3009d33a --- /dev/null +++ b/ts/packages/agents/playerLocal/test/localPlayerCommandActions.spec.ts @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { executeLocalPlayerAction } from "../src/agent/localPlayerHandlers.js"; + +function makeContext(service: object) { + return { + sessionContext: { + agentContext: { playerService: service, storage: undefined }, + }, + } as any; +} + +function makeService(overrides: Record = {}) { + const state = { + isPaused: false, + isMuted: false, + shuffle: false, + currentIndex: 0, + queue: [] as object[], + ...((overrides.state as object | undefined) ?? {}), + }; + const calls = { + playFile: [] as unknown[][], + playFolder: [] as unknown[][], + playFromQueue: [] as unknown[][], + resume: [] as unknown[][], + setShuffle: [] as unknown[][], + mute: [] as unknown[][], + unmute: [] as unknown[][], + }; + return { + state, + calls, + getState: () => state, + playFile: async (...args: unknown[]) => { + calls.playFile.push(args); + return true; + }, + playFolder: async (...args: unknown[]) => { + calls.playFolder.push(args); + return true; + }, + playFromQueue: async (...args: unknown[]) => { + calls.playFromQueue.push(args); + return true; + }, + resume: (...args: unknown[]) => { + calls.resume.push(args); + return true; + }, + setShuffle: (on: boolean) => { + calls.setShuffle.push([on]); + state.shuffle = on; + return true; + }, + mute: (...args: unknown[]) => { + calls.mute.push(args); + state.isMuted = true; + return true; + }, + unmute: (...args: unknown[]) => { + calls.unmute.push(args); + state.isMuted = false; + return true; + }, + ...overrides, + }; +} + +async function run(service: object, action: object) { + return executeLocalPlayerAction( + { schemaName: "localPlayer", ...action } as any, + makeContext(service), + ); +} + +describe("localPlayer command-equivalent actions", () => { + it("plays a named file when play includes fileName", async () => { + const service = makeService(); + + await run(service, { + actionName: "play", + parameters: { fileName: "sunrise.mp3" }, + }); + + expect(service.calls.playFile).toEqual([["sunrise.mp3"]]); + }); + + it("resumes paused playback when play has no file", async () => { + const service = makeService({ state: { isPaused: true } }); + + await run(service, { actionName: "play" }); + + expect(service.calls.resume).toHaveLength(1); + expect(service.calls.playFolder).toHaveLength(0); + }); + + it("plays the current queue position when a queue exists", async () => { + const service = makeService({ + state: { currentIndex: 2, queue: [{}, {}, {}] }, + }); + + await run(service, { actionName: "play" }); + + expect(service.calls.playFromQueue).toEqual([[3]]); + expect(service.calls.playFolder).toHaveLength(0); + }); + + it("plays the music folder when there is no paused track or queue", async () => { + const service = makeService(); + + await run(service, { actionName: "play" }); + + expect(service.calls.playFolder).toEqual([[undefined, false]]); + }); + + it("toggles shuffle in both directions", async () => { + const service = makeService(); + + await run(service, { actionName: "toggleShuffle" }); + await run(service, { actionName: "toggleShuffle" }); + + expect(service.calls.setShuffle).toEqual([[true], [false]]); + }); + + it("toggles mute in both directions", async () => { + const service = makeService(); + + await run(service, { actionName: "toggleMute" }); + await run(service, { actionName: "toggleMute" }); + + expect(service.calls.mute).toHaveLength(1); + expect(service.calls.unmute).toHaveLength(1); + }); +}); diff --git a/ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts b/ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts new file mode 100644 index 0000000000..9e8768d0ab --- /dev/null +++ b/ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; +import { getLocalPlayerCommandInterface } from "../src/agent/localPlayerCommands.js"; + +describe("localPlayer command action links", () => { + it("declares only action-equivalent command endpoints", async () => { + const table = (await getLocalPlayerCommandInterface().getCommands( + {} as any, + )) as CommandDescriptorTable; + const expected = { + status: "status", + play: "play", + pause: "pause", + resume: "resume", + stop: "stop", + next: "next", + prev: "previous", + folder: "showMusicFolder", + setfolder: "setMusicFolder", + list: "listFiles", + queue: "showQueue", + clear: "clearQueue", + shuffle: "toggleShuffle", + volume: "setVolume", + mute: "toggleMute", + }; + + for (const [command, action] of Object.entries(expected)) { + expect((table.commands[command] as CommandDescriptor).action).toBe( + action, + ); + } + + expect(Object.keys(expected)).toHaveLength(15); + }); +}); diff --git a/ts/packages/agents/playerLocal/test/localPlayerGrammar.spec.ts b/ts/packages/agents/playerLocal/test/localPlayerGrammar.spec.ts new file mode 100644 index 0000000000..34dbb8a91e --- /dev/null +++ b/ts/packages/agents/playerLocal/test/localPlayerGrammar.spec.ts @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import * as fs from "node:fs"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; +import { + compileGrammarToNFA, + loadGrammarRulesNoThrow, + matchNFA, +} from "@typeagent/action-grammar"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const grammarPath = path.resolve( + here, + "..", + "..", + "src", + "agent", + "localPlayerSchema.agr", +); + +function makeMatcher() { + const errors: string[] = []; + const grammar = loadGrammarRulesNoThrow( + "localPlayerSchema.agr", + fs.readFileSync(grammarPath, "utf-8"), + errors, + ); + if (grammar === undefined || errors.length > 0) { + throw new Error( + `Failed to parse localPlayer grammar: ${errors.join("; ")}`, + ); + } + const nfa = compileGrammarToNFA(grammar, "localPlayer"); + return (input: string) => { + const result = matchNFA(nfa, input.toLowerCase().split(/\s+/), false); + return result.matched ? (result.actionValue as any) : undefined; + }; +} + +describe("localPlayer command-equivalent grammar", () => { + const match = makeMatcher(); + + it.each(["play", "play music", "play the audio"])( + "maps %p to general play", + (input) => { + expect(match(input)).toEqual({ actionName: "play" }); + }, + ); + + it("keeps numbered tracks on playFromQueue", () => { + expect(match("play track 3")).toEqual({ + actionName: "playFromQueue", + parameters: { trackNumber: 3 }, + }); + }); + + it("maps explicit shuffle toggling to toggleShuffle", () => { + expect(match("toggle shuffle")).toEqual({ + actionName: "toggleShuffle", + }); + }); + + it("distinguishes toggle mute from mute and unmute setters", () => { + expect(match("toggle mute")).toEqual({ actionName: "toggleMute" }); + expect(match("mute")).toEqual({ + actionName: "mute", + parameters: { isMuted: true }, + }); + expect(match("unmute")).toEqual({ + actionName: "mute", + parameters: { isMuted: false }, + }); + }); +}); diff --git a/ts/packages/agents/powershell/src/actionHandler.mts b/ts/packages/agents/powershell/src/actionHandler.mts index b85422b23e..e170f76fb0 100644 --- a/ts/packages/agents/powershell/src/actionHandler.mts +++ b/ts/packages/agents/powershell/src/actionHandler.mts @@ -728,9 +728,18 @@ async function handlePowerShellFlowAction( let _agentStore: PowerShellStore | undefined; +function executeBuiltInPowerShellAction( + action: { actionName: string; parameters?: Record }, + context: ActionContext, +): Promise { + (context as any).__store = _agentStore; + return handlePowerShellFlowAction(action, context); +} + class ImportScriptHandler implements CommandHandler { public readonly description = "Import a PowerShell script as a reusable PowerShell flow"; + public readonly action = "importPowerShellFlow"; public readonly parameters = { args: { filePath: { @@ -749,83 +758,35 @@ class ImportScriptHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const store = _agentStore; - if (!store) { - throw new Error("Script flow store not available"); - } - - const filePath = params.args.filePath; - if (!filePath) { - throw new Error("Missing required argument: filePath"); - } - - const resolvedPath = isAbsolute(filePath) - ? filePath - : resolve(process.cwd(), filePath); - - if (!existsSync(resolvedPath)) { - throw new Error(`File not found: ${resolvedPath}`); - } - - if (extname(resolvedPath).toLowerCase() !== ".ps1") { - throw new Error("Only PowerShell (.ps1) files can be imported"); - } - - const scriptContent = readFileSync(resolvedPath, "utf8"); - if (!scriptContent.trim()) { - throw new Error("Script file is empty"); - } - - const analyzer = new ScriptAnalyzer(); - const overrideName = params.flags.actionName; - const recipe = await analyzer.analyze( - scriptContent, - resolvedPath, - overrideName, - ); - - if (store.hasFlow(recipe.actionName)) { - throw new Error( - `A flow named '${recipe.actionName}' already exists. Delete it first or use --actionName to specify a different name.`, - ); - } - - await store.saveFlow(recipe, "manual"); - await context.sessionContext.reloadAgentSchema(); - - const patternList = recipe.grammarPatterns - .map((p) => ` "${p.pattern}"`) - .join("\n"); - context.actionIO.setDisplay( - `Imported PowerShell flow '${recipe.actionName}': ${recipe.description}\n\nGrammar patterns:\n${patternList}`, + return executeBuiltInPowerShellAction( + { + actionName: "importPowerShellFlow", + parameters: { + filePath: params.args.filePath, + ...(params.flags.actionName === undefined + ? {} + : { actionName: params.flags.actionName }), + }, + }, + context, ); } } class ListHandler implements CommandHandlerNoParams { public readonly description = "List all registered PowerShell flows"; + public readonly action = "listPowerShellFlows"; public async run(context: ActionContext) { - const store = _agentStore; - if (!store) { - throw new Error("Script flow store not available"); - } - const entries = store.listFlows(); - if (entries.length === 0) { - context.actionIO.setDisplay("No PowerShell flows registered."); - return; - } - const lines = entries.map( - (e) => - ` ${e.actionName}: ${e.description} [usage: ${e.usageCount}]${e.source === "seed" ? " (sample)" : ""}`, - ); - context.actionIO.setDisplay( - `Script flows (${entries.length}):\n${lines.join("\n")}`, + return executeBuiltInPowerShellAction( + { actionName: "listPowerShellFlows" }, + context, ); } } class RunHandler implements CommandHandler { public readonly description = "Execute a PowerShell flow by name"; + public readonly action = "executePowerShellFlow"; public readonly parameters = { args: { flowName: { @@ -844,76 +805,27 @@ class RunHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const store = _agentStore; - if (!store) { - throw new Error("Script flow store not available"); - } - - const flowName = params.args.flowName; - if (!flowName) { - throw new Error("Missing required argument: flowName"); - } - - const flow = await store.getFlow(flowName); - if (!flow) { - throw new Error( - `Unknown PowerShell flow '${flowName}'. Use '@powershell list' to see available flows.`, - ); - } - - const script = await store.getScript(flowName); - if (!script) { - throw new Error(`Script not found for flow: ${flowName}`); - } - - let flowParameters: Record = {}; - if (params.flags.flowParametersJson) { - try { - flowParameters = JSON.parse(params.flags.flowParametersJson); - } catch { - throw new Error( - `Invalid JSON in --flowParametersJson: ${params.flags.flowParametersJson}`, - ); - } - } - - expandEnvVarsInParams(flowParameters, flow.parameters); - const pathError = validatePathParameters( - flowParameters, - flow.parameters, - ); - if (pathError) { - throw new Error(pathError); - } - const validationError = validateParameterRules( - flowParameters, - flow.parameters, + return executeBuiltInPowerShellAction( + { + actionName: "executePowerShellFlow", + parameters: { + flowName: params.args.flowName, + ...(params.flags.flowParametersJson === undefined + ? {} + : { + flowParametersJson: + params.flags.flowParametersJson, + }), + }, + }, + context, ); - if (validationError) { - throw new Error(validationError); - } - - const result = await executeFlowScript(flow, script, flowParameters); - if (result.error !== undefined) { - throw new Error(String(result.error)); - } - - await store.recordUsage(flowName); - if ("displayContent" in result && result.displayContent) { - const content = result.displayContent; - const text = - typeof content === "string" - ? content - : "content" in content - ? content.content - : String(content); - context.actionIO.setDisplay(text); - } } } class DeleteHandler implements CommandHandler { public readonly description = "Delete a PowerShell flow by name"; + public readonly action = "deletePowerShellFlow"; public readonly parameters = { args: { name: { @@ -925,23 +837,13 @@ class DeleteHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const store = _agentStore; - if (!store) { - throw new Error("Script flow store not available"); - } - - const name = params.args.name; - if (!name) { - throw new Error("Missing required argument: name"); - } - - const deleted = await store.deleteFlow(name); - if (!deleted) { - throw new Error(`Script flow not found: ${name}`); - } - - await context.sessionContext.reloadAgentSchema(); - context.actionIO.setDisplay(`Deleted PowerShell flow: ${name}`); + return executeBuiltInPowerShellAction( + { + actionName: "deletePowerShellFlow", + parameters: { name: params.args.name }, + }, + context, + ); } } diff --git a/ts/packages/agents/selfhelp/src/selfHelpActionHandler.ts b/ts/packages/agents/selfhelp/src/selfHelpActionHandler.ts index 6b482c2e9b..dd1600ebec 100644 --- a/ts/packages/agents/selfhelp/src/selfHelpActionHandler.ts +++ b/ts/packages/agents/selfhelp/src/selfHelpActionHandler.ts @@ -154,6 +154,7 @@ async function executeAction( class AskCommandHandler implements CommandHandler { public readonly description = "Find the TypeAgent command for what you want to do (e.g. 'create a new conversation')."; + public readonly action = "answerTypeAgentQuestion"; public readonly parameters = { args: { question: { diff --git a/ts/packages/agents/selfhelp/test/selfHelpCommands.spec.ts b/ts/packages/agents/selfhelp/test/selfHelpCommands.spec.ts new file mode 100644 index 0000000000..b262173fdf --- /dev/null +++ b/ts/packages/agents/selfhelp/test/selfHelpCommands.spec.ts @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; +import { instantiate } from "../src/selfHelpActionHandler.js"; + +describe("selfhelp command action links", () => { + it("links ask and its bare default to answerTypeAgentQuestion", async () => { + const table = (await instantiate().getCommands!({} as any)) as + | CommandDescriptorTable + | CommandDescriptor; + expect( + "commands" in table && + (table.commands.ask as CommandDescriptor).action, + ).toBe("answerTypeAgentQuestion"); + expect( + "commands" in table && + typeof table.defaultSubCommand !== "string" && + table.defaultSubCommand?.action, + ).toBe("answerTypeAgentQuestion"); + }); +}); diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index 1404dce90f..93283966b0 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -3155,6 +3155,9 @@ importers: specifier: ^1.1.6 version: 1.1.6 devDependencies: + '@typeagent/action-grammar': + specifier: workspace:* + version: link:../../actionGrammar '@typeagent/action-grammar-compiler': specifier: workspace:* version: link:../../actionGrammarCompiler @@ -6578,6 +6581,12 @@ importers: specifier: workspace:* version: link:../../packages/defaultAgentProvider devDependencies: + '@types/jest': + specifier: ^29.5.7 + version: 29.5.14 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 diff --git a/ts/tools/actionBrowser/jest.config.cjs b/ts/tools/actionBrowser/jest.config.cjs new file mode 100644 index 0000000000..357467404f --- /dev/null +++ b/ts/tools/actionBrowser/jest.config.cjs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +module.exports = { + testMatch: ["/dist/test/**/*.spec.js"], + testEnvironment: "node", + moduleNameMapper: { + "^../src/(.*)$": "/dist/$1", + }, +}; diff --git a/ts/tools/actionBrowser/package.json b/ts/tools/actionBrowser/package.json index 28a7baba2f..f1f4af4c87 100644 --- a/ts/tools/actionBrowser/package.json +++ b/ts/tools/actionBrowser/package.json @@ -25,8 +25,11 @@ "build": "npm run tsc", "clean": "rimraf --glob dist *.tsbuildinfo *.done.build.log", "docs:action-browser": "node ./dist/cli.js", + "jest-esm": "node --no-warnings --experimental-vm-modules ./node_modules/jest/bin/jest.js", "prettier": "prettier --check . --ignore-path ../../.prettierignore", "prettier:fix": "prettier --write . --ignore-path ../../.prettierignore", + "test": "npm run test:local", + "test:local": "pnpm run jest-esm --testPathPattern=\".*[.]spec[.]js\"", "tsc": "tsc -b" }, "dependencies": { @@ -37,6 +40,8 @@ "default-agent-provider": "workspace:*" }, "devDependencies": { + "@types/jest": "^29.5.7", + "jest": "^29.7.0", "rimraf": "^6.0.1", "typescript": "~5.4.5" } diff --git a/ts/tools/actionBrowser/src/cli.ts b/ts/tools/actionBrowser/src/cli.ts index 6e51cd2c42..6820f8e1f9 100644 --- a/ts/tools/actionBrowser/src/cli.ts +++ b/ts/tools/actionBrowser/src/cli.ts @@ -13,12 +13,15 @@ import { renderHtml } from "./render.js"; const HELP = `action-browser — generate the self-contained TypeAgent Action Browser. Usage: - action-browser [--out ] [--json] [--help] + action-browser [--out ] [--json] [--check] [--allow-missing] [--help] Options: --out Output HTML path. Defaults to ts/docs/overview/action-browser.html. --json Also write the raw catalog JSON next to the HTML output. + --check Require valid links and action coverage for every endpoint. + --allow-missing + Report the migration baseline without failing on missing links. --help Show this message. The generator reads bundled agent manifests, action schemas, and grammar @@ -39,6 +42,8 @@ async function main(): Promise { options: { out: { type: "string" }, json: { type: "boolean", default: false }, + check: { type: "boolean", default: false }, + "allow-missing": { type: "boolean", default: false }, help: { type: "boolean", default: false }, }, allowPositionals: false, @@ -55,7 +60,56 @@ async function main(): Promise { ? path.resolve(values.out) : defaultOutPath(); - const catalog = await collectCatalog(); + const catalog = await collectCatalog({ strict: values.check }); + + if (values.check) { + const issues = catalog.commandActionLinkIssues; + const missing = catalog.missingCommandActions; + process.stdout.write( + `Command action coverage: ${catalog.counts.linkedCommandEndpoints} / ` + + `${catalog.counts.commandEndpoints} endpoints ` + + `(${missing.length} missing, ${issues.length} invalid)\n`, + ); + if (issues.length > 0) { + for (const issue of issues) { + const command = + issue.host === "system" + ? `@${issue.path}` + : issue.path.length > 0 + ? `@${issue.host} ${issue.path}` + : `@${issue.host}`; + const action = issue.schema + ? `${issue.schema}.${issue.actionName}` + : issue.actionName; + process.stderr.write( + `${command} -> ${action}: ${issue.message}\n`, + ); + } + } + if (!values["allow-missing"]) { + for (const gap of missing) { + const command = + gap.host === "system" + ? `@${gap.path}` + : gap.path.length > 0 + ? `@${gap.host} ${gap.path}` + : `@${gap.host}`; + process.stderr.write(`${command}: no equivalent action\n`); + } + } + if (catalog.runtimeOnlySchemas.length > 0) { + process.stdout.write( + `Runtime-only schemas omitted: ${catalog.runtimeOnlySchemas.join(", ")}\n`, + ); + } + if ( + issues.length > 0 || + (missing.length > 0 && !values["allow-missing"]) + ) { + process.exitCode = 1; + } + return; + } await fs.mkdir(path.dirname(outPath), { recursive: true }); @@ -75,7 +129,7 @@ async function main(): Promise { process.stdout.write( `Action browser: ${catalog.counts.agents} agents, ` + `${catalog.counts.actions} actions, ` + - `${catalog.counts.commands} commands\n`, + `${catalog.counts.commandEndpoints} command endpoints\n`, ); process.stdout.write(`wrote ${outPath}\n`); } diff --git a/ts/tools/actionBrowser/src/collect.ts b/ts/tools/actionBrowser/src/collect.ts index 5ffbf9e952..bc2f35afe1 100644 --- a/ts/tools/actionBrowser/src/collect.ts +++ b/ts/tools/actionBrowser/src/collect.ts @@ -14,7 +14,15 @@ import { extractPhrasings, extractCompiledPhrasings } from "./phrasings.js"; import { collectCommands } from "./commands.js"; import { categoryForAgent } from "./categories.js"; import { joinComments } from "./util.js"; -import type { ActionInfo, AgentInfo, Catalog, SchemaInfo } from "./types.js"; +import type { + ActionInfo, + AgentInfo, + Catalog, + CommandActionGap, + CommandActionLinkIssue, + CommandInfo, + SchemaInfo, +} from "./types.js"; /** * Collect the full capability catalog from the workspace's bundled agents. @@ -26,7 +34,13 @@ import type { ActionInfo, AgentInfo, Catalog, SchemaInfo } from "./types.js"; * capabilities (MCP tools, recorded web flows) are intentionally out of scope * so the catalog stays reproducible for the documentation build. */ -export async function collectCatalog(): Promise { +export type CollectCatalogOptions = { + strict?: boolean; +}; + +export async function collectCatalog( + options: CollectCatalogOptions = {}, +): Promise { // `undefined` builds only the static bundled-agent provider (no instance // directory, so no installed/MCP agents are pulled in). const providers = getDefaultAppAgentProviders(undefined); @@ -37,8 +51,12 @@ export async function collectCatalog(): Promise { for (const name of provider.getAppAgentNames()) { try { manifests[name] = await provider.getAppAgentManifest(name); - } catch { - // Skip agents whose manifest can't be resolved statically. + } catch (error) { + if (options.strict) { + throw new Error( + `Failed to load manifest for agent "${name}": ${getErrorMessage(error)}`, + ); + } } } } @@ -61,6 +79,7 @@ export async function collectCatalog(): Promise { } const agents: AgentInfo[] = []; + const runtimeOnlySchemas: string[] = []; let actionCount = 0; for (const [agentName, agentConfigs] of [...configsByAgent].sort((a, b) => @@ -68,7 +87,15 @@ export async function collectCatalog(): Promise { )) { const schemas: SchemaInfo[] = []; for (const config of sortSchemas(agentConfigs, agentName)) { - const actions = collectActions(provider, config); + if (isRuntimeOnlySchema(config)) { + runtimeOnlySchemas.push(config.schemaName); + continue; + } + const actions = collectActions( + provider, + config, + options.strict ?? false, + ); actionCount += actions.length; schemas.push({ schemaName: config.schemaName, @@ -91,20 +118,143 @@ export async function collectCatalog(): Promise { }); } - const commands = await collectCommands(); + const commands = await collectCommands({ + strict: options.strict ?? false, + }); + const commandActionLinkIssues = resolveCommandActionLinks(agents, commands); + const missingCommandActions = findMissingCommandActions(commands); + const commandEndpoints = commands.filter((command) => command.executable); + const linkedCommandEndpoints = commandEndpoints.filter( + (command) => command.action?.resolvedSchema !== undefined, + ).length; return { generatedAt: new Date().toISOString(), agents, commands, + commandActionLinkIssues, + missingCommandActions, + runtimeOnlySchemas: runtimeOnlySchemas.sort(), counts: { agents: agents.length, actions: actionCount, commands: commands.length, + commandEndpoints: commandEndpoints.length, + linkedCommandEndpoints, + missingCommandActions: missingCommandActions.length, + invalidCommandActionLinks: commandActionLinkIssues.length, }, }; } +export function isRuntimeOnlySchema(config: ActionConfig): boolean { + if ( + config.schemaFilePath !== undefined || + config.originalSchemaFilePath !== undefined + ) { + return false; + } + try { + const schema = + typeof config.schemaFile === "function" + ? config.schemaFile() + : config.schemaFile; + return schema.content.trim().length === 0; + } catch { + return false; + } +} + +/** Resolve every declared command link to exactly one registered action. */ +export function resolveCommandActionLinks( + agents: AgentInfo[], + commands: CommandInfo[], +): CommandActionLinkIssue[] { + const schemasByAgent = new Map(); + for (const agent of agents) { + schemasByAgent.set(agent.name, agent.schemas); + } + + const issues: CommandActionLinkIssue[] = []; + for (const command of commands) { + const link = command.action; + if (link === undefined) { + continue; + } + delete link.resolvedSchema; + + const schemas = schemasByAgent.get(command.host) ?? []; + const candidates = + link.schema === undefined + ? schemas.filter((schema) => + schema.actions.some( + (action) => action.actionName === link.actionName, + ), + ) + : schemas.filter((schema) => schema.schemaName === link.schema); + + if (link.schema !== undefined && candidates.length === 0) { + issues.push( + createLinkIssue( + command, + `Schema "${link.schema}" is not registered for host "${command.host}".`, + ), + ); + continue; + } + + const matches = candidates.filter((schema) => + schema.actions.some( + (action) => action.actionName === link.actionName, + ), + ); + if (matches.length === 0) { + issues.push( + createLinkIssue( + command, + link.schema === undefined + ? `Action "${link.actionName}" is not registered for host "${command.host}".` + : `Action "${link.actionName}" is not registered in schema "${link.schema}".`, + ), + ); + continue; + } + if (matches.length > 1) { + issues.push( + createLinkIssue( + command, + `Action "${link.actionName}" is ambiguous across schemas: ${matches.map((schema) => schema.schemaName).join(", ")}.`, + ), + ); + continue; + } + link.resolvedSchema = matches[0].schemaName; + } + return issues; +} + +export function findMissingCommandActions( + commands: CommandInfo[], +): CommandActionGap[] { + return commands + .filter((command) => command.executable && command.action === undefined) + .map((command) => ({ host: command.host, path: command.path })); +} + +function createLinkIssue( + command: CommandInfo, + message: string, +): CommandActionLinkIssue { + const link = command.action!; + return { + host: command.host, + path: command.path, + actionName: link.actionName, + ...(link.schema === undefined ? {} : { schema: link.schema }), + message, + }; +} + /** Order schemas so the agent's primary schema leads, then the rest by name. */ function sortSchemas( configs: ActionConfig[], @@ -126,6 +276,7 @@ function collectActions( ReturnType >["provider"], config: ActionConfig, + strict: boolean, ): ActionInfo[] { const phrasings = collectPhrasings(config); @@ -133,7 +284,12 @@ function collectActions( try { const schemaFile = provider.getActionSchemaFileForConfig(config); actionSchemas = schemaFile.parsedActionSchema.actionSchemas; - } catch { + } catch (error) { + if (strict) { + throw new Error( + `Failed to load action schema "${config.schemaName}": ${getErrorMessage(error)}`, + ); + } return []; } @@ -150,6 +306,10 @@ function collectActions( return actions; } +function getErrorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + /** Load and parse the schema's grammar file into per-action phrasings. */ function collectPhrasings(config: ActionConfig): Map { const grammar = grammarContentOf(config); @@ -162,7 +322,7 @@ function collectPhrasings(config: ActionConfig): Map { return extractPhrasings(`${config.schemaName}.agr`, grammar.content); } if (grammar.format === "ag") { - return extractCompiledPhrasings(grammar.content); + return extractCompiledPhrasings(grammar.content, grammar.sourceMap); } return new Map(); } diff --git a/ts/tools/actionBrowser/src/commands.ts b/ts/tools/actionBrowser/src/commands.ts index d5a94e7886..cff6543e03 100644 --- a/ts/tools/actionBrowser/src/commands.ts +++ b/ts/tools/actionBrowser/src/commands.ts @@ -51,7 +51,13 @@ interface ParameterDef { * the same way the command-reference doc generator does. Best-effort: any * failure yields an empty list so the rest of the catalog still generates. */ -export async function collectCommands(): Promise { +export type CollectCommandsOptions = { + strict?: boolean; +}; + +export async function collectCommands( + options: CollectCommandsOptions = {}, +): Promise { let context: CommandHandlerContext; try { context = await initializeCommandHandlerContext("action-browser", { @@ -61,61 +67,78 @@ export async function collectCommands(): Promise { explainer: { enabled: false }, cache: { enabled: false }, }); - } catch { + } catch (error) { + if (options.strict) { + throw new Error( + `Failed to initialize command collection: ${getErrorMessage(error)}`, + ); + } return []; } - const out: CommandInfo[] = []; try { - const agents = context.agents; - for (const host of agents.getAppAgentNames()) { - if (!agents.isCommandEnabled(host)) { - continue; - } - const appAgent = agents.getAppAgent(host); - if (appAgent.getCommands === undefined) { - continue; - } - let commands: HandlerNode; - try { - commands = (await appAgent.getCommands( - agents.getSessionContext(host), - )) as unknown as HandlerNode; - } catch { - continue; - } - collectHostCommands(host, commands, out); - } + return await collectCommandsFromContext( + context, + options.strict ?? false, + ); } finally { await closeCommandHandlerContext(context); } +} +export async function collectCommandsFromContext( + context: CommandHandlerContext, + strict: boolean, +): Promise { + const out: CommandInfo[] = []; + const agents = context.agents; + for (const host of agents.getAppAgentNames()) { + if (!agents.isCommandEnabled(host)) { + continue; + } + const appAgent = agents.getAppAgent(host); + if (appAgent.getCommands === undefined) { + continue; + } + let commands: HandlerNode; + try { + commands = (await appAgent.getCommands( + agents.getSessionContext(host), + )) as unknown as HandlerNode; + } catch (error) { + if (strict) { + throw new Error( + `Failed to collect commands for host "${host}": ${getErrorMessage(error)}`, + ); + } + continue; + } + collectHostCommands(host, commands, out); + } return out.sort( (a, b) => a.host.localeCompare(b.host) || a.path.localeCompare(b.path), ); } +function getErrorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + // A host either exposes a table of sub-commands (walked recursively) or a // single top-level command invoked as bare `@` (path left empty). -function collectHostCommands( +export function collectHostCommands( host: string, node: HandlerNode, out: CommandInfo[], ): void { if (node.commands !== undefined && typeof node.commands === "object") { + const rootDefault = getDefaultDescriptor(node); + if (rootDefault !== undefined) { + out.push(createCommandInfo(host, "", node, true, rootDefault)); + } walk(host, node, [], out); } else { - const action = normalizeActionLink(node.action); - out.push({ - host, - path: "", - description: - typeof node.description === "string" ? node.description : "", - group: false, - args: extractArgs(node.parameters), - flags: extractFlags(node.parameters), - ...(action ? { action } : {}), - }); + out.push(createCommandInfo(host, "", node, false, { node })); } } @@ -137,30 +160,78 @@ function walk( const hasSub = child.commands !== undefined && Object.keys(child.commands).length > 0; - // A string `defaultSubCommand` references another entry that the loop - // renders on its own; only an inline descriptor contributes parameters. - const defaultSub = - typeof child.defaultSubCommand === "object" - ? child.defaultSubCommand - : undefined; - const params = child.parameters ?? defaultSub?.parameters; - const action = normalizeActionLink(child.action); - out.push({ - host, - path: currentPath.join(" "), - description: - typeof child.description === "string" ? child.description : "", - group: hasSub, - args: extractArgs(params), - flags: extractFlags(params), - ...(action ? { action } : {}), - }); + const endpoint = hasSub ? getDefaultDescriptor(child) : { node: child }; + out.push( + createCommandInfo( + host, + currentPath.join(" "), + child, + hasSub, + endpoint, + ), + ); if (hasSub) { walk(host, child, currentPath, out); } } } +type DefaultDescriptor = { + node: HandlerNode; + name?: string; +}; + +function getDefaultDescriptor( + table: HandlerNode, +): DefaultDescriptor | undefined { + const defaultSubCommand = table.defaultSubCommand; + if (typeof defaultSubCommand === "string") { + const target = table.commands?.[defaultSubCommand]; + if ( + target === undefined || + (target.commands !== undefined && + typeof target.commands === "object") + ) { + return undefined; + } + return { node: target, name: defaultSubCommand }; + } + if ( + defaultSubCommand === undefined || + (defaultSubCommand.commands !== undefined && + typeof defaultSubCommand.commands === "object") + ) { + return undefined; + } + return { node: defaultSubCommand }; +} + +function createCommandInfo( + host: string, + commandPath: string, + displayNode: HandlerNode, + group: boolean, + endpoint: DefaultDescriptor | undefined, +): CommandInfo { + const action = normalizeActionLink(endpoint?.node.action); + return { + host, + path: commandPath, + description: + typeof displayNode.description === "string" + ? displayNode.description + : "", + group, + executable: endpoint !== undefined, + ...(endpoint?.name === undefined + ? {} + : { defaultSubCommand: endpoint.name }), + args: extractArgs(endpoint?.node.parameters), + flags: extractFlags(endpoint?.node.parameters), + ...(action ? { action } : {}), + }; +} + // Normalize a handler's declared `action` (a bare actionName or a // {schema, actionName} pair) into the catalog's link shape. function normalizeActionLink( diff --git a/ts/tools/actionBrowser/src/index.ts b/ts/tools/actionBrowser/src/index.ts index 0a711b2b00..cb7be492a7 100644 --- a/ts/tools/actionBrowser/src/index.ts +++ b/ts/tools/actionBrowser/src/index.ts @@ -8,6 +8,9 @@ export type { AgentInfo, Catalog, CatalogCounts, + CommandActionGap, + CommandActionLink, + CommandActionLinkIssue, CommandArg, CommandFlag, CommandInfo, diff --git a/ts/tools/actionBrowser/src/phrasings.ts b/ts/tools/actionBrowser/src/phrasings.ts index af26afc880..c4a695ca21 100644 --- a/ts/tools/actionBrowser/src/phrasings.ts +++ b/ts/tools/actionBrowser/src/phrasings.ts @@ -208,7 +208,13 @@ function isUsefulPhrase(phrase: string): boolean { */ export function extractCompiledPhrasings( content: string, + sourceMap?: string, ): Map { + const source = sourceGrammarFromMap(sourceMap); + if (source !== undefined) { + return extractPhrasings(source.fileName, source.content); + } + const result = new Map(); let grammar: Grammar; try { @@ -252,6 +258,28 @@ export function extractCompiledPhrasings( return result; } +function sourceGrammarFromMap( + sourceMap: string | undefined, +): { fileName: string; content: string } | undefined { + if (sourceMap === undefined) { + return undefined; + } + try { + const parsed = asRecord(JSON.parse(sourceMap)); + const rules = asRecord(parsed?.rules); + const start = asRecord(rules?.Start); + const fileName = start?.fileId; + const files = asRecord(parsed?.files); + if (typeof fileName !== "string") { + return undefined; + } + const content = files?.[fileName]; + return typeof content === "string" ? { fileName, content } : undefined; + } catch { + return undefined; + } +} + function renderCompiledParts(parts: unknown, depth: number): string { if (!Array.isArray(parts)) { return ""; diff --git a/ts/tools/actionBrowser/src/render.ts b/ts/tools/actionBrowser/src/render.ts index 9f6d2b2ffe..d3fccf0a60 100644 --- a/ts/tools/actionBrowser/src/render.ts +++ b/ts/tools/actionBrowser/src/render.ts @@ -44,7 +44,10 @@ interface TreeNode { host?: string; // Full invocation path minus the leading `@` (e.g. `config agent enable`). full?: string; - // actionName of the equivalent agent action, when the handler declares one. + executable?: boolean; + defaultSubCommand?: string; + // Resolved identity of the equivalent agent action. + actionSchema?: string; actionName?: string; args?: { name: string; optional: boolean; description: string }[]; flags?: { @@ -175,7 +178,12 @@ function buildHostTree(host: string, commands: CommandInfo[]): TreeNode { const node = ensureNode(segments); node.host = host; node.full = commandDisplayPath(host, command.path); - if (command.action) { + node.executable = command.executable; + if (command.defaultSubCommand !== undefined) { + node.defaultSubCommand = command.defaultSubCommand; + } + if (command.action?.resolvedSchema !== undefined) { + node.actionSchema = command.action.resolvedSchema; node.actionName = command.action.actionName; } node.description = command.description; @@ -377,10 +385,10 @@ const APP = ` // Cross-reference actions with the commands declared equivalent to them, and // tally how many commands carry a natural-language action. - var actionIndex={}, commandsForAction={}, commandLeafCount=0, commandLinkedCount=0; - (function walk(n){ if(n.kind==='action'){ actionIndex[n.agent+'\\n'+n.name]=n; } if(n.children) n.children.forEach(walk); })(DATA.agents); + var actionIndex={}, commandsForAction={}, commandEndpointCount=0, commandLinkedCount=0; + (function walk(n){ if(n.kind==='action'){ actionIndex[n.schema+'\\n'+n.name]=n; } if(n.children) n.children.forEach(walk); })(DATA.agents); (function walk(n){ - if(n.kind==='command'){ commandLeafCount++; if(n.actionName){ commandLinkedCount++; var k=n.host+'\\n'+n.actionName; (commandsForAction[k]||(commandsForAction[k]=[])).push(n); } } + if(n.executable){ commandEndpointCount++; if(n.actionSchema&&n.actionName){ commandLinkedCount++; var k=n.actionSchema+'\\n'+n.actionName; (commandsForAction[k]||(commandsForAction[k]=[])).push(n); } } if(n.children) n.children.forEach(walk); })(DATA.commands); @@ -467,7 +475,7 @@ const APP = ` function buildCell(c, role, idx, n){ var node=c.node; var el=document.createElement('div'); - el.className='cell '+role+' k-'+node.kind+(node.actionName?' linked':''); + el.className='cell '+role+' k-'+node.kind+(node.actionSchema?' linked':''); el._layout=c; if(role==='container'){ var h=node._hue==null?210:node._hue; @@ -507,6 +515,7 @@ const APP = ` // into). Categories, command hosts, and command groups zoom in; leaves // open the side panel. if(node.kind==='agent'){ openActionsDialog(node); return; } + if(state.query && node.executable){ openPanel(node); return; } if(node.children && node.children.length){ var r=el._layout; state.path.push(node); @@ -593,7 +602,7 @@ const APP = ` if(state.query){ var r=document.createElement('span'); r.className='crumb crumb-static'; r.textContent='Results: “'+state.query+'”'; crumbEl.appendChild(r); } if(state.mode==='commands' && !state.query){ var cov=document.createElement('span'); cov.className='cov-chip'; - cov.textContent=commandLinkedCount+' / '+commandLeafCount+' commands have an action'; + cov.textContent=commandLinkedCount+' / '+commandEndpointCount+' command endpoints have an action'; crumbEl.appendChild(cov); } } @@ -611,12 +620,12 @@ const APP = ` var toks = state.query.split(/\\s+/).filter(Boolean); var out=[]; (function walk(n){ - if(n.children && n.children.length) n.children.forEach(walk); - else { + if(n.kind==='action' || n.executable){ if(n._hay==null) n._hay=buildHay(n); var ok=true; for(var i=0;i'; }); html+=''; } - } else if(node.kind==='command'){ + } else if(node.executable){ if(node.description) html+='

'+esc(node.description)+'

'; if(node.args && node.args.length){ html+='

Arguments

    '; @@ -689,16 +698,16 @@ const APP = ` var panelLinkTargets=[]; function panelLinkChip(node){ var i=panelLinkTargets.push(node)-1; - var label=node.kind==='command'?'@'+(node.full||node.name):node.name; + var label=node.kind==='action'?node.name:'@'+(node.full||node.name); return ''; } function crossLinkHtml(node){ - if(node.kind==='command' && node.actionName){ - var a=actionIndex[node.host+'\\n'+node.actionName]; + if(node.executable && node.actionSchema && node.actionName){ + var a=actionIndex[node.actionSchema+'\\n'+node.actionName]; return ''; } if(node.kind==='action'){ - var cs=commandsForAction[node.agent+'\\n'+node.name]; + var cs=commandsForAction[node.schema+'\\n'+node.name]; if(cs&&cs.length){ var chips=''; for(var i=0;iSame as command'+(cs.length>1?'s':'')+''+chips+''; @@ -708,10 +717,10 @@ const APP = ` } function openPanel(node){ - if(node.kind!=='action' && node.kind!=='command') return; + if(node.kind!=='action' && !node.executable) return; panelLinkTargets=[]; var kicker = node.kind==='action' ? esc(node.agent||'')+' · '+esc(node.schema||'') : esc(node.host||'system')+' command'; - var title = node.kind==='command' ? '@'+esc(node.full||node.name) : esc(node.name); + var title = node.kind==='action' ? esc(node.name) : '@'+esc(node.full||node.name); document.getElementById('panelBody').innerHTML='
    '+kicker+'

    '+title+'

    '+crossLinkHtml(node)+detailHtml(node); document.getElementById('panel').classList.add('open'); document.getElementById('backdrop').classList.add('show'); @@ -873,7 +882,7 @@ export function renderHtml(catalog: Catalog): string { "
    ", '
    ', "

    🧭 TypeAgent Action Browser

    ", - `${counts.agents} agents · ${counts.actions} actions · ${counts.commands} commands · generated ${generated}`, + `${counts.agents} agents · ${counts.actions} actions · ${counts.commandEndpoints} command endpoints · generated ${generated}`, "
    ", '
    ', '
    ', diff --git a/ts/tools/actionBrowser/src/types.ts b/ts/tools/actionBrowser/src/types.ts index 66106f5226..61a94e0880 100644 --- a/ts/tools/actionBrowser/src/types.ts +++ b/ts/tools/actionBrowser/src/types.ts @@ -65,6 +65,21 @@ export interface CommandActionLink { /** Schema that declares the action; omitted when unambiguous in the agent. */ schema?: string; actionName: string; + /** Fully-qualified schema resolved from the bundled action catalog. */ + resolvedSchema?: string; +} + +export interface CommandActionLinkIssue { + host: string; + path: string; + actionName: string; + schema?: string; + message: string; +} + +export interface CommandActionGap { + host: string; + path: string; } export interface CommandInfo { @@ -83,6 +98,10 @@ export interface CommandInfo { description: string; /** True when the entry is a command group (has sub-commands). */ group: boolean; + /** True when this exact path resolves to an executable descriptor. */ + executable: boolean; + /** Referenced child used when this path is invoked without a subcommand. */ + defaultSubCommand?: string; args: CommandArg[]; flags: CommandFlag[]; /** @@ -97,6 +116,10 @@ export interface CatalogCounts { agents: number; actions: number; commands: number; + commandEndpoints: number; + linkedCommandEndpoints: number; + missingCommandActions: number; + invalidCommandActionLinks: number; } export interface Catalog { @@ -105,5 +128,11 @@ export interface Catalog { agents: AgentInfo[]; /** Every `@command`, across the system host and each agent host. */ commands: CommandInfo[]; + /** Declared command links that do not resolve to one registered action. */ + commandActionLinkIssues: CommandActionLinkIssue[]; + /** Executable command endpoints with no declared equivalent action. */ + missingCommandActions: CommandActionGap[]; + /** Runtime-generated schemas intentionally omitted from static collection. */ + runtimeOnlySchemas: string[]; counts: CatalogCounts; } diff --git a/ts/tools/actionBrowser/test/collect.spec.ts b/ts/tools/actionBrowser/test/collect.spec.ts new file mode 100644 index 0000000000..a17bb07d84 --- /dev/null +++ b/ts/tools/actionBrowser/test/collect.spec.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { isRuntimeOnlySchema } from "../src/collect.js"; +import type { ActionConfig } from "agent-dispatcher/internal"; + +function makeConfig( + content: string, + paths: { + schemaFilePath?: string; + originalSchemaFilePath?: string; + } = {}, +): ActionConfig { + return { + schemaName: "demo", + schemaFile: { format: "ts", content }, + schemaFilePath: paths.schemaFilePath, + originalSchemaFilePath: paths.originalSchemaFilePath, + } as ActionConfig; +} + +describe("isRuntimeOnlySchema", () => { + it("recognizes an empty schema without authored paths", () => { + expect(isRuntimeOnlySchema(makeConfig(""))).toBe(true); + }); + + it("keeps a nonempty inline schema in strict collection", () => { + expect( + isRuntimeOnlySchema( + makeConfig('export type Demo = { actionName: "run" }'), + ), + ).toBe(false); + }); + + it("keeps an authored empty schema so strict parsing reports the defect", () => { + expect( + isRuntimeOnlySchema( + makeConfig("", { schemaFilePath: "demoSchema.ts" }), + ), + ).toBe(false); + }); +}); diff --git a/ts/tools/actionBrowser/test/commandActionLinks.spec.ts b/ts/tools/actionBrowser/test/commandActionLinks.spec.ts new file mode 100644 index 0000000000..d24af8a733 --- /dev/null +++ b/ts/tools/actionBrowser/test/commandActionLinks.spec.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + findMissingCommandActions, + resolveCommandActionLinks, +} from "../src/collect.js"; +import type { + ActionInfo, + AgentInfo, + CommandActionLink, + CommandInfo, + SchemaInfo, +} from "../src/types.js"; + +function makeAction(actionName: string): ActionInfo { + return { actionName, description: "", parameters: [], phrasings: [] }; +} + +function makeSchema(schemaName: string, actionNames: string[]): SchemaInfo { + return { + schemaName, + description: "", + defaultEnabled: true, + transient: false, + actions: actionNames.map(makeAction), + }; +} + +function makeAgent(schemas: SchemaInfo[]): AgentInfo { + return { + name: "demo", + category: "Other", + emoji: "", + description: "", + schemas, + }; +} + +function makeCommand(action: CommandActionLink): CommandInfo { + return { + host: "demo", + path: "run", + description: "", + group: false, + executable: true, + args: [], + flags: [], + action, + }; +} + +describe("resolveCommandActionLinks", () => { + it("resolves a unique bare action name", () => { + const command = makeCommand({ actionName: "runTask" }); + const issues = resolveCommandActionLinks( + [makeAgent([makeSchema("demo", ["runTask"])])], + [command], + ); + + expect(issues).toEqual([]); + expect(command.action?.resolvedSchema).toBe("demo"); + }); + + it("resolves an action in an explicitly qualified schema", () => { + const command = makeCommand({ + schema: "demo.admin", + actionName: "runTask", + }); + const issues = resolveCommandActionLinks( + [ + makeAgent([ + makeSchema("demo", ["runTask"]), + makeSchema("demo.admin", ["runTask"]), + ]), + ], + [command], + ); + + expect(issues).toEqual([]); + expect(command.action?.resolvedSchema).toBe("demo.admin"); + }); + + it("rejects an ambiguous bare action name", () => { + const command = makeCommand({ actionName: "runTask" }); + const issues = resolveCommandActionLinks( + [ + makeAgent([ + makeSchema("demo", ["runTask"]), + makeSchema("demo.admin", ["runTask"]), + ]), + ], + [command], + ); + + expect(command.action?.resolvedSchema).toBeUndefined(); + expect(issues[0].message).toMatch(/ambiguous/); + expect(issues[0].message).toMatch(/demo, demo\.admin/); + }); + + it("rejects an unknown qualified schema", () => { + const command = makeCommand({ + schema: "demo.missing", + actionName: "runTask", + }); + const issues = resolveCommandActionLinks( + [makeAgent([makeSchema("demo", ["runTask"])])], + [command], + ); + + expect(command.action?.resolvedSchema).toBeUndefined(); + expect(issues[0].message).toMatch(/not registered for host/); + }); + + it("rejects an action absent from the registered schema union", () => { + const command = makeCommand({ + schema: "demo", + actionName: "disabledTask", + }); + const issues = resolveCommandActionLinks( + [makeAgent([makeSchema("demo", ["runTask"])])], + [command], + ); + + expect(command.action?.resolvedSchema).toBeUndefined(); + expect(issues[0].message).toMatch(/not registered in schema/); + }); +}); + +describe("findMissingCommandActions", () => { + it("reports only executable endpoints without a declaration", () => { + const missing = makeCommand({ actionName: "unused" }); + delete missing.action; + const namespace = { ...missing, path: "admin", executable: false }; + const invalid = makeCommand({ actionName: "missingAction" }); + + expect( + findMissingCommandActions([missing, namespace, invalid]), + ).toEqual([{ host: "demo", path: "run" }]); + }); +}); diff --git a/ts/tools/actionBrowser/test/commands.spec.ts b/ts/tools/actionBrowser/test/commands.spec.ts new file mode 100644 index 0000000000..e1ec1b098f --- /dev/null +++ b/ts/tools/actionBrowser/test/commands.spec.ts @@ -0,0 +1,160 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + collectCommandsFromContext, + collectHostCommands, +} from "../src/commands.js"; +import type { CommandInfo } from "../src/types.js"; + +function collect(node: object): CommandInfo[] { + const commands: CommandInfo[] = []; + collectHostCommands("demo", node, commands); + return commands; +} + +describe("collectHostCommands", () => { + it("emits a bare executable endpoint for a root string default", () => { + const commands = collect({ + description: "Demo commands", + defaultSubCommand: "status", + commands: { + status: { + description: "Show status", + action: "showStatus", + }, + }, + }); + + expect(commands.map((command) => command.path)).toEqual(["", "status"]); + expect(commands[0]).toMatchObject({ + group: true, + executable: true, + defaultSubCommand: "status", + action: { actionName: "showStatus" }, + }); + }); + + it("uses an inline default descriptor at the group path", () => { + const commands = collect({ + description: "Demo commands", + commands: { + clear: { + description: "Clear output", + defaultSubCommand: { + description: "Clear output", + action: "clearOutput", + }, + commands: { + deep: { + description: "Clear all state", + action: "clearAllState", + }, + }, + }, + }, + }); + + expect(commands[0]).toMatchObject({ + path: "clear", + group: true, + executable: true, + action: { actionName: "clearOutput" }, + }); + expect(commands[1]).toMatchObject({ + path: "clear deep", + group: false, + executable: true, + }); + }); + + it("keeps a group without a default as a namespace", () => { + const commands = collect({ + description: "Demo commands", + commands: { + admin: { + description: "Administrative commands", + commands: { + show: { description: "Show configuration" }, + }, + }, + }, + }); + + expect(commands[0]).toMatchObject({ + path: "admin", + group: true, + executable: false, + }); + expect(commands[1].executable).toBe(true); + }); + + it("does not treat a string default that targets a table as executable", () => { + const commands = collect({ + description: "Demo commands", + defaultSubCommand: "admin", + commands: { + admin: { + description: "Administrative commands", + commands: { + show: { description: "Show configuration" }, + }, + }, + }, + }); + + expect(commands.some((command) => command.path === "")).toBe(false); + expect(commands[0]).toMatchObject({ + path: "admin", + group: true, + executable: false, + }); + }); + + it("emits a bare descriptor as an executable endpoint", () => { + const commands = collect({ + description: "Run demo", + action: "runDemo", + }); + + expect(commands).toEqual([ + expect.objectContaining({ + path: "", + group: false, + executable: true, + action: { actionName: "runDemo" }, + }), + ]); + }); +}); + +describe("collectCommandsFromContext", () => { + function makeFailingContext() { + return { + agents: { + getAppAgentNames: () => ["demo"], + isCommandEnabled: () => true, + getAppAgent: () => ({ + getCommands: async () => { + throw new Error("command table failed"); + }, + }), + getSessionContext: () => ({}), + }, + } as any; + } + + it("throws with the host name in strict mode", async () => { + await expect( + collectCommandsFromContext(makeFailingContext(), true), + ).rejects.toThrow( + 'Failed to collect commands for host "demo": command table failed', + ); + }); + + it("keeps best-effort generation behavior outside strict mode", async () => { + await expect( + collectCommandsFromContext(makeFailingContext(), false), + ).resolves.toEqual([]); + }); +}); diff --git a/ts/tools/actionBrowser/test/phrasings.spec.ts b/ts/tools/actionBrowser/test/phrasings.spec.ts new file mode 100644 index 0000000000..45be4af8a7 --- /dev/null +++ b/ts/tools/actionBrowser/test/phrasings.spec.ts @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { extractCompiledPhrasings } from "../src/phrasings.js"; + +describe("extractCompiledPhrasings", () => { + it("prefers authored grammar from the source map over optimized fragments", () => { + const fileName = "demo.agr"; + const sourceMap = JSON.stringify({ + files: { + [fileName]: + ' = toggle mute -> { actionName: "toggleMute" };', + }, + rules: { Start: { fileId: fileName, start: 0, end: 64 } }, + }); + + const result = extractCompiledPhrasings("[]", sourceMap); + + expect(result.get("toggleMute")).toEqual(["toggle mute"]); + }); + + it("falls back to optimized grammar when no source map is available", () => { + expect(extractCompiledPhrasings("[]")).toEqual(new Map()); + }); +}); diff --git a/ts/tools/actionBrowser/test/render.spec.ts b/ts/tools/actionBrowser/test/render.spec.ts new file mode 100644 index 0000000000..0329aa7de7 --- /dev/null +++ b/ts/tools/actionBrowser/test/render.spec.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { renderHtml } from "../src/render.js"; +import type { Catalog } from "../src/types.js"; + +describe("renderHtml", () => { + it("emits syntactically valid embedded JavaScript for qualified links", () => { + const catalog: Catalog = { + generatedAt: "2026-07-31T00:00:00.000Z", + agents: [ + { + name: "demo", + category: "Other", + emoji: "", + description: "", + schemas: [ + { + schemaName: "demo.admin", + description: "", + defaultEnabled: true, + transient: false, + actions: [ + { + actionName: "runTask", + description: "", + parameters: [], + phrasings: [], + }, + ], + }, + ], + }, + ], + commands: [ + { + host: "demo", + path: "run", + description: "", + group: false, + executable: true, + args: [], + flags: [], + action: { + schema: "demo.admin", + actionName: "runTask", + resolvedSchema: "demo.admin", + }, + }, + ], + commandActionLinkIssues: [], + missingCommandActions: [], + runtimeOnlySchemas: [], + counts: { + agents: 1, + actions: 1, + commands: 1, + commandEndpoints: 1, + linkedCommandEndpoints: 1, + missingCommandActions: 0, + invalidCommandActionLinks: 0, + }, + }; + + const html = renderHtml(catalog); + const scripts = [ + ...html.matchAll(/]*)?>([\s\S]*?)<\/script>/g), + ]; + const executableScript = scripts.at(-1)?.[1]; + + expect(executableScript).toBeDefined(); + expect(() => new Function(executableScript!)).not.toThrow(); + expect(executableScript).toContain("n.schema+'\\n'+n.name"); + }); +}); diff --git a/ts/tools/actionBrowser/test/tsconfig.json b/ts/tools/actionBrowser/test/tsconfig.json new file mode 100644 index 0000000000..d3fbfa5c19 --- /dev/null +++ b/ts/tools/actionBrowser/test/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "rootDir": ".", + "outDir": "../dist/test", + "types": ["node", "jest"] + }, + "include": ["./**/*"], + "references": [{ "path": "../src" }] +} diff --git a/ts/tools/actionBrowser/tsconfig.json b/ts/tools/actionBrowser/tsconfig.json index b6e1577e45..cdf483e0d6 100644 --- a/ts/tools/actionBrowser/tsconfig.json +++ b/ts/tools/actionBrowser/tsconfig.json @@ -4,7 +4,7 @@ "composite": true }, "include": [], - "references": [{ "path": "./src" }], + "references": [{ "path": "./src" }, { "path": "./test" }], "ts-node": { "esm": true } From f93c93534b5426243cb449cef51985e966044c43 Mon Sep 17 00:00:00 2001 From: Robert Gruen Date: Fri, 31 Jul 2026 13:38:48 -0700 Subject: [PATCH 02/22] phase 2 --- ts/docs/plans/agent-command-actions/PLAN.md | 5 +- ts/docs/plans/agent-command-actions/STATUS.md | 12 +- ts/packages/agents/email/package.json | 4 + .../agents/email/src/emailActionHandler.ts | 61 ++++--- .../agents/email/src/emailActionsSchema.ts | 10 +- ts/packages/agents/email/src/emailSchema.agr | 9 +- .../agents/email/test/emailIndex.spec.ts | 113 +++++++++++++ ts/packages/agents/email/test/tsconfig.json | 11 ++ ts/packages/agents/email/tsconfig.json | 2 +- ts/packages/agents/greeting/package.json | 7 +- .../greeting/src/greetingActionSchema.ts | 2 + .../greeting/src/greetingCommandHandler.ts | 67 ++++---- .../agents/greeting/src/greetingManifest.json | 8 +- .../greeting/test/greetingAction.spec.ts | 79 ++++++++++ .../agents/greeting/test/tsconfig.json | 11 ++ ts/packages/agents/greeting/tsconfig.json | 2 +- ts/packages/agents/powershell/package.json | 4 + .../agents/powershell/src/actionHandler.mts | 92 +++++------ .../agents/powershell/src/flowDetails.mts | 44 ++++++ .../powershell/src/powershellSchema.agr | 6 +- .../powershell/src/schema/scriptActions.mts | 12 ++ .../powershell/src/store/powerShellStore.mts | 20 +++ .../powershell/test/powerShellShow.spec.ts | 149 ++++++++++++++++++ .../agents/powershell/test/tsconfig.json | 11 ++ ts/packages/agents/powershell/tsconfig.json | 2 +- ts/pnpm-lock.yaml | 12 ++ 26 files changed, 633 insertions(+), 122 deletions(-) create mode 100644 ts/packages/agents/email/test/emailIndex.spec.ts create mode 100644 ts/packages/agents/email/test/tsconfig.json create mode 100644 ts/packages/agents/greeting/test/greetingAction.spec.ts create mode 100644 ts/packages/agents/greeting/test/tsconfig.json create mode 100644 ts/packages/agents/powershell/src/flowDetails.mts create mode 100644 ts/packages/agents/powershell/test/powerShellShow.spec.ts create mode 100644 ts/packages/agents/powershell/test/tsconfig.json diff --git a/ts/docs/plans/agent-command-actions/PLAN.md b/ts/docs/plans/agent-command-actions/PLAN.md index 9cb2036c91..9408315bf0 100644 --- a/ts/docs/plans/agent-command-actions/PLAN.md +++ b/ts/docs/plans/agent-command-actions/PLAN.md @@ -126,8 +126,9 @@ paths use a shared typed helper. effects, and readiness before linking PowerShell, OS notifications, self-help, exact localPlayer operations, and exact browser operations. 3. **Complete agent-host actions.** Add the known localPlayer and browser gaps, - auth/OAuth/indexing actions, browser configuration, PowerShell `show`, and - dispatcher diagnostics. No agent-host command remains excluded. + auth/OAuth actions, browser configuration, and dispatcher diagnostics. + PowerShell `show` and email indexing were completed in the second + implementation slice. No agent-host command remains excluded. 4. **Complete existing system families.** Finish `system.config`, `system.conversation`, `system.describe`, `system.grammar`, `system.history`, `system.notify`, and `system.settings`. diff --git a/ts/docs/plans/agent-command-actions/STATUS.md b/ts/docs/plans/agent-command-actions/STATUS.md index b1317f5a0c..0225a1f512 100644 --- a/ts/docs/plans/agent-command-actions/STATUS.md +++ b/ts/docs/plans/agent-command-actions/STATUS.md @@ -18,8 +18,8 @@ collection, not manual estimates. | Metric | Count | | ------------------------------------ | ------------------: | | Executable command endpoints | 387 | -| Valid linked endpoints | 43 | -| Missing action declarations | 344 | +| Valid linked endpoints | 46 | +| Missing action declarations | 341 | | Invalid / dangling / ambiguous links | 0 | | Runtime-only static omissions | 1 (`mcpfilesystem`) | @@ -47,13 +47,15 @@ collection, not manual estimates. | localPlayer | All 16 endpoints, including bare status default, general play, and mute/shuffle toggles. | | osNotifications | `sync`, `test`. | | selfhelp | Bare default and `ask`. | -| powershell | `list`, `run`, `delete`, `import`; `show` remains a new-action gap. | +| powershell | All five management endpoints: `list`, `run`, `delete`, `show`, and `import`. | | browser | `open`, `close`, `learn`, `actions match`, `actions infer`, and inherited `actions` default. | +| email | `index`; auth management remains. | +| greeting | Bare command, including deterministic `--mock` action parity. | The current migration check is: ```text -Command action coverage: 43 / 387 endpoints (344 missing, 0 invalid) +Command action coverage: 46 / 387 endpoints (341 missing, 0 invalid) Runtime-only schemas omitted: mcpfilesystem ``` @@ -65,7 +67,7 @@ pnpm --filter @typeagent/action-browser test:local node tools/actionBrowser/dist/cli.js --check --allow-missing ``` -Strict completion command (expected to fail until all 344 remaining gaps +Strict completion command (expected to fail until all 341 remaining gaps close): ```powershell diff --git a/ts/packages/agents/email/package.json b/ts/packages/agents/email/package.json index 8659da77ac..d317c7c34d 100644 --- a/ts/packages/agents/email/package.json +++ b/ts/packages/agents/email/package.json @@ -21,6 +21,7 @@ "files": [ "dist", "src", + "!dist/test", "!dist/tsconfig.tsbuildinfo" ], "scripts": { @@ -29,6 +30,8 @@ "clean": "rimraf --glob dist *.tsbuildinfo *.done.build.log", "prettier": "prettier --check . --ignore-path ../../../.prettierignore", "prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore", + "test": "npm run test:local", + "test:local": "node --test ./dist/test/*.spec.js", "tsc": "tsc -b" }, "dependencies": { @@ -42,6 +45,7 @@ "debug": "^4.4.0" }, "devDependencies": { + "@typeagent/action-grammar": "workspace:*", "@typeagent/action-schema-compiler": "workspace:*", "@types/debug": "^4.1.12", "concurrently": "^9.1.2", diff --git a/ts/packages/agents/email/src/emailActionHandler.ts b/ts/packages/agents/email/src/emailActionHandler.ts index bbbde1ceb6..7184b8e893 100644 --- a/ts/packages/agents/email/src/emailActionHandler.ts +++ b/ts/packages/agents/email/src/emailActionHandler.ts @@ -293,30 +293,9 @@ class GoogleAuthCommandHandler implements CommandHandler { class EmailIndexCommandHandler implements CommandHandlerNoParams { public readonly description = "Build keyword index from inbox emails for fast search"; + public readonly action = "indexInbox"; public async run(context: ActionContext) { - const provider = context.sessionContext.agentContext.emailProvider; - if (provider === undefined) { - throw new Error("Email provider not initialized"); - } - if (!provider.isAuthenticated()) { - displayWarn("Please log in first with '@email login'", context); - return; - } - - const agentCtx = context.sessionContext.agentContext; - if (agentCtx.indexingInProgress) { - displayWarn( - "Index build already in progress. Progress will appear as notifications.", - context, - ); - return; - } - - displayStatus( - "Starting email keyword index build in background...", - context, - ); - startBackgroundInitialIndex(agentCtx); + runEmailIndex(context); } } @@ -542,6 +521,11 @@ async function executeEmailAction( action: TypeAgentAction, context: ActionContext, ) { + if (action.actionName === "indexInbox") { + runEmailIndex(context); + return; + } + const { emailProvider } = context.sessionContext.agentContext; if (emailProvider === undefined) { throw new Error("Email provider not initialized"); @@ -568,6 +552,37 @@ async function executeEmailAction( } } +export function runEmailIndex( + context: ActionContext, + startIndex: ( + context: EmailActionContext, + ) => void = startBackgroundInitialIndex, +): void { + const provider = context.sessionContext.agentContext.emailProvider; + if (provider === undefined) { + throw new Error("Email provider not initialized"); + } + if (!provider.isAuthenticated()) { + displayWarn("Please log in first with '@email login'", context); + return; + } + + const agentContext = context.sessionContext.agentContext; + if (agentContext.indexingInProgress) { + displayWarn( + "Index build already in progress. Progress will appear as notifications.", + context, + ); + return; + } + + displayStatus( + "Starting email keyword index build in background...", + context, + ); + startIndex(agentContext); +} + async function handleEmailAction( action: EmailAction, context: ActionContext, diff --git a/ts/packages/agents/email/src/emailActionsSchema.ts b/ts/packages/agents/email/src/emailActionsSchema.ts index 79b98a4e30..3618898354 100644 --- a/ts/packages/agents/email/src/emailActionsSchema.ts +++ b/ts/packages/agents/email/src/emailActionsSchema.ts @@ -5,7 +5,15 @@ export type EmailAction = | SendEmailAction | ReplyEmailAction | ForwardEmailAction - | FindEmailAction; + | FindEmailAction + | IndexInboxAction; + +// user: index my inbox +// agent: { "actionName": "indexInbox" } +// Build the local keyword index from inbox email messages. +export type IndexInboxAction = { + actionName: "indexInbox"; +}; // Type for generating the body content of an email based on the user input export interface GenerateContent { diff --git a/ts/packages/agents/email/src/emailSchema.agr b/ts/packages/agents/email/src/emailSchema.agr index 51490dbcff..149c878122 100644 --- a/ts/packages/agents/email/src/emailSchema.agr +++ b/ts/packages/agents/email/src/emailSchema.agr @@ -2,11 +2,11 @@ // Licensed under the MIT License. // Email Management Grammar -// Covers: sendEmail, replyEmail, forwardEmail, findEmail actions +// Covers: sendEmail, replyEmail, forwardEmail, findEmail, indexInbox actions import { EmailAction } from "./emailActionsSchema.ts"; - : EmailAction = | | | ; + : EmailAction = | | | | ; // ===== Main Action Rules ===== @@ -24,6 +24,11 @@ import { EmailAction } from "./emailActionsSchema.ts"; = $(messageRef:string) -> { actionName: "findEmail", parameters: { messageRef: messageRef } } | ('with' | 'having')? ('message' | 'msg')? ('reference' | 'ref' | 'id') $(messageRef:string) -> { actionName: "findEmail", parameters: { messageRef: messageRef } }; + = (index | reindex) (my | the)? (email)? inbox + -> { actionName: "indexInbox" } + | (build | rebuild) (my | the)? email index + -> { actionName: "indexInbox" }; + // ===== Shared Sub-Rules ===== = ? (('send' ('an' | 'a')? 'email') | 'email') ('to' | 'for')?; diff --git a/ts/packages/agents/email/test/emailIndex.spec.ts b/ts/packages/agents/email/test/emailIndex.spec.ts new file mode 100644 index 0000000000..57fc628a66 --- /dev/null +++ b/ts/packages/agents/email/test/emailIndex.spec.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import assert from "node:assert/strict"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { + compileGrammarToNFA, + loadGrammarRulesNoThrow, + matchNFA, +} from "@typeagent/action-grammar"; +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(here, "..", ".."); +const { instantiate, runEmailIndex } = await import( + pathToFileURL(path.join(packageRoot, "dist", "emailActionHandler.js")).href +); +const grammarPath = path.join(packageRoot, "src", "emailSchema.agr"); + +function makeMatcher() { + const errors: string[] = []; + const grammar = loadGrammarRulesNoThrow( + "emailSchema.agr", + fs.readFileSync(grammarPath, "utf8"), + errors, + ); + if (grammar === undefined || errors.length > 0) { + throw new Error(`Failed to parse email grammar: ${errors.join("; ")}`); + } + const nfa = compileGrammarToNFA(grammar, "email"); + return (input: string) => { + const result = matchNFA(nfa, input.toLowerCase().split(/\s+/), false); + return result.matched ? result.actionValue : undefined; + }; +} + +function makeContext(authenticated: boolean, indexingInProgress = false) { + const displays: unknown[] = []; + const agentContext = { + emailProvider: { + isAuthenticated: () => authenticated, + }, + indexingInProgress, + }; + return { + agentContext, + displays, + context: { + sessionContext: { agentContext }, + actionIO: { + setDisplay: (content: unknown) => displays.push(content), + appendDisplay: (content: unknown) => displays.push(content), + }, + } as any, + }; +} + +describe("indexInbox", () => { + it("matches narrow inbox-indexing requests", () => { + const match = makeMatcher(); + + assert.deepEqual(match("index my inbox"), { + actionName: "indexInbox", + }); + assert.deepEqual(match("rebuild my email index"), { + actionName: "indexInbox", + }); + }); + + it("links the index command to indexInbox", async () => { + const descriptors = (await instantiate().getCommands!({} as any)) as + | CommandDescriptor + | CommandDescriptorTable; + assert.ok("commands" in descriptors); + assert.equal( + (descriptors.commands.index as CommandDescriptor).action, + "indexInbox", + ); + }); + + it("starts indexing when authenticated", () => { + const { context, agentContext } = makeContext(true); + const started: unknown[] = []; + + runEmailIndex(context, (value: unknown) => started.push(value)); + + assert.deepEqual(started, [agentContext]); + }); + + it("does not start indexing while signed out", () => { + const { context } = makeContext(false); + const started: unknown[] = []; + + runEmailIndex(context, (value: unknown) => started.push(value)); + + assert.deepEqual(started, []); + }); + + it("does not start a duplicate index build", () => { + const { context } = makeContext(true, true); + const started: unknown[] = []; + + runEmailIndex(context, (value: unknown) => started.push(value)); + + assert.deepEqual(started, []); + }); +}); diff --git a/ts/packages/agents/email/test/tsconfig.json b/ts/packages/agents/email/test/tsconfig.json new file mode 100644 index 0000000000..072111edfe --- /dev/null +++ b/ts/packages/agents/email/test/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "rootDir": ".", + "outDir": "../dist/test", + "types": ["node"] + }, + "include": ["./**/*"], + "references": [{ "path": "../src" }] +} diff --git a/ts/packages/agents/email/tsconfig.json b/ts/packages/agents/email/tsconfig.json index acb9cb4a91..94dfc60bb1 100644 --- a/ts/packages/agents/email/tsconfig.json +++ b/ts/packages/agents/email/tsconfig.json @@ -4,7 +4,7 @@ "composite": true }, "include": [], - "references": [{ "path": "./src" }], + "references": [{ "path": "./src" }, { "path": "./test" }], "ts-node": { "esm": true } diff --git a/ts/packages/agents/greeting/package.json b/ts/packages/agents/greeting/package.json index b3a420af0f..ec6e6f5097 100644 --- a/ts/packages/agents/greeting/package.json +++ b/ts/packages/agents/greeting/package.json @@ -20,11 +20,14 @@ "./agent/handlers": "./dist/greetingCommandHandler.js" }, "scripts": { - "build": "npm run tsc", + "asc": "asc -i ./src/greetingActionSchema.ts -o ./dist/greetingActionSchema.pas.json -t GreetingAction", + "build": "concurrently npm:tsc npm:asc", "postbuild": "copyfiles -u 1 \"src/**/config.json\" dist", "clean": "rimraf --glob dist *.tsbuildinfo *.done.build.log", "prettier": "prettier --check . --ignore-path ../../../.prettierignore", "prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore", + "test": "npm run test:local", + "test:local": "node --test ./dist/test/*.spec.js", "tsc": "tsc -b" }, "dependencies": { @@ -40,7 +43,9 @@ "typechat": "^0.1.1" }, "devDependencies": { + "@typeagent/action-schema-compiler": "workspace:*", "@types/debug": "^4.1.12", + "concurrently": "^9.1.2", "copyfiles": "^2.4.1", "prettier": "^3.5.3", "rimraf": "^6.0.1", diff --git a/ts/packages/agents/greeting/src/greetingActionSchema.ts b/ts/packages/agents/greeting/src/greetingActionSchema.ts index c37b8b51d5..ce4b28b47f 100644 --- a/ts/packages/agents/greeting/src/greetingActionSchema.ts +++ b/ts/packages/agents/greeting/src/greetingActionSchema.ts @@ -13,6 +13,8 @@ export type GreetingAction = PersonalizedGreetingAction; export interface PersonalizedGreetingAction { actionName: "personalizedGreetingAction"; parameters: { + // Set true only when the caller requests the deterministic mock greeting. + mock?: boolean; // the original request/greeting from the user originalRequest: string; // a set possible generic greeting responses to the user diff --git a/ts/packages/agents/greeting/src/greetingCommandHandler.ts b/ts/packages/agents/greeting/src/greetingCommandHandler.ts index 3f4a530391..439d463830 100644 --- a/ts/packages/agents/greeting/src/greetingCommandHandler.ts +++ b/ts/packages/agents/greeting/src/greetingCommandHandler.ts @@ -7,6 +7,7 @@ import { ActionResult, ActionResultSuccess, ParsedCommandParams, + TypeAgentAction, } from "@typeagent/agent-sdk"; import { createTypeChat } from "@typeagent/agent-runtime"; import { createActionResult } from "@typeagent/agent-sdk/helpers/action"; @@ -36,6 +37,7 @@ const debug = registerDebug("typeagent:greeting"); export function instantiate(): AppAgent { return { initializeAgentContext: initializeGreetingAgentContext, + executeAction: executeGreetingAction, ...getCommandInterface(handlers), }; } @@ -123,6 +125,7 @@ export interface GenericGreeting { export class GreetingCommandHandler implements CommandHandler { public readonly description = "Have the agent generate a personalized greeting."; + public readonly action = "personalizedGreetingAction"; public readonly parameters = { flags: { mock: { @@ -143,11 +146,20 @@ export class GreetingCommandHandler implements CommandHandler { params: ParsedCommandParams, ): Promise { if (params.flags.mock) { - context.actionIO.appendDisplay("Hello. How can I help you today?"); - // Mock path makes no LLM call — report all-zero usage so the UI - // can distinguish "no tokens used" from "not reported". + const result = (await executeGreetingAction( + { + schemaName: "greeting", + actionName: "personalizedGreetingAction", + parameters: { + mock: true, + originalRequest: "@greeting --mock", + possibleGreetings: [], + }, + }, + context, + )) as ActionResultSuccess; return { - entities: [], + ...result, tokenUsage: { prompt_tokens: 0, completion_tokens: 0, @@ -182,31 +194,14 @@ export class GreetingCommandHandler implements CommandHandler { if (response.success) { context.actionIO.appendDiagnosticData(response.data); - - const action: GreetingAction = response.data as GreetingAction; - let result: ActionResultSuccess | undefined = undefined; - switch (action.actionName) { - case "personalizedGreetingAction": - result = (await handlePersonalizedGreetingAction( - action as PersonalizedGreetingAction, - context, - )) as ActionResultSuccess; - - context.actionIO.appendDisplay( - result.displayContent, - "block", - ); - break; - - // case "contextualGreetingAction": - - // result = await handleContextualGreetingAction( - // action as ContextualGreetingAction, - // ) as ActionResultSuccess; - - // displayResult(result.literalText!, context); - // break; - } + const result = (await executeGreetingAction( + { + ...response.data, + schemaName: "greeting", + }, + context, + )) as ActionResultSuccess; + return { ...result, tokenUsage }; } else { displayError("Unable to generate greeting.", context); } @@ -331,6 +326,10 @@ async function handlePersonalizedGreetingAction( greetingAction: PersonalizedGreetingAction, context: ActionContext, ): Promise { + if (greetingAction.parameters.mock === true) { + return createActionResult("Hello. How can I help you today?"); + } + let result = createActionResult("Hi!", true, undefined); if (greetingAction.parameters !== undefined) { const count = greetingAction.parameters.possibleGreetings.length; @@ -366,6 +365,16 @@ async function handlePersonalizedGreetingAction( return result; } +async function executeGreetingAction( + action: TypeAgentAction, + context: ActionContext, +): Promise { + switch (action.actionName) { + case "personalizedGreetingAction": + return handlePersonalizedGreetingAction(action, context); + } +} + // function handleContextualGreetingAction( // greetingAction: ContextualGreetingAction, // ): ActionResult { diff --git a/ts/packages/agents/greeting/src/greetingManifest.json b/ts/packages/agents/greeting/src/greetingManifest.json index 7956d7003e..867ceb8bc9 100644 --- a/ts/packages/agents/greeting/src/greetingManifest.json +++ b/ts/packages/agents/greeting/src/greetingManifest.json @@ -1,4 +1,10 @@ { "emojiChar": "🖐️", - "description": "Agent to generate greeting messages" + "description": "Agent to generate greeting messages", + "schema": { + "description": "Greeting agent that responds to greetings with a personalized greeting.", + "originalSchemaFile": "./greetingActionSchema.ts", + "schemaFile": "../dist/greetingActionSchema.pas.json", + "schemaType": "GreetingAction" + } } diff --git a/ts/packages/agents/greeting/test/greetingAction.spec.ts b/ts/packages/agents/greeting/test/greetingAction.spec.ts new file mode 100644 index 0000000000..0e9b9d9257 --- /dev/null +++ b/ts/packages/agents/greeting/test/greetingAction.spec.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import assert from "node:assert/strict"; +import * as path from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(here, "..", ".."); +const { instantiate } = await import( + pathToFileURL(path.join(packageRoot, "dist", "greetingCommandHandler.js")) + .href +); + +function mockAction() { + return { + schemaName: "greeting", + actionName: "personalizedGreetingAction", + parameters: { + mock: true, + originalRequest: "hello", + possibleGreetings: [], + }, + } as any; +} + +describe("greeting action parity", () => { + it("exposes an executable personalizedGreetingAction", async () => { + const agent = instantiate(); + + assert.equal(typeof agent.executeAction, "function"); + const result = await agent.executeAction!(mockAction(), {} as any); + assert.equal( + (result as any).displayContent, + "Hello. How can I help you today?", + ); + }); + + it("links the bare command default to personalizedGreetingAction", async () => { + const descriptors = (await instantiate().getCommands!({} as any)) as + | CommandDescriptor + | CommandDescriptorTable; + assert.ok("commands" in descriptors); + assert.notEqual(typeof descriptors.defaultSubCommand, "string"); + assert.equal( + (descriptors.defaultSubCommand as CommandDescriptor).action, + "personalizedGreetingAction", + ); + }); + + it("returns the same mock display through the command", async () => { + const descriptors = (await instantiate().getCommands!({} as any)) as + | CommandDescriptor + | CommandDescriptorTable; + assert.ok("commands" in descriptors); + assert.notEqual(typeof descriptors.defaultSubCommand, "string"); + const command = descriptors.defaultSubCommand as any; + + const result = await command.run({} as any, { + args: {}, + flags: { mock: true }, + }); + + assert.equal( + result.displayContent, + "Hello. How can I help you today?", + ); + assert.deepEqual(result.tokenUsage, { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + }); + }); +}); diff --git a/ts/packages/agents/greeting/test/tsconfig.json b/ts/packages/agents/greeting/test/tsconfig.json new file mode 100644 index 0000000000..072111edfe --- /dev/null +++ b/ts/packages/agents/greeting/test/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "rootDir": ".", + "outDir": "../dist/test", + "types": ["node"] + }, + "include": ["./**/*"], + "references": [{ "path": "../src" }] +} diff --git a/ts/packages/agents/greeting/tsconfig.json b/ts/packages/agents/greeting/tsconfig.json index acb9cb4a91..94dfc60bb1 100644 --- a/ts/packages/agents/greeting/tsconfig.json +++ b/ts/packages/agents/greeting/tsconfig.json @@ -4,7 +4,7 @@ "composite": true }, "include": [], - "references": [{ "path": "./src" }], + "references": [{ "path": "./src" }, { "path": "./test" }], "ts-node": { "esm": true } diff --git a/ts/packages/agents/powershell/package.json b/ts/packages/agents/powershell/package.json index a1389e8640..6c031dbd89 100644 --- a/ts/packages/agents/powershell/package.json +++ b/ts/packages/agents/powershell/package.json @@ -22,6 +22,7 @@ "files": [ "dist", "src", + "!dist/test", "!dist/tsconfig.tsbuildinfo" ], "scripts": { @@ -50,6 +51,8 @@ "compile": "node scripts/compileRecipes.mjs", "prettier": "prettier --check . --ignore-path ../../../.prettierignore", "prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore", + "test": "npm run test:local", + "test:local": "node --test ./dist/test/*.spec.js", "tsc": "tsc -b" }, "dependencies": { @@ -59,6 +62,7 @@ "debug": "^4.3.4" }, "devDependencies": { + "@typeagent/action-grammar": "workspace:*", "@typeagent/action-grammar-compiler": "workspace:*", "@typeagent/action-schema-compiler": "workspace:*", "@types/debug": "^4.1.12", diff --git a/ts/packages/agents/powershell/src/actionHandler.mts b/ts/packages/agents/powershell/src/actionHandler.mts index e170f76fb0..ac9d9b060c 100644 --- a/ts/packages/agents/powershell/src/actionHandler.mts +++ b/ts/packages/agents/powershell/src/actionHandler.mts @@ -28,6 +28,7 @@ import { homedir } from "os"; import { ScriptAnalyzer } from "./analysis/scriptAnalyzer.mjs"; import { fileURLToPath } from "url"; import { PowerShellStore } from "./store/powerShellStore.mjs"; +import { formatPowerShellFlowDetails } from "./flowDetails.mjs"; import type { PowerShellFlowDefinition } from "./store/powerShellStore.mjs"; import { type ScriptRecipe, @@ -253,6 +254,35 @@ async function handlePowerShellFlowAction( ); } + case "showPowerShellFlow": { + if (!flowStore) { + return createActionResultFromError( + "Script flow store not available", + ); + } + const flowName = action.parameters?.flowName as string | undefined; + if (!flowName) { + return createActionResultFromError( + "Missing required parameter: flowName", + ); + } + const flow = await flowStore.getFlow(flowName); + if (!flow) { + return createActionResultFromError( + `Unknown PowerShell flow '${flowName}'. Use '@powershell list' to see available flows.`, + ); + } + const script = await flowStore.getScript(flowName); + const usageCount = + flowStore + .listFlows() + .find((entry) => entry.actionName === flowName) + ?.usageCount ?? 0; + return createActionResultFromTextDisplay( + formatPowerShellFlowDetails(flow, script, usageCount), + ); + } + case "deletePowerShellFlow": { if (!flowStore) { return createActionResultFromError( @@ -849,6 +879,7 @@ class DeleteHandler implements CommandHandler { class ShowHandler implements CommandHandler { public readonly description = "Show details of a PowerShell flow"; + public readonly action = "showPowerShellFlow"; public readonly parameters = { args: { flowName: { @@ -860,61 +891,13 @@ class ShowHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const store = _agentStore; - if (!store) { - throw new Error("Script flow store not available"); - } - - const flowName = params.args.flowName; - if (!flowName) { - throw new Error("Missing required argument: flowName"); - } - - const flow = await store.getFlow(flowName); - if (!flow) { - throw new Error( - `Unknown PowerShell flow '${flowName}'. Use '@powershell list' to see available flows.`, - ); - } - - const script = await store.getScript(flowName); - const entries = store.listFlows(); - const entry = entries.find((e) => e.actionName === flowName); - - const paramLines = flow.parameters.map( - (p) => - ` ${p.name} (${p.type}${p.required ? ", required" : ""}): ${p.description}${p.default !== undefined ? ` [default: ${p.default}]` : ""}`, - ); - const grammarLines = flow.grammarPatterns.map( - (g) => ` "${g.pattern}"${g.isAlias ? " (alias)" : ""}`, + return executeBuiltInPowerShellAction( + { + actionName: "showPowerShellFlow", + parameters: { flowName: params.args.flowName }, + }, + context, ); - const cmdletList = flow.sandbox.allowedCmdlets.join(", "); - - const output = [ - `Flow: ${flow.actionName}`, - `Description: ${flow.description}`, - `Display Name: ${flow.displayName}`, - `Source: ${flow.source?.type ?? "unknown"}`, - `Usage Count: ${entry?.usageCount ?? 0}`, - "", - "Parameters:", - paramLines.length > 0 ? paramLines.join("\n") : " (none)", - "", - "Grammar Patterns:", - grammarLines.length > 0 ? grammarLines.join("\n") : " (none)", - "", - "Sandbox:", - ` Cmdlets: ${cmdletList || "(none)"}`, - ` Timeout: ${flow.sandbox.maxExecutionTime}s`, - ` Network: ${flow.sandbox.networkAccess ? "allowed" : "blocked"}`, - "", - "Script:", - "```powershell", - script ?? "(script not found)", - "```", - ]; - - context.actionIO.setDisplay(output.join("\n")); } } @@ -933,6 +916,7 @@ const handlers: CommandHandlerTable = { // in that schema is a dynamic, user-created flow. const POWERSHELL_BUILTIN_ACTIONS = new Set([ "listPowerShellFlows", + "showPowerShellFlow", "deletePowerShellFlow", "executePowerShellFlow", "createPowerShellFlow", diff --git a/ts/packages/agents/powershell/src/flowDetails.mts b/ts/packages/agents/powershell/src/flowDetails.mts new file mode 100644 index 0000000000..e6dd6edb6e --- /dev/null +++ b/ts/packages/agents/powershell/src/flowDetails.mts @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { PowerShellFlowDefinition } from "./store/powerShellStore.mjs"; + +export function formatPowerShellFlowDetails( + flow: PowerShellFlowDefinition, + script: string | null, + usageCount: number, +): string { + const paramLines = flow.parameters.map( + (parameter) => + ` ${parameter.name} (${parameter.type}${parameter.required ? ", required" : ""}): ${parameter.description}${parameter.default !== undefined ? ` [default: ${parameter.default}]` : ""}`, + ); + const grammarLines = flow.grammarPatterns.map( + (pattern) => + ` "${pattern.pattern}"${pattern.isAlias ? " (alias)" : ""}`, + ); + const cmdletList = flow.sandbox.allowedCmdlets.join(", "); + + return [ + `Flow: ${flow.actionName}`, + `Description: ${flow.description}`, + `Display Name: ${flow.displayName}`, + `Source: ${flow.source?.type ?? "unknown"}`, + `Usage Count: ${usageCount}`, + "", + "Parameters:", + paramLines.length > 0 ? paramLines.join("\n") : " (none)", + "", + "Grammar Patterns:", + grammarLines.length > 0 ? grammarLines.join("\n") : " (none)", + "", + "Sandbox:", + ` Cmdlets: ${cmdletList || "(none)"}`, + ` Timeout: ${flow.sandbox.maxExecutionTime}s`, + ` Network: ${flow.sandbox.networkAccess ? "allowed" : "blocked"}`, + "", + "Script:", + "```powershell", + script ?? "(script not found)", + "```", + ].join("\n"); +} diff --git a/ts/packages/agents/powershell/src/powershellSchema.agr b/ts/packages/agents/powershell/src/powershellSchema.agr index d57c244874..b704c21d50 100644 --- a/ts/packages/agents/powershell/src/powershellSchema.agr +++ b/ts/packages/agents/powershell/src/powershellSchema.agr @@ -3,11 +3,15 @@ import { PowerShellActions } from "./schema/scriptActions.mts"; - : PowerShellActions = | | ; + : PowerShellActions = | | | ; // Built-in action rules (dynamic flows are registered at runtime via addGeneratedRules) = ()? ()? ()? (show me | list | display) (all)? (the)? (available)? powershell flows -> { actionName: "listPowerShellFlows" }; + [spacing=optional] = + (show | describe | inspect) (me)? (the)? powershell flow $(flowName:wildcard) + -> { actionName: "showPowerShellFlow", parameters: { flowName } }; + [spacing=optional] = (delete | remove) (the)? powershell flow $(name:wildcard) -> { actionName: "deletePowerShellFlow", parameters: { name } }; diff --git a/ts/packages/agents/powershell/src/schema/scriptActions.mts b/ts/packages/agents/powershell/src/schema/scriptActions.mts index c33a7ada90..7a5cdc9992 100644 --- a/ts/packages/agents/powershell/src/schema/scriptActions.mts +++ b/ts/packages/agents/powershell/src/schema/scriptActions.mts @@ -6,6 +6,17 @@ export type ListPowerShellFlows = { actionName: "listPowerShellFlows"; }; +// user: show me the details for the cleanup PowerShell flow +// agent: { "actionName": "showPowerShellFlow", "parameters": { "flowName": "cleanup" } } +// Show the saved definition and script for a PowerShell flow. +export type ShowPowerShellFlow = { + actionName: "showPowerShellFlow"; + parameters: { + // Name of the PowerShell flow to show. + flowName: string; + }; +}; + // Delete a PowerShell flow by name export type DeletePowerShellFlow = { actionName: "deletePowerShellFlow"; @@ -91,6 +102,7 @@ export type ImportPowerShellFlow = { export type PowerShellActions = | ListPowerShellFlows + | ShowPowerShellFlow | DeletePowerShellFlow | ExecutePowerShellFlow | CreatePowerShellFlow diff --git a/ts/packages/agents/powershell/src/store/powerShellStore.mts b/ts/packages/agents/powershell/src/store/powerShellStore.mts index be63ed9800..58b90b6085 100644 --- a/ts/packages/agents/powershell/src/store/powerShellStore.mts +++ b/ts/packages/agents/powershell/src/store/powerShellStore.mts @@ -358,6 +358,14 @@ export class PowerShellStore { ' actionName: "listPowerShellFlows";', "};", "", + "// Show the saved definition and script for a PowerShell flow", + "export type ShowPowerShellFlow = {", + ' actionName: "showPowerShellFlow";', + " parameters: {", + ` flowName: ${flowNameType};`, + " };", + "};", + "", "// Delete a PowerShell flow by name", "export type DeletePowerShellFlow = {", ' actionName: "deletePowerShellFlow";', @@ -365,6 +373,16 @@ export class PowerShellStore { " name: string;", " };", "};", + "", + "// Execute a registered PowerShell flow by name with parameters", + "export type ExecutePowerShellFlow = {", + ' actionName: "executePowerShellFlow";', + " parameters: {", + ` flowName: ${flowNameType};`, + " flowArgs?: string;", + " flowParametersJson?: string;", + " };", + "};", ].join("\n"); const { typeDefinitions, typeNames } = @@ -440,7 +458,9 @@ export class PowerShellStore { const allTypeNames = [ "ListPowerShellFlows", + "ShowPowerShellFlow", "DeletePowerShellFlow", + "ExecutePowerShellFlow", ...typeNames, "TestPowerShellFlow", "CreatePowerShellFlow", diff --git a/ts/packages/agents/powershell/test/powerShellShow.spec.ts b/ts/packages/agents/powershell/test/powerShellShow.spec.ts new file mode 100644 index 0000000000..7debeb9787 --- /dev/null +++ b/ts/packages/agents/powershell/test/powerShellShow.spec.ts @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import assert from "node:assert/strict"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { + compileGrammarToNFA, + loadGrammarRulesNoThrow, + matchNFA, +} from "@typeagent/action-grammar"; +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; +import type { + PowerShellFlowDefinition, + PowerShellStore as PowerShellStoreType, +} from "../src/store/powerShellStore.mjs"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(here, "..", ".."); +const { instantiate } = await import( + pathToFileURL(path.join(packageRoot, "dist", "actionHandler.mjs")).href +); +const { formatPowerShellFlowDetails } = await import( + pathToFileURL(path.join(packageRoot, "dist", "flowDetails.mjs")).href +); +const { PowerShellStore } = await import( + pathToFileURL( + path.join(packageRoot, "dist", "store", "powerShellStore.mjs"), + ).href +); +const grammarPath = path.resolve( + here, + "..", + "..", + "src", + "powershellSchema.agr", +); + +function makeMatcher() { + const errors: string[] = []; + const grammar = loadGrammarRulesNoThrow( + "powershellSchema.agr", + fs.readFileSync(grammarPath, "utf8"), + errors, + ); + if (grammar === undefined || errors.length > 0) { + throw new Error( + `Failed to parse PowerShell grammar: ${errors.join("; ")}`, + ); + } + const nfa = compileGrammarToNFA(grammar, "powershell"); + return (input: string) => { + const result = matchNFA(nfa, input.toLowerCase().split(/\s+/), false); + return result.matched ? result.actionValue : undefined; + }; +} + +function makeFlow(): PowerShellFlowDefinition { + return { + version: 1, + actionName: "cleanup", + displayName: "Cleanup", + description: "Remove temporary files", + parameters: [ + { + name: "path", + type: "path", + required: true, + description: "Directory to clean", + default: "$env:TEMP", + }, + ], + scriptRef: "scripts/cleanup.ps1", + expectedOutputFormat: "text", + grammarPatterns: [ + { + pattern: "clean temporary files", + isAlias: true, + examples: [], + }, + ], + sandbox: { + allowedCmdlets: ["Get-ChildItem", "Remove-Item"], + allowedPaths: ["$env:TEMP"], + allowedModules: ["Microsoft.PowerShell.Management"], + maxExecutionTime: 30, + networkAccess: false, + }, + source: { type: "manual", timestamp: "2026-07-31T00:00:00.000Z" }, + }; +} + +describe("showPowerShellFlow", () => { + it("matches an anchored natural-language request", () => { + const match = makeMatcher(); + + assert.deepEqual(match("show powershell flow cleanup"), { + actionName: "showPowerShellFlow", + parameters: { flowName: "cleanup" }, + }); + }); + + it("formats the same details used by command and action paths", () => { + const text = formatPowerShellFlowDetails( + makeFlow(), + "param($path)\nGet-ChildItem $path", + 4, + ); + + assert.match(text, /Flow: cleanup/); + assert.match(text, /Usage Count: 4/); + assert.match(text, /path \(path, required\).*\[default: \$env:TEMP\]/); + assert.match(text, /"clean temporary files" \(alias\)/); + assert.match(text, /Cmdlets: Get-ChildItem, Remove-Item/); + assert.match(text, /```powershell\nparam\(\$path\)/); + }); + + it("links the show command to the action", async () => { + const descriptors = (await instantiate().getCommands!({} as any)) as + | CommandDescriptor + | CommandDescriptorTable; + assert.ok("commands" in descriptors); + assert.equal( + (descriptors.commands.show as CommandDescriptor).action, + "showPowerShellFlow", + ); + }); + + it("keeps show and execute actions in the runtime-generated schema", () => { + const store = Object.create( + PowerShellStore.prototype, + ) as PowerShellStoreType; + (store as any).index = { flows: {} }; + + const schema = store.generateDynamicSchemaText(); + + assert.match(schema, /export type ShowPowerShellFlow/); + assert.match(schema, /export type ExecutePowerShellFlow/); + assert.match( + schema, + /PowerShellActions[\s\S]*ShowPowerShellFlow[\s\S]*ExecutePowerShellFlow/, + ); + }); +}); diff --git a/ts/packages/agents/powershell/test/tsconfig.json b/ts/packages/agents/powershell/test/tsconfig.json new file mode 100644 index 0000000000..072111edfe --- /dev/null +++ b/ts/packages/agents/powershell/test/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "rootDir": ".", + "outDir": "../dist/test", + "types": ["node"] + }, + "include": ["./**/*"], + "references": [{ "path": "../src" }] +} diff --git a/ts/packages/agents/powershell/tsconfig.json b/ts/packages/agents/powershell/tsconfig.json index 101c05e749..97ba0ad295 100644 --- a/ts/packages/agents/powershell/tsconfig.json +++ b/ts/packages/agents/powershell/tsconfig.json @@ -4,5 +4,5 @@ "composite": true }, "include": [], - "references": [{ "path": "./src" }] + "references": [{ "path": "./src" }, { "path": "./test" }] } diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index 93283966b0..479762cd37 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -2516,6 +2516,9 @@ importers: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) devDependencies: + '@typeagent/action-grammar': + specifier: workspace:* + version: link:../../actionGrammar '@typeagent/action-schema-compiler': specifier: workspace:* version: link:../../actionSchemaCompiler @@ -2596,12 +2599,18 @@ importers: specifier: ^0.1.1 version: 0.1.1(typescript@5.4.5)(zod@3.25.76) devDependencies: + '@typeagent/action-schema-compiler': + specifier: workspace:* + version: link:../../actionSchemaCompiler '@types/debug': specifier: ^4.1.12 version: 4.1.12 copyfiles: specifier: ^2.4.1 version: 2.4.1 + concurrently: + specifier: ^9.1.2 + version: 9.1.2 prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3201,6 +3210,9 @@ importers: specifier: ^4.3.4 version: 4.4.3(supports-color@8.1.1) devDependencies: + '@typeagent/action-grammar': + specifier: workspace:* + version: link:../../actionGrammar '@typeagent/action-grammar-compiler': specifier: workspace:* version: link:../../actionGrammarCompiler From ac76b78b6f0865afeb55ee6a001bab03e92d774c Mon Sep 17 00:00:00 2001 From: Robert Gruen Date: Fri, 31 Jul 2026 14:18:49 -0700 Subject: [PATCH 03/22] more updates --- ts/docs/plans/agent-command-actions/PLAN.md | 3 +- ts/docs/plans/agent-command-actions/STATUS.md | 58 +++--- .../src/agent/automationActionHandler.mts | 47 +++++ .../src/agent/automationActionSchema.mts | 22 +++ .../src/agent/browserActionHandler.mts | 66 ++++++- .../browser/src/agent/configActionHandler.mts | 119 ++++++++++++ .../browser/src/agent/configActionSchema.mts | 108 +++++++++++ .../knowledge/extractKnowledgeCommand.mts | 4 + .../agent/lookup/lookupCommandHandlers.mts | 8 + .../agents/browser/src/agent/manifest.json | 27 +++ .../src/agent/pageToolsActionHandler.mts | 64 +++++++ .../src/agent/pageToolsActionSchema.mts | 40 ++++ .../searchProviderCommandHandlers.mts | 24 +++ .../test/automationActionHandler.test.ts | 42 +++++ .../browser/test/configActionHandler.test.ts | 109 +++++++++++ .../test/pageToolsActionHandler.test.ts | 63 +++++++ ts/packages/agents/calendar/package.json | 1 + .../calendar/src/calendarActionHandlerV3.ts | 29 ++- .../calendar/src/calendarActionsSchemaV3.ts | 28 +++ .../agents/calendar/src/calendarSchema.agr | 14 +- .../agents/calendar/test/calendarAuth.spec.ts | 175 ++++++++++++++++++ .../agents/email/src/emailActionHandler.ts | 36 +++- .../agents/email/src/emailActionsSchema.ts | 28 +++ ts/packages/agents/email/src/emailSchema.agr | 13 +- .../agents/email/test/emailIndex.spec.ts | 144 +++++++++++++- ts/packages/agents/player/package.json | 1 + .../agents/player/src/agent/playerCommands.ts | 60 +----- .../agents/player/src/agent/playerHandlers.ts | 69 +++++++ .../agents/player/src/agent/playerSchema.agr | 11 +- .../agents/player/src/agent/playerSchema.ts | 28 +++ .../player/test/playerManagement.spec.ts | 157 ++++++++++++++++ .../dispatcher/diagnosticsActionHandler.ts | 71 +++++++ .../src/context/dispatcher/dispatcherAgent.ts | 39 +++- .../handlers/explainCommandHandler.ts | 4 + .../handlers/matchCommandHandler.ts | 4 + .../handlers/reasonCommandHandler.ts | 4 + .../handlers/requestCommandHandler.ts | 4 + .../handlers/translateCommandHandler.ts | 4 + .../schema/diagnosticsActionSchema.ts | 76 ++++++++ .../action/conversationActionHandler.ts | 3 + .../system/action/describeActionHandler.ts | 19 ++ .../handlers/conversationCommandHandlers.ts | 1 + .../handlers/describeCommandHandlers.ts | 4 + .../system/handlers/grammarCommandHandlers.ts | 133 ++++--------- .../schema/conversationActionSchema.agr | 7 +- .../system/schema/conversationActionSchema.ts | 6 + .../system/schema/describeActionSchema.ts | 18 +- .../test/conversationActionHandler.spec.ts | 5 + .../test/conversationGrammar.spec.ts | 11 ++ .../test/dispatcherDiagnosticsAction.spec.ts | 135 ++++++++++++++ ts/pnpm-lock.yaml | 6 + 51 files changed, 1949 insertions(+), 203 deletions(-) create mode 100644 ts/packages/agents/browser/src/agent/automationActionHandler.mts create mode 100644 ts/packages/agents/browser/src/agent/automationActionSchema.mts create mode 100644 ts/packages/agents/browser/src/agent/configActionHandler.mts create mode 100644 ts/packages/agents/browser/src/agent/configActionSchema.mts create mode 100644 ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts create mode 100644 ts/packages/agents/browser/src/agent/pageToolsActionSchema.mts create mode 100644 ts/packages/agents/browser/test/automationActionHandler.test.ts create mode 100644 ts/packages/agents/browser/test/configActionHandler.test.ts create mode 100644 ts/packages/agents/browser/test/pageToolsActionHandler.test.ts create mode 100644 ts/packages/agents/calendar/test/calendarAuth.spec.ts create mode 100644 ts/packages/agents/player/test/playerManagement.spec.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/dispatcher/schema/diagnosticsActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/test/dispatcherDiagnosticsAction.spec.ts diff --git a/ts/docs/plans/agent-command-actions/PLAN.md b/ts/docs/plans/agent-command-actions/PLAN.md index 9408315bf0..5239821d19 100644 --- a/ts/docs/plans/agent-command-actions/PLAN.md +++ b/ts/docs/plans/agent-command-actions/PLAN.md @@ -128,7 +128,8 @@ paths use a shared typed helper. 3. **Complete agent-host actions.** Add the known localPlayer and browser gaps, auth/OAuth actions, browser configuration, and dispatcher diagnostics. PowerShell `show` and email indexing were completed in the second - implementation slice. No agent-host command remains excluded. + implementation slice. This phase is complete: no agent-host command remains + uncovered. 4. **Complete existing system families.** Finish `system.config`, `system.conversation`, `system.describe`, `system.grammar`, `system.history`, `system.notify`, and `system.settings`. diff --git a/ts/docs/plans/agent-command-actions/STATUS.md b/ts/docs/plans/agent-command-actions/STATUS.md index 0225a1f512..e6d51f4797 100644 --- a/ts/docs/plans/agent-command-actions/STATUS.md +++ b/ts/docs/plans/agent-command-actions/STATUS.md @@ -18,8 +18,8 @@ collection, not manual estimates. | Metric | Count | | ------------------------------------ | ------------------: | | Executable command endpoints | 387 | -| Valid linked endpoints | 46 | -| Missing action declarations | 341 | +| Valid linked endpoints | 96 | +| Missing action declarations | 291 | | Invalid / dangling / ambiguous links | 0 | | Runtime-only static omissions | 1 (`mcpfilesystem`) | @@ -34,28 +34,41 @@ collection, not manual estimates. - [x] Report runtime-only schema omissions explicitly. - [x] Add missing/invalid endpoint counters and migration check mode. - [ ] Generate and maintain the per-host endpoint ledger. -- [ ] Audit and link exact existing equivalents. -- [ ] Complete all remaining agent-host actions. +- [x] Audit and link exact existing equivalents. +- [x] Complete all remaining agent-host actions. - [ ] Complete existing system action families. - [ ] Add remaining system action families. - [ ] Enable permanent zero-gap regression check. ## Implemented hosts and slices -| Host | Coverage completed in this milestone | -| --------------- | -------------------------------------------------------------------------------------------- | -| localPlayer | All 16 endpoints, including bare status default, general play, and mute/shuffle toggles. | -| osNotifications | `sync`, `test`. | -| selfhelp | Bare default and `ask`. | -| powershell | All five management endpoints: `list`, `run`, `delete`, `show`, and `import`. | -| browser | `open`, `close`, `learn`, `actions match`, `actions infer`, and inherited `actions` default. | -| email | `index`; auth management remains. | -| greeting | Bare command, including deterministic `--mock` action parity. | +| Host | Coverage completed in this milestone | +| --------------- | ----------------------------------------------------------------------------------------- | +| localPlayer | All 16 endpoints, including bare status default, general play, and mute/shuffle toggles. | +| osNotifications | `sync`, `test`. | +| selfhelp | Bare default and `ask`. | +| powershell | All five management endpoints: `list`, `run`, `delete`, `show`, and `import`. | +| browser | All 31 endpoints, including config, automation lifecycle, extraction, Q&A, and recording. | +| email | All 5 endpoints: login default, logout, Google auth, and inbox indexing. | +| greeting | Bare command, including deterministic `--mock` action parity. | +| player | All 3 Spotify management endpoints: load, login, and logout. | +| calendar | All 4 auth endpoints, including the bare login default and Google auth. | +| dispatcher | All 6 request/match/translate/reason/explain diagnostics. | + +All non-system command hosts are now fully covered. + +## System progress + +| Family | Completed in this milestone | +| ------------ | --------------------------------------------------------------- | +| conversation | Added help action for bare `@conversation` and explicit `help`. | +| grammar | Unified and linked list/show/delete/clear plus bare default. | +| describe | Added exact multiplexing action for `@describe`. | The current migration check is: ```text -Command action coverage: 46 / 387 endpoints (341 missing, 0 invalid) +Command action coverage: 96 / 387 endpoints (291 missing, 0 invalid) Runtime-only schemas omitted: mcpfilesystem ``` @@ -67,23 +80,12 @@ pnpm --filter @typeagent/action-browser test:local node tools/actionBrowser/dist/cli.js --check --allow-missing ``` -Strict completion command (expected to fail until all 341 remaining gaps +Strict completion command (expected to fail until all 291 remaining gaps close): ```powershell node tools/actionBrowser/dist/cli.js --check ``` -## Known blockers requiring new behavior - -| Host / command | Reason it cannot be linked yet | -| -------------------------- | ---------------------------------------------------------------- | -| browser `extractKnowledge` | Named action is not in a registered schema. | -| browser `ask` | Proposed action is outside active `BrowserActions`. | -| browser `actions record` | Starts recording; proposed action consumes a finished recording. | -| calendar/email login | Readiness setup intercepts execution while signed out. | -| calendar/email logout | Must refresh cached readiness after logout. | - -No built-in command is excluded. OAuth callbacks, dispatcher diagnostics, -PowerShell `show`, browser automation controls, recording stop, and every -system command remain in the endpoint ledger until covered. +The remaining gaps are all system command families. No built-in command is +excluded; every remaining endpoint stays in the ledger until covered. diff --git a/ts/packages/agents/browser/src/agent/automationActionHandler.mts b/ts/packages/agents/browser/src/agent/automationActionHandler.mts new file mode 100644 index 0000000000..edb96a778b --- /dev/null +++ b/ts/packages/agents/browser/src/agent/automationActionHandler.mts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { BrowserActionContext } from "./browserActions.mjs"; +import { BrowserAutomationActions } from "./automationActionSchema.mjs"; + +type CommandExecutor = ( + handlers: CommandHandlerTable, + commands: string[], + params: undefined, + context: ActionContext, +) => Promise; + +export function executeBrowserAutomationAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, + execute: CommandExecutor = executeCommandFromHandlers, +): Promise { + switch (action.actionName) { + case "launchHiddenAutomationBrowser": + return execute( + handlers, + ["auto", "launch", "hidden"], + undefined, + context, + ); + case "launchStandaloneAutomationBrowser": + return execute( + handlers, + ["auto", "launch", "standalone"], + undefined, + context, + ); + case "closeAutomationBrowser": + return execute(handlers, ["auto", "close"], undefined, context); + } +} diff --git a/ts/packages/agents/browser/src/agent/automationActionSchema.mts b/ts/packages/agents/browser/src/agent/automationActionSchema.mts new file mode 100644 index 0000000000..d123bbb230 --- /dev/null +++ b/ts/packages/agents/browser/src/agent/automationActionSchema.mts @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type BrowserAutomationActions = + | LaunchHiddenAutomationBrowser + | LaunchStandaloneAutomationBrowser + | CloseAutomationBrowser; + +// Launch a hidden browser process for TypeAgent automation. +export type LaunchHiddenAutomationBrowser = { + actionName: "launchHiddenAutomationBrowser"; +}; + +// Launch a visible standalone browser process for TypeAgent automation. +export type LaunchStandaloneAutomationBrowser = { + actionName: "launchStandaloneAutomationBrowser"; +}; + +// Close the browser process launched for TypeAgent automation. +export type CloseAutomationBrowser = { + actionName: "closeAutomationBrowser"; +}; diff --git a/ts/packages/agents/browser/src/agent/browserActionHandler.mts b/ts/packages/agents/browser/src/agent/browserActionHandler.mts index 2c5dcc0855..1d0f19fa5a 100644 --- a/ts/packages/agents/browser/src/agent/browserActionHandler.mts +++ b/ts/packages/agents/browser/src/agent/browserActionHandler.mts @@ -149,6 +149,12 @@ import { LookupCommandHandlerTable } from "./lookup/lookupCommandHandlers.mjs"; import { createExternalBrowserClient } from "./rpc/externalBrowserControlClient.mjs"; import { createAgentInvokeHandlers } from "./agentServiceHandlers.mjs"; import { hookModelTokenUsage, runWithTokenUsage } from "./tokenUsage.mjs"; +import { BrowserConfigActions } from "./configActionSchema.mjs"; +import { executeBrowserConfigAction } from "./configActionHandler.mjs"; +import { BrowserAutomationActions } from "./automationActionSchema.mjs"; +import { executeBrowserAutomationAction } from "./automationActionHandler.mjs"; +import { BrowserPageToolsActions } from "./pageToolsActionSchema.mjs"; +import { executeBrowserPageToolsAction } from "./pageToolsActionHandler.mjs"; const debug = registerDebug("typeagent:browser:action"); const debugClientRouting = registerDebug("typeagent:browser:client-routing"); @@ -1857,7 +1863,10 @@ async function executeBrowserAction( | TypeAgentAction | TypeAgentAction | TypeAgentAction - | TypeAgentAction, + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction, context: ActionContext, ) { @@ -1889,7 +1898,10 @@ async function executeBrowserActionImpl( | TypeAgentAction | TypeAgentAction | TypeAgentAction - | TypeAgentAction, + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction, context: ActionContext, ) { @@ -1958,6 +1970,12 @@ async function executeBrowserActionImpl( // try { switch (action.schemaName) { + case "browser.pageTools": + return executeBrowserPageToolsAction(action, context, handlers); + case "browser.automation": + return executeBrowserAutomationAction(action, context, handlers); + case "browser.config": + return executeBrowserConfigAction(action, context, handlers); case "browser": switch (action.actionName) { case "openWebPage": @@ -2757,6 +2775,10 @@ export async function createAutomationBrowser(isVisible?: boolean) { class OpenStandaloneAutomationBrowserHandler implements CommandHandlerNoParams { public readonly description = "Open a standalone browser instance"; + public readonly action = { + schema: "browser.automation", + actionName: "launchStandaloneAutomationBrowser", + }; public async run(context: ActionContext) { if (context.sessionContext.agentContext.browserProcess) { context.sessionContext.agentContext.browserProcess.kill(); @@ -2768,6 +2790,10 @@ class OpenStandaloneAutomationBrowserHandler implements CommandHandlerNoParams { class OpenHiddenAutomationBrowserHandler implements CommandHandlerNoParams { public readonly description = "Open a hidden/headless browser instance"; + public readonly action = { + schema: "browser.automation", + actionName: "launchHiddenAutomationBrowser", + }; public async run(context: ActionContext) { if (context.sessionContext.agentContext.browserProcess) { context.sessionContext.agentContext.browserProcess.kill(); @@ -2779,6 +2805,10 @@ class OpenHiddenAutomationBrowserHandler implements CommandHandlerNoParams { class CloseBrowserHandler implements CommandHandlerNoParams { public readonly description = "Close the new Web Content view"; + public readonly action = { + schema: "browser.automation", + actionName: "closeAutomationBrowser", + }; public async run(context: ActionContext) { if (context.sessionContext.agentContext.browserProcess) { context.sessionContext.agentContext.browserProcess.kill(); @@ -3045,6 +3075,10 @@ export async function handleWebsiteLibraryStats( class RecordActionHandler implements CommandHandler { public readonly description = "Record a new browser action by capturing user interactions"; + public readonly action = { + schema: "browser.pageTools", + actionName: "startPageActionRecording", + }; public readonly parameters = { args: { name: { @@ -3084,6 +3118,10 @@ class RecordActionHandler implements CommandHandler { class StopRecordingHandler implements CommandHandler { public readonly description = "Stop recording and create a WebFlow"; + public readonly action = { + schema: "browser.pageTools", + actionName: "stopPageActionRecording", + }; public readonly parameters = { args: { description: { @@ -3111,6 +3149,10 @@ class StopRecordingHandler implements CommandHandler { class AskAboutPageHandler implements CommandHandler { public readonly description = "Ask a question about the current web page using extracted knowledge"; + public readonly action = { + schema: "browser.pageTools", + actionName: "answerCurrentPageQuestion", + }; public readonly parameters = { args: { question: { @@ -3327,6 +3369,10 @@ export const handlers: CommandHandlerTable = { commands: { on: { description: "Enable external browser control", + action: { + schema: "browser.config", + actionName: "useExternalBrowserControl", + }, run: async ( context: ActionContext, ) => { @@ -3373,6 +3419,10 @@ export const handlers: CommandHandlerTable = { }, off: { description: "Disable external browser control", + action: { + schema: "browser.config", + actionName: "useClientBrowserControl", + }, run: async ( context: ActionContext, ) => { @@ -3421,6 +3471,10 @@ export const handlers: CommandHandlerTable = { commands: { list: { description: "List all available URL resolvers", + action: { + schema: "browser.config", + actionName: "listUrlResolvers", + }, run: async ( context: ActionContext, ) => { @@ -3442,6 +3496,10 @@ export const handlers: CommandHandlerTable = { }, keyword: { description: "Toggle keyword resolver", + action: { + schema: "browser.config", + actionName: "toggleKeywordResolver", + }, run: async ( context: ActionContext, ) => { @@ -3462,6 +3520,10 @@ export const handlers: CommandHandlerTable = { }, history: { description: "Toggle history resolver", + action: { + schema: "browser.config", + actionName: "toggleHistoryResolver", + }, run: async ( context: ActionContext, ) => { diff --git a/ts/packages/agents/browser/src/agent/configActionHandler.mts b/ts/packages/agents/browser/src/agent/configActionHandler.mts new file mode 100644 index 0000000000..bc6b3aa11a --- /dev/null +++ b/ts/packages/agents/browser/src/agent/configActionHandler.mts @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { BrowserActionContext } from "./browserActions.mjs"; +import { BrowserConfigActions } from "./configActionSchema.mjs"; + +type CommandExecutor = ( + handlers: CommandHandlerTable, + commands: string[], + params: ParsedCommandParams | undefined, + context: ActionContext, +) => Promise; + +export async function executeBrowserConfigAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, + execute: CommandExecutor = executeCommandFromHandlers, +): Promise { + switch (action.actionName) { + case "useExternalBrowserControl": + return execute(handlers, ["external", "on"], undefined, context); + case "useClientBrowserControl": + return execute(handlers, ["external", "off"], undefined, context); + case "listUrlResolvers": + return execute(handlers, ["resolver", "list"], undefined, context); + case "toggleKeywordResolver": + return execute( + handlers, + ["resolver", "keyword"], + undefined, + context, + ); + case "toggleHistoryResolver": + return execute( + handlers, + ["resolver", "history"], + undefined, + context, + ); + case "showLookupSettings": + return execute(handlers, ["lookup", "status"], undefined, context); + case "setLookupMode": + return execute( + handlers, + ["lookup", "mode"], + { + args: { mode: action.parameters.mode }, + flags: undefined, + }, + context, + ); + case "listSearchProviders": + return execute(handlers, ["search", "list"], undefined, context); + case "setSearchProvider": + return execute( + handlers, + ["search", "set"], + { + args: { provider: action.parameters.provider }, + flags: undefined, + }, + context, + ); + case "showSearchProvider": + return execute( + handlers, + ["search", "show"], + { + args: { provider: action.parameters.provider }, + flags: undefined, + }, + context, + ); + case "addSearchProvider": + return execute( + handlers, + ["search", "add"], + { + args: { + provider: action.parameters.provider, + url: action.parameters.url, + }, + flags: undefined, + }, + context, + ); + case "removeSearchProvider": + return execute( + handlers, + ["search", "remove"], + { + args: { provider: action.parameters.provider }, + flags: undefined, + }, + context, + ); + case "importSearchProviders": + return execute( + handlers, + ["search", "import"], + { + args: { browser: action.parameters.browser }, + flags: undefined, + }, + context, + ); + } +} diff --git a/ts/packages/agents/browser/src/agent/configActionSchema.mts b/ts/packages/agents/browser/src/agent/configActionSchema.mts new file mode 100644 index 0000000000..7d14e8fbc0 --- /dev/null +++ b/ts/packages/agents/browser/src/agent/configActionSchema.mts @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type BrowserConfigActions = + | UseExternalBrowserControl + | UseClientBrowserControl + | ListUrlResolvers + | ToggleKeywordResolver + | ToggleHistoryResolver + | ShowLookupSettings + | SetLookupMode + | ListSearchProviders + | SetSearchProvider + | ShowSearchProvider + | AddSearchProvider + | RemoveSearchProvider + | ImportSearchProviders; + +// Use the connected browser extension for browser control. +export type UseExternalBrowserControl = { + actionName: "useExternalBrowserControl"; +}; + +// Use the TypeAgent client browser for browser control. +export type UseClientBrowserControl = { + actionName: "useClientBrowserControl"; +}; + +// List the browser URL resolvers and their enabled state. +export type ListUrlResolvers = { + actionName: "listUrlResolvers"; +}; + +// Toggle the browser keyword URL resolver. +export type ToggleKeywordResolver = { + actionName: "toggleKeywordResolver"; +}; + +// Toggle the browser-history URL resolver. +export type ToggleHistoryResolver = { + actionName: "toggleHistoryResolver"; +}; + +// Show the effective internet lookup configuration. +export type ShowLookupSettings = { + actionName: "showLookupSettings"; +}; + +// Set how browser internet lookups are answered. +export type SetLookupMode = { + actionName: "setLookupMode"; + parameters: { + // Lookup implementation: browser only, Azure AI Search API, or Azure AI Search MCP. + mode: "off" | "api" | "mcp"; + }; +}; + +// List configured browser search providers. +export type ListSearchProviders = { + actionName: "listSearchProviders"; +}; + +// Select the active browser search provider. +export type SetSearchProvider = { + actionName: "setSearchProvider"; + parameters: { + // Name of the configured search provider. + provider: string; + }; +}; + +// Show one browser search provider's configuration. +export type ShowSearchProvider = { + actionName: "showSearchProvider"; + parameters: { + // Name of the configured search provider. + provider: string; + }; +}; + +// Add a browser search provider. +export type AddSearchProvider = { + actionName: "addSearchProvider"; + parameters: { + // Name for the search provider. + provider: string; + // Search URL containing a %s placeholder for the encoded query. + url: string; + }; +}; + +// Remove a browser search provider. +export type RemoveSearchProvider = { + actionName: "removeSearchProvider"; + parameters: { + // Name of the configured search provider. + provider: string; + }; +}; + +// Import search providers from an installed browser. +export type ImportSearchProviders = { + actionName: "importSearchProviders"; + parameters: { + // Browser from which to import search providers. + browser: "Edge" | "Chrome"; + }; +}; diff --git a/ts/packages/agents/browser/src/agent/knowledge/extractKnowledgeCommand.mts b/ts/packages/agents/browser/src/agent/knowledge/extractKnowledgeCommand.mts index 68698987f1..0ef0c2a251 100644 --- a/ts/packages/agents/browser/src/agent/knowledge/extractKnowledgeCommand.mts +++ b/ts/packages/agents/browser/src/agent/knowledge/extractKnowledgeCommand.mts @@ -309,6 +309,10 @@ async function performKnowledgeExtraction( export class ExtractKnowledgeHandler implements CommandHandlerNoParams { public readonly description = "Extract knowledge from the current web page"; + public readonly action = { + schema: "browser.pageTools", + actionName: "extractCurrentPageKnowledge", + }; public async run( context: ActionContext, diff --git a/ts/packages/agents/browser/src/agent/lookup/lookupCommandHandlers.mts b/ts/packages/agents/browser/src/agent/lookup/lookupCommandHandlers.mts index cd47c90864..2b19533364 100644 --- a/ts/packages/agents/browser/src/agent/lookup/lookupCommandHandlers.mts +++ b/ts/packages/agents/browser/src/agent/lookup/lookupCommandHandlers.mts @@ -43,6 +43,10 @@ export class LookupCommandHandlerTable implements CommandHandlerTable { class LookupStatusCommandHandler implements CommandHandlerNoParams { public readonly description = "Show the current internet lookup mode"; + public readonly action = { + schema: "browser.config", + actionName: "showLookupSettings", + }; public async run( context: ActionContext, ): Promise { @@ -73,6 +77,10 @@ class LookupStatusCommandHandler implements CommandHandlerNoParams { class LookupModeCommandHandler implements CommandHandler { public readonly description = "Set the internet lookup mode: off (browser), api, or mcp"; + public readonly action = { + schema: "browser.config", + actionName: "setLookupMode", + }; public readonly parameters = { args: { mode: { diff --git a/ts/packages/agents/browser/src/agent/manifest.json b/ts/packages/agents/browser/src/agent/manifest.json index 8dfafc7fbf..586cb69fab 100644 --- a/ts/packages/agents/browser/src/agent/manifest.json +++ b/ts/packages/agents/browser/src/agent/manifest.json @@ -24,6 +24,33 @@ } }, "subActionManifests": { + "pageTools": { + "defaultEnabled": true, + "transient": false, + "schema": { + "description": "Extract knowledge, answer questions, and record reusable actions on the current browser page.", + "schemaFile": "./pageToolsActionSchema.mts", + "schemaType": "BrowserPageToolsActions" + } + }, + "automation": { + "defaultEnabled": true, + "transient": false, + "schema": { + "description": "Launch and close browser processes used by TypeAgent automation.", + "schemaFile": "./automationActionSchema.mts", + "schemaType": "BrowserAutomationActions" + } + }, + "config": { + "defaultEnabled": true, + "transient": false, + "schema": { + "description": "Configure browser control routing, URL resolvers, internet lookup mode, and search providers.", + "schemaFile": "./configActionSchema.mts", + "schemaType": "BrowserConfigActions" + } + }, "lookupAndAnswer": { "defaultEnabled": true, "transient": false, diff --git a/ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts b/ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts new file mode 100644 index 0000000000..4c2ef02953 --- /dev/null +++ b/ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { BrowserActionContext } from "./browserActions.mjs"; +import { BrowserPageToolsActions } from "./pageToolsActionSchema.mjs"; + +type CommandExecutor = ( + handlers: CommandHandlerTable, + commands: string[], + params: ParsedCommandParams | undefined, + context: ActionContext, +) => Promise; + +export function executeBrowserPageToolsAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, + execute: CommandExecutor = executeCommandFromHandlers, +): Promise { + switch (action.actionName) { + case "extractCurrentPageKnowledge": + return execute(handlers, ["extractKnowledge"], undefined, context); + case "answerCurrentPageQuestion": + return execute( + handlers, + ["ask"], + { + args: { question: action.parameters.question }, + flags: undefined, + }, + context, + ); + case "startPageActionRecording": + return execute( + handlers, + ["actions", "record"], + { + args: { name: action.parameters.name }, + flags: undefined, + }, + context, + ); + case "stopPageActionRecording": + return execute( + handlers, + ["actions", "stop", "recording"], + { + args: { description: action.parameters?.description }, + flags: undefined, + }, + context, + ); + } +} diff --git a/ts/packages/agents/browser/src/agent/pageToolsActionSchema.mts b/ts/packages/agents/browser/src/agent/pageToolsActionSchema.mts new file mode 100644 index 0000000000..f3bc9c0f49 --- /dev/null +++ b/ts/packages/agents/browser/src/agent/pageToolsActionSchema.mts @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type BrowserPageToolsActions = + | ExtractCurrentPageKnowledge + | AnswerCurrentPageQuestion + | StartPageActionRecording + | StopPageActionRecording; + +// Extract and index structured knowledge from the current browser page. +export type ExtractCurrentPageKnowledge = { + actionName: "extractCurrentPageKnowledge"; +}; + +// Answer a question using knowledge from the current browser page. +export type AnswerCurrentPageQuestion = { + actionName: "answerCurrentPageQuestion"; + parameters: { + // Question to answer about the current page. + question: string; + }; +}; + +// Start recording browser interactions for a named page action. +export type StartPageActionRecording = { + actionName: "startPageActionRecording"; + parameters: { + // Name of the browser action being recorded. + name: string; + }; +}; + +// Stop the current browser interaction recording. +export type StopPageActionRecording = { + actionName: "stopPageActionRecording"; + parameters?: { + // Optional description of what the recorded action does. + description?: string; + }; +}; diff --git a/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts b/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts index ce0731c727..3f6a10ad2a 100644 --- a/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts +++ b/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts @@ -29,6 +29,10 @@ export class SearchProviderCommandHandlerTable implements CommandHandlerTable { export class ListCommandHandler implements CommandHandlerNoParams { public readonly description = "Lists browser agent search providers"; + public readonly action = { + schema: "browser.config", + actionName: "listSearchProviders", + }; public async run( context: ActionContext, ): Promise { @@ -52,6 +56,10 @@ export class ListCommandHandler implements CommandHandlerNoParams { export class SetCommandHandler implements CommandHandler { public readonly description = "Sets the active search provider"; + public readonly action = { + schema: "browser.config", + actionName: "setSearchProvider", + }; public readonly parameters = { args: { provider: { @@ -100,6 +108,10 @@ export class SetCommandHandler implements CommandHandler { export class ShowCommandHandler implements CommandHandler { public readonly description = "Shows the details of the selected search provider"; + public readonly action = { + schema: "browser.config", + actionName: "showSearchProvider", + }; public readonly parameters = { args: { provider: { @@ -138,6 +150,10 @@ export class ShowCommandHandler implements CommandHandler { export class AddCommandHandler implements CommandHandler { public readonly description = "Adds a new search provider"; + public readonly action = { + schema: "browser.config", + actionName: "addSearchProvider", + }; public readonly parameters = { args: { provider: { @@ -196,6 +212,10 @@ export class AddCommandHandler implements CommandHandler { export class RemoveCommandHandler implements CommandHandler { public readonly description = "Removes the selected search provider"; + public readonly action = { + schema: "browser.config", + actionName: "removeSearchProvider", + }; public readonly parameters = { args: { provider: { @@ -260,6 +280,10 @@ export class RemoveCommandHandler implements CommandHandler { export class ImportCommandHandler implements CommandHandler { public readonly description = "Imports the search providers from the specified browser"; + public readonly action = { + schema: "browser.config", + actionName: "importSearchProviders", + }; public readonly parameters = { args: { browser: { diff --git a/ts/packages/agents/browser/test/automationActionHandler.test.ts b/ts/packages/agents/browser/test/automationActionHandler.test.ts new file mode 100644 index 0000000000..c7cca569e4 --- /dev/null +++ b/ts/packages/agents/browser/test/automationActionHandler.test.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { executeBrowserAutomationAction } from "../src/agent/automationActionHandler.mjs"; + +describe("browser automation actions", () => { + it("maps lifecycle actions to canonical commands", async () => { + const calls: unknown[][] = []; + const execute = async (...args: unknown[]) => { + calls.push(args); + return undefined; + }; + const handlers = { description: "test", commands: {} } as any; + const context = { id: "context" } as any; + const cases = [ + ["launchHiddenAutomationBrowser", ["auto", "launch", "hidden"]], + [ + "launchStandaloneAutomationBrowser", + ["auto", "launch", "standalone"], + ], + ["closeAutomationBrowser", ["auto", "close"]], + ] as const; + + for (const [actionName] of cases) { + await executeBrowserAutomationAction( + { schemaName: "browser.automation", actionName } as any, + context, + handlers, + execute as any, + ); + } + + expect(calls).toEqual( + cases.map(([, commands]) => [ + handlers, + commands, + undefined, + context, + ]), + ); + }); +}); diff --git a/ts/packages/agents/browser/test/configActionHandler.test.ts b/ts/packages/agents/browser/test/configActionHandler.test.ts new file mode 100644 index 0000000000..5b709b0943 --- /dev/null +++ b/ts/packages/agents/browser/test/configActionHandler.test.ts @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { executeBrowserConfigAction } from "../src/agent/configActionHandler.mjs"; + +describe("browser config actions", () => { + it("maps every action to its canonical command path and parameters", async () => { + const calls: unknown[][] = []; + const execute = async (...args: unknown[]) => { + calls.push(args); + return undefined; + }; + const handlers = { description: "test", commands: {} } as any; + const context = { id: "context" } as any; + const cases = [ + [ + "useExternalBrowserControl", + undefined, + ["external", "on"], + undefined, + ], + [ + "useClientBrowserControl", + undefined, + ["external", "off"], + undefined, + ], + ["listUrlResolvers", undefined, ["resolver", "list"], undefined], + [ + "toggleKeywordResolver", + undefined, + ["resolver", "keyword"], + undefined, + ], + [ + "toggleHistoryResolver", + undefined, + ["resolver", "history"], + undefined, + ], + ["showLookupSettings", undefined, ["lookup", "status"], undefined], + [ + "setLookupMode", + { mode: "mcp" }, + ["lookup", "mode"], + { args: { mode: "mcp" }, flags: undefined }, + ], + ["listSearchProviders", undefined, ["search", "list"], undefined], + [ + "setSearchProvider", + { provider: "Bing" }, + ["search", "set"], + { args: { provider: "Bing" }, flags: undefined }, + ], + [ + "showSearchProvider", + { provider: "Bing" }, + ["search", "show"], + { args: { provider: "Bing" }, flags: undefined }, + ], + [ + "addSearchProvider", + { provider: "Example", url: "https://example.com/?q=%s" }, + ["search", "add"], + { + args: { + provider: "Example", + url: "https://example.com/?q=%s", + }, + flags: undefined, + }, + ], + [ + "removeSearchProvider", + { provider: "Example" }, + ["search", "remove"], + { args: { provider: "Example" }, flags: undefined }, + ], + [ + "importSearchProviders", + { browser: "Edge" }, + ["search", "import"], + { args: { browser: "Edge" }, flags: undefined }, + ], + ] as const; + + for (const [actionName, parameters] of cases) { + await executeBrowserConfigAction( + { + schemaName: "browser.config", + actionName, + ...(parameters === undefined ? {} : { parameters }), + } as any, + context, + handlers, + execute as any, + ); + } + + expect(calls).toEqual( + cases.map(([, , commands, params]) => [ + handlers, + commands, + params, + context, + ]), + ); + }); +}); diff --git a/ts/packages/agents/browser/test/pageToolsActionHandler.test.ts b/ts/packages/agents/browser/test/pageToolsActionHandler.test.ts new file mode 100644 index 0000000000..3f19471165 --- /dev/null +++ b/ts/packages/agents/browser/test/pageToolsActionHandler.test.ts @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { executeBrowserPageToolsAction } from "../src/agent/pageToolsActionHandler.mjs"; + +describe("browser page-tools actions", () => { + it("maps page tools to canonical commands and arguments", async () => { + const calls: unknown[][] = []; + const execute = async (...args: unknown[]) => { + calls.push(args); + return undefined; + }; + const handlers = { description: "test", commands: {} } as any; + const context = { id: "context" } as any; + const cases = [ + ["extractCurrentPageKnowledge", undefined], + ["answerCurrentPageQuestion", { question: "What is this about?" }], + ["startPageActionRecording", { name: "Add to cart" }], + ["stopPageActionRecording", { description: "Adds one item" }], + ] as const; + + for (const [actionName, parameters] of cases) { + await executeBrowserPageToolsAction( + { + schemaName: "browser.pageTools", + actionName, + ...(parameters === undefined ? {} : { parameters }), + } as any, + context, + handlers, + execute as any, + ); + } + + expect(calls).toEqual([ + [handlers, ["extractKnowledge"], undefined, context], + [ + handlers, + ["ask"], + { + args: { question: "What is this about?" }, + flags: undefined, + }, + context, + ], + [ + handlers, + ["actions", "record"], + { args: { name: "Add to cart" }, flags: undefined }, + context, + ], + [ + handlers, + ["actions", "stop", "recording"], + { + args: { description: "Adds one item" }, + flags: undefined, + }, + context, + ], + ]); + }); +}); diff --git a/ts/packages/agents/calendar/package.json b/ts/packages/agents/calendar/package.json index c1ef6b7dbe..214a8ec646 100644 --- a/ts/packages/agents/calendar/package.json +++ b/ts/packages/agents/calendar/package.json @@ -44,6 +44,7 @@ "debug": "^4.4.0" }, "devDependencies": { + "@typeagent/action-grammar": "workspace:*", "@typeagent/action-grammar-compiler": "workspace:*", "@typeagent/action-schema-compiler": "workspace:*", "@types/debug": "^4.1.12", diff --git a/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts b/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts index 8ff0c2dd70..ade065b384 100644 --- a/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts +++ b/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts @@ -71,6 +71,7 @@ export class CalendarClientLoginCommandHandler implements CommandHandlerNoParams { public readonly description = "Log into calendar service"; + public readonly action = "calendarLogin"; public async run(context: ActionContext) { const provider = context.sessionContext.agentContext.calendarProvider; const providerType = context.sessionContext.agentContext.providerType; @@ -148,6 +149,7 @@ export class CalendarClientLogoutCommandHandler implements CommandHandlerNoParams { public readonly description = "Log out of calendar service"; + public readonly action = "calendarLogout"; public async run(context: ActionContext) { const provider = context.sessionContext.agentContext.calendarProvider; if (provider === undefined) { @@ -167,6 +169,7 @@ export class CalendarClientLogoutCommandHandler type: "html", content: ``, }); + await context.sessionContext.notifyReadinessChanged(); } } @@ -174,6 +177,7 @@ export class CalendarClientLogoutCommandHandler export class GoogleAuthCommandHandler implements CommandHandler { public readonly description = "Complete Google Calendar OAuth flow with authorization code"; + public readonly action = "calendarGoogleAuth"; public readonly parameters = { args: { code: { @@ -232,13 +236,17 @@ export class GoogleAuthCommandHandler implements CommandHandler { } } +const calendarLoginHandler = new CalendarClientLoginCommandHandler(); +const calendarLogoutHandler = new CalendarClientLogoutCommandHandler(); +const googleAuthHandler = new GoogleAuthCommandHandler(); + const handlers: CommandHandlerTable = { description: "Calendar login command", defaultSubCommand: "login", commands: { - login: new CalendarClientLoginCommandHandler(), - logout: new CalendarClientLogoutCommandHandler(), - "google-auth": new GoogleAuthCommandHandler(), + login: calendarLoginHandler, + logout: calendarLogoutHandler, + "google-auth": googleAuthHandler, }, }; @@ -551,6 +559,21 @@ export class CalendarActionHandlerV3 implements AppAgent { ), ); + switch (calendarAction.actionName) { + case "calendarLogin": + await calendarLoginHandler.run(context); + return undefined; + case "calendarLogout": + await calendarLogoutHandler.run(context); + return undefined; + case "calendarGoogleAuth": + await googleAuthHandler.run(context, { + args: { code: calendarAction.parameters.code }, + flags: undefined, + }); + return undefined; + } + if (!provider) { return createActionResultFromError( "Calendar provider not initialized. Please configure MSGRAPH_APP_CLIENTID or GOOGLE_CALENDAR_CLIENT_ID.", diff --git a/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts b/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts index e9a5605e20..e14023fc80 100644 --- a/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts +++ b/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts @@ -16,6 +16,9 @@ export type CalendarTimeRange = string; // "2pm to 3pm", "9am-10am", "1-2pm" - u export type CalendarEntities = CalendarDate | CalendarTime | CalendarTimeRange; export type CalendarActionV3 = + | CalendarLoginAction + | CalendarLogoutAction + | CalendarGoogleAuthAction | ScheduleEventAction | FindEventsAction | AddParticipantAction @@ -23,6 +26,31 @@ export type CalendarActionV3 = | FindThisWeeksEventsAction | RemoveEventAction; +// user: log in to my calendar +// agent: { "actionName": "calendarLogin" } +// Sign in to the configured calendar provider. +export type CalendarLoginAction = { + actionName: "calendarLogin"; +}; + +// user: log out of my calendar +// agent: { "actionName": "calendarLogout" } +// Sign out of the configured calendar provider. +export type CalendarLogoutAction = { + actionName: "calendarLogout"; +}; + +// user: complete Google Calendar authorization with code 4/abc123 +// agent: { "actionName": "calendarGoogleAuth", "parameters": { "code": "4/abc123" } } +// Complete Google Calendar authorization with the exact authorization code. +export type CalendarGoogleAuthAction = { + actionName: "calendarGoogleAuth"; + parameters: { + // The unmodified authorization code returned by Google. + code: string; + }; +}; + // Schedule a new event on the calendar // Examples: "schedule a meeting tomorrow at 2pm", "add dentist appointment on Friday at 3pm" export type ScheduleEventAction = { diff --git a/ts/packages/agents/calendar/src/calendarSchema.agr b/ts/packages/agents/calendar/src/calendarSchema.agr index 68f93767dd..686fe536e7 100644 --- a/ts/packages/agents/calendar/src/calendarSchema.agr +++ b/ts/packages/agents/calendar/src/calendarSchema.agr @@ -87,7 +87,19 @@ import { CalendarActionV3 } from "./calendarActionsSchemaV3.ts"; | | | - | ; + | + | + | + | ; + + = (log in | login | sign in) (to)? (my)? (calendar | google calendar | outlook calendar) + -> { actionName: "calendarLogin" }; + + = (log out | logout | sign out) (of)? (my)? (calendar | google calendar | outlook calendar) + -> { actionName: "calendarLogout" }; + + = (complete | finish) google calendar (authorization | authentication | oauth) (with)? (code)? $(code:wildcard) + -> { actionName: "calendarGoogleAuth", parameters: { code } }; = what's happening this week -> { actionName: "findThisWeeksEvents" diff --git a/ts/packages/agents/calendar/test/calendarAuth.spec.ts b/ts/packages/agents/calendar/test/calendarAuth.spec.ts new file mode 100644 index 0000000000..06799af7e1 --- /dev/null +++ b/ts/packages/agents/calendar/test/calendarAuth.spec.ts @@ -0,0 +1,175 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import * as fs from "node:fs"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; +import { + compileGrammarToNFA, + loadGrammarRulesNoThrow, + matchNFA, +} from "@typeagent/action-grammar"; +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; +import { instantiate } from "../src/calendarActionHandlerV3.js"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const grammarPath = path.resolve(here, "..", "..", "src", "calendarSchema.agr"); + +function makeMatcher() { + const errors: string[] = []; + const grammar = loadGrammarRulesNoThrow( + "calendarSchema.agr", + fs.readFileSync(grammarPath, "utf8"), + errors, + ); + if (grammar === undefined || errors.length > 0) { + throw new Error( + `Failed to parse calendar grammar: ${errors.join("; ")}`, + ); + } + const nfa = compileGrammarToNFA(grammar, "calendar"); + return (input: string) => { + const result = matchNFA(nfa, input.toLowerCase().split(/\s+/), false); + return result.matched ? (result.actionValue as any) : undefined; + }; +} + +describe("calendar auth actions", () => { + it("matches anchored login, logout, and Google authorization requests", () => { + const match = makeMatcher(); + + expect(match("log in to my calendar")).toEqual({ + actionName: "calendarLogin", + }); + expect(match("sign out of google calendar")).toEqual({ + actionName: "calendarLogout", + }); + expect( + match("complete google calendar authorization with code 4/abc123"), + ).toEqual({ + actionName: "calendarGoogleAuth", + parameters: { code: "4/abc123" }, + }); + }); + + it("links all auth commands to their actions", async () => { + const descriptors = (await instantiate().getCommands!({} as any)) as + | CommandDescriptor + | CommandDescriptorTable; + expect("commands" in descriptors).toBe(true); + if (!("commands" in descriptors)) return; + + expect((descriptors.commands.login as CommandDescriptor).action).toBe( + "calendarLogin", + ); + expect((descriptors.commands.logout as CommandDescriptor).action).toBe( + "calendarLogout", + ); + expect( + (descriptors.commands["google-auth"] as CommandDescriptor).action, + ).toBe("calendarGoogleAuth"); + }); + + it("re-emits identity when login is already authenticated", async () => { + const agent = instantiate(); + const displays: unknown[] = []; + const context = { + sessionContext: { + agentContext: { + calendarProvider: { + isAuthenticated: () => true, + getUser: async () => ({ + displayName: "Ada", + email: "ada@example.com", + }), + }, + providerType: "microsoft", + }, + }, + actionIO: { + setDisplay: (value: unknown) => displays.push(value), + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await agent.executeAction!( + { schemaName: "calendar", actionName: "calendarLogin" } as any, + context, + ); + + expect(JSON.stringify(displays)).toMatch(/ada@example\.com/); + expect(JSON.stringify(displays)).toMatch(/typeagent-user-signed-in/); + }); + + it("logs out and refreshes cached readiness", async () => { + const agent = instantiate(); + let logoutCalls = 0; + let readinessCalls = 0; + const displays: unknown[] = []; + const context = { + sessionContext: { + agentContext: { + calendarProvider: { + logout: () => { + logoutCalls++; + return true; + }, + }, + }, + notifyReadinessChanged: async () => { + readinessCalls++; + }, + }, + actionIO: { + setDisplay: (value: unknown) => displays.push(value), + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await agent.executeAction!( + { schemaName: "calendar", actionName: "calendarLogout" } as any, + context, + ); + + expect(logoutCalls).toBe(1); + expect(readinessCalls).toBe(1); + expect(JSON.stringify(displays)).toMatch(/typeagent-user-signed-out/); + }); + + it("forwards the Google authorization code unchanged", async () => { + const agent = instantiate(); + const codes: string[] = []; + const displays: unknown[] = []; + const context = { + sessionContext: { + agentContext: { + providerType: "google", + calendarProvider: { + completeAuth: async (code: string) => { + codes.push(code); + return false; + }, + }, + }, + }, + actionIO: { + setDisplay: (value: unknown) => displays.push(value), + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await agent.executeAction!( + { + schemaName: "calendar", + actionName: "calendarGoogleAuth", + parameters: { code: "4/AbC-123_exact" }, + } as any, + context, + ); + + expect(codes).toEqual(["4/AbC-123_exact"]); + }); +}); diff --git a/ts/packages/agents/email/src/emailActionHandler.ts b/ts/packages/agents/email/src/emailActionHandler.ts index 7184b8e893..5252f82cee 100644 --- a/ts/packages/agents/email/src/emailActionHandler.ts +++ b/ts/packages/agents/email/src/emailActionHandler.ts @@ -117,6 +117,7 @@ async function resolveRecipients( class EmailLoginCommandHandler implements CommandHandlerNoParams { public readonly description = "Log into email service"; + public readonly action = "emailLogin"; public async run(context: ActionContext) { const provider = context.sessionContext.agentContext.emailProvider; const providerType = context.sessionContext.agentContext.providerType; @@ -200,6 +201,7 @@ class EmailLoginCommandHandler implements CommandHandlerNoParams { class EmailLogoutCommandHandler implements CommandHandlerNoParams { public readonly description = "Log out of email service"; + public readonly action = "emailLogout"; public async run(context: ActionContext) { const provider = context.sessionContext.agentContext.emailProvider; if (provider === undefined) { @@ -218,12 +220,14 @@ class EmailLogoutCommandHandler implements CommandHandlerNoParams { type: "html", content: ``, }); + await context.sessionContext.notifyReadinessChanged(); } } class GoogleAuthCommandHandler implements CommandHandler { public readonly description = "Complete Google Gmail OAuth flow with authorization code"; + public readonly action = "emailGoogleAuth"; public readonly parameters = { args: { code: { @@ -299,14 +303,19 @@ class EmailIndexCommandHandler implements CommandHandlerNoParams { } } +const emailLoginHandler = new EmailLoginCommandHandler(); +const emailLogoutHandler = new EmailLogoutCommandHandler(); +const googleAuthHandler = new GoogleAuthCommandHandler(); +const emailIndexHandler = new EmailIndexCommandHandler(); + const handlers: CommandHandlerTable = { description: "Email commands", defaultSubCommand: "login", commands: { - login: new EmailLoginCommandHandler(), - logout: new EmailLogoutCommandHandler(), - "google-auth": new GoogleAuthCommandHandler(), - index: new EmailIndexCommandHandler(), + login: emailLoginHandler, + logout: emailLogoutHandler, + "google-auth": googleAuthHandler, + index: emailIndexHandler, }, }; @@ -521,9 +530,22 @@ async function executeEmailAction( action: TypeAgentAction, context: ActionContext, ) { - if (action.actionName === "indexInbox") { - runEmailIndex(context); - return; + switch (action.actionName) { + case "emailLogin": + await emailLoginHandler.run(context); + return undefined; + case "emailLogout": + await emailLogoutHandler.run(context); + return undefined; + case "emailGoogleAuth": + await googleAuthHandler.run(context, { + args: { code: action.parameters.code }, + flags: undefined, + }); + return undefined; + case "indexInbox": + runEmailIndex(context); + return undefined; } const { emailProvider } = context.sessionContext.agentContext; diff --git a/ts/packages/agents/email/src/emailActionsSchema.ts b/ts/packages/agents/email/src/emailActionsSchema.ts index 3618898354..99586e9867 100644 --- a/ts/packages/agents/email/src/emailActionsSchema.ts +++ b/ts/packages/agents/email/src/emailActionsSchema.ts @@ -2,12 +2,40 @@ // Licensed under the MIT License. export type EmailAction = + | EmailLoginAction + | EmailLogoutAction + | EmailGoogleAuthAction | SendEmailAction | ReplyEmailAction | ForwardEmailAction | FindEmailAction | IndexInboxAction; +// user: log in to email +// agent: { "actionName": "emailLogin" } +// Sign in to the configured email provider. +export type EmailLoginAction = { + actionName: "emailLogin"; +}; + +// user: log out of email +// agent: { "actionName": "emailLogout" } +// Sign out of the configured email provider. +export type EmailLogoutAction = { + actionName: "emailLogout"; +}; + +// user: complete Gmail authorization with code 4/abc123 +// agent: { "actionName": "emailGoogleAuth", "parameters": { "code": "4/abc123" } } +// Complete Google Gmail authorization with the exact authorization code. +export type EmailGoogleAuthAction = { + actionName: "emailGoogleAuth"; + parameters: { + // The unmodified authorization code returned by Google. + code: string; + }; +}; + // user: index my inbox // agent: { "actionName": "indexInbox" } // Build the local keyword index from inbox email messages. diff --git a/ts/packages/agents/email/src/emailSchema.agr b/ts/packages/agents/email/src/emailSchema.agr index 149c878122..3eea3918d0 100644 --- a/ts/packages/agents/email/src/emailSchema.agr +++ b/ts/packages/agents/email/src/emailSchema.agr @@ -2,14 +2,23 @@ // Licensed under the MIT License. // Email Management Grammar -// Covers: sendEmail, replyEmail, forwardEmail, findEmail, indexInbox actions +// Covers email management, authentication, and indexing actions import { EmailAction } from "./emailActionsSchema.ts"; - : EmailAction = | | | | ; + : EmailAction = | | | | | | | ; // ===== Main Action Rules ===== + = (log in | login | sign in) (to)? (my)? (email | gmail | outlook) + -> { actionName: "emailLogin" }; + + = (log out | logout | sign out) (of)? (my)? (email | gmail | outlook) + -> { actionName: "emailLogout" }; + + = (complete | finish) (google | gmail) (email)? (authorization | authentication | oauth) (with)? (code)? $(code:wildcard) + -> { actionName: "emailGoogleAuth", parameters: { code } }; + = $(to:string) $(subject:string) $(body:string) $(cc:)? $(bcc:)? $(attachments:)? -> { actionName: "sendEmail", parameters: { to: to, subject: subject, body: body, cc: cc, bcc: bcc, attachments: attachments } } | $(to:string) $(body:string) $(subject:string) $(cc:)? $(bcc:)? $(attachments:)? -> { actionName: "sendEmail", parameters: { to: to, subject: subject, body: body, cc: cc, bcc: bcc, attachments: attachments } } | $(to:string) $(subject:string) $(body:string) $(cc:)? $(bcc:)? $(attachments:)? -> { actionName: "sendEmail", parameters: { to: to, subject: subject, body: body, cc: cc, bcc: bcc, attachments: attachments } } diff --git a/ts/packages/agents/email/test/emailIndex.spec.ts b/ts/packages/agents/email/test/emailIndex.spec.ts index 57fc628a66..0ab2dcd149 100644 --- a/ts/packages/agents/email/test/emailIndex.spec.ts +++ b/ts/packages/agents/email/test/emailIndex.spec.ts @@ -48,11 +48,15 @@ function makeContext(authenticated: boolean, indexingInProgress = false) { }, indexingInProgress, }; + const sessionContext = { + agentContext, + notifyReadinessChanged: async () => {}, + }; return { agentContext, displays, context: { - sessionContext: { agentContext }, + sessionContext, actionIO: { setDisplay: (content: unknown) => displays.push(content), appendDisplay: (content: unknown) => displays.push(content), @@ -111,3 +115,141 @@ describe("indexInbox", () => { assert.deepEqual(started, []); }); }); + +describe("email auth actions", () => { + it("matches anchored login, logout, and Google authorization requests", () => { + const match = makeMatcher(); + + assert.deepEqual(match("log in to email"), { + actionName: "emailLogin", + }); + assert.deepEqual(match("sign out of gmail"), { + actionName: "emailLogout", + }); + assert.deepEqual( + match("complete gmail authorization with code 4/abc123"), + { + actionName: "emailGoogleAuth", + parameters: { code: "4/abc123" }, + }, + ); + }); + + it("links all auth commands to their actions", async () => { + const descriptors = (await instantiate().getCommands!({} as any)) as + | CommandDescriptor + | CommandDescriptorTable; + assert.ok("commands" in descriptors); + assert.equal( + (descriptors.commands.login as CommandDescriptor).action, + "emailLogin", + ); + assert.equal( + (descriptors.commands.logout as CommandDescriptor).action, + "emailLogout", + ); + assert.equal( + (descriptors.commands["google-auth"] as CommandDescriptor).action, + "emailGoogleAuth", + ); + }); + + it("re-emits identity when login is already authenticated", async () => { + const agent = instantiate(); + const displays: unknown[] = []; + const agentContext = { + emailProvider: { + isAuthenticated: () => true, + getUser: async () => ({ + displayName: "Ada", + email: "ada@example.com", + }), + }, + providerType: "microsoft", + }; + const context = { + sessionContext: { agentContext }, + actionIO: { + setDisplay: (value: unknown) => displays.push(value), + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await agent.executeAction!( + { schemaName: "email", actionName: "emailLogin" } as any, + context, + ); + + assert.match(JSON.stringify(displays), /ada@example\.com/); + assert.match(JSON.stringify(displays), /typeagent-user-signed-in/); + }); + + it("logs out and refreshes cached readiness", async () => { + const agent = instantiate(); + let logoutCalls = 0; + let readinessCalls = 0; + const displays: unknown[] = []; + const context = { + sessionContext: { + agentContext: { + emailProvider: { + logout: () => { + logoutCalls++; + return true; + }, + }, + }, + notifyReadinessChanged: async () => { + readinessCalls++; + }, + }, + actionIO: { + setDisplay: (value: unknown) => displays.push(value), + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await agent.executeAction!( + { schemaName: "email", actionName: "emailLogout" } as any, + context, + ); + + assert.equal(logoutCalls, 1); + assert.equal(readinessCalls, 1); + assert.match(JSON.stringify(displays), /typeagent-user-signed-out/); + }); + + it("forwards the Google authorization code unchanged", async () => { + const agent = instantiate(); + const codes: string[] = []; + const displays: unknown[] = []; + const context = { + sessionContext: { + agentContext: { + providerType: "google", + emailProvider: { + completeAuth: async (code: string) => { + codes.push(code); + return false; + }, + }, + }, + }, + actionIO: { + setDisplay: (value: unknown) => displays.push(value), + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await agent.executeAction!( + { + schemaName: "email", + actionName: "emailGoogleAuth", + parameters: { code: "4/AbC-123_exact" }, + } as any, + context, + ); + + assert.deepEqual(codes, ["4/AbC-123_exact"]); + }); +}); diff --git a/ts/packages/agents/player/package.json b/ts/packages/agents/player/package.json index 2a04b59b36..a329a8334e 100644 --- a/ts/packages/agents/player/package.json +++ b/ts/packages/agents/player/package.json @@ -46,6 +46,7 @@ "typechat": "^0.1.1" }, "devDependencies": { + "@typeagent/action-grammar": "workspace:*", "@typeagent/action-grammar-compiler": "workspace:*", "@typeagent/action-schema-compiler": "workspace:*", "@types/debug": "^4.1.12", diff --git a/ts/packages/agents/player/src/agent/playerCommands.ts b/ts/packages/agents/player/src/agent/playerCommands.ts index e5d3813b5e..f7d73c10a9 100644 --- a/ts/packages/agents/player/src/agent/playerCommands.ts +++ b/ts/packages/agents/player/src/agent/playerCommands.ts @@ -12,15 +12,11 @@ import { CommandHandler, } from "@typeagent/agent-sdk/helpers/command"; import { - disableSpotify, - enableSpotify, PlayerActionContext, + runLoadSpotifyUserData, + runSpotifyLogin, + runSpotifyLogout, } from "./playerHandlers.js"; -import { loadHistoryFile } from "../client.js"; -import { - displaySuccess, - displayWarn, -} from "@typeagent/agent-sdk/helpers/display"; const loadHandlerParameters = { args: { @@ -31,29 +27,13 @@ const loadHandlerParameters = { } as const; const loadHandler: CommandHandler = { description: "Load spotify user data", + action: "loadSpotifyUserData", parameters: loadHandlerParameters, run: async ( context: ActionContext, params: ParsedCommandParams, ) => { - const sessionContext = context.sessionContext; - const agentContext = sessionContext.agentContext; - if (agentContext.spotify === undefined) { - throw new Error("Spotify integration is not enabled."); - } - - if (sessionContext.instanceStorage === undefined) { - throw new Error("User data storage disabled."); - } - context.actionIO.setDisplay("Loading Spotify user data..."); - - await loadHistoryFile( - sessionContext.instanceStorage, - params.args.file, - agentContext.spotify, - ); - - context.actionIO.setDisplay("Spotify user data loaded."); + return runLoadSpotifyUserData(context, params.args.file); }, }; const handlers: CommandHandlerTable = { @@ -65,42 +45,20 @@ const handlers: CommandHandlerTable = { load: loadHandler, login: { description: "Login to Spotify", + action: "spotifyLogin", run: async ( context: ActionContext, ) => { - const sessionContext = context.sessionContext; - const agentContext = sessionContext.agentContext; - const clientContext = agentContext.spotify; - if (clientContext !== undefined) { - const user = - clientContext.service.retrieveUser().username; - displayWarn( - `Already logged in to Spotify as ${user}`, - context, - ); - return; - } - const user = await enableSpotify(sessionContext); - displaySuccess( - `Logged in to Spotify as ${user}`, - context, - ); + return runSpotifyLogin(context); }, }, logout: { description: "Logout from Spotify", + action: "spotifyLogout", run: async ( context: ActionContext, ) => { - const sessionContext = context.sessionContext; - const agentContext = sessionContext.agentContext; - if (agentContext.spotify === undefined) { - displayWarn("Not logged in to Spotify.", context); - return; - } - - disableSpotify(sessionContext, true); - displaySuccess("Logged out from Spotify.", context); + return runSpotifyLogout(context); }, }, }, diff --git a/ts/packages/agents/player/src/agent/playerHandlers.ts b/ts/packages/agents/player/src/agent/playerHandlers.ts index 6cec5dc460..8911e6c117 100644 --- a/ts/packages/agents/player/src/agent/playerHandlers.ts +++ b/ts/packages/agents/player/src/agent/playerHandlers.ts @@ -5,6 +5,7 @@ import { IClientContext, getClientContext, handleCall, + loadHistoryFile, searchForPlaylists, } from "../client.js"; import chalk from "chalk"; @@ -21,6 +22,10 @@ import { ResolveEntityResult, } from "@typeagent/agent-sdk"; import { createActionResultFromError } from "@typeagent/agent-sdk/helpers/action"; +import { + displaySuccess, + displayWarn, +} from "@typeagent/agent-sdk/helpers/display"; import { searchTracks } from "../client.js"; import { htmlStatus } from "../playback.js"; import { getPlayerCommandInterface } from "./playerCommands.js"; @@ -103,6 +108,15 @@ async function executePlayerAction( action: TypeAgentAction, context: ActionContext, ) { + switch (action.actionName) { + case "spotifyLogin": + return runSpotifyLogin(context); + case "spotifyLogout": + return runSpotifyLogout(context); + case "loadSpotifyUserData": + return runLoadSpotifyUserData(context, action.parameters.file); + } + const clientContext = context.sessionContext.agentContext.spotify; if (clientContext) { // Per-request accumulator for any LLM tokens consumed while executing @@ -134,6 +148,61 @@ async function executePlayerAction( ); } +export async function runSpotifyLogin( + context: ActionContext, + login: ( + context: SessionContext, + ) => Promise = enableSpotify, +): Promise { + const sessionContext = context.sessionContext; + const clientContext = sessionContext.agentContext.spotify; + if (clientContext !== undefined) { + const user = clientContext.service.retrieveUser().username; + displayWarn(`Already logged in to Spotify as ${user}`, context); + return undefined; + } + const user = await login(sessionContext); + displaySuccess(`Logged in to Spotify as ${user}`, context); + return undefined; +} + +export async function runSpotifyLogout( + context: ActionContext, + logout: ( + context: SessionContext, + clearToken: boolean, + ) => Promise = disableSpotify, +): Promise { + const sessionContext = context.sessionContext; + if (sessionContext.agentContext.spotify === undefined) { + displayWarn("Not logged in to Spotify.", context); + return undefined; + } + await logout(sessionContext, true); + displaySuccess("Logged out from Spotify.", context); + return undefined; +} + +export async function runLoadSpotifyUserData( + context: ActionContext, + file: string, + load: typeof loadHistoryFile = loadHistoryFile, +): Promise { + const sessionContext = context.sessionContext; + const clientContext = sessionContext.agentContext.spotify; + if (clientContext === undefined) { + throw new Error("Spotify integration is not enabled."); + } + if (sessionContext.instanceStorage === undefined) { + throw new Error("User data storage disabled."); + } + + context.actionIO.setDisplay("Loading Spotify user data..."); + await load(sessionContext.instanceStorage, file, clientContext); + context.actionIO.setDisplay("Spotify user data loaded."); + return undefined; +} + async function updatePlayerContext( enable: boolean, context: SessionContext, diff --git a/ts/packages/agents/player/src/agent/playerSchema.agr b/ts/packages/agents/player/src/agent/playerSchema.agr index a2537c936d..9cbe179169 100644 --- a/ts/packages/agents/player/src/agent/playerSchema.agr +++ b/ts/packages/agents/player/src/agent/playerSchema.agr @@ -8,7 +8,10 @@ import { PlayerActions } from "./playerSchema.ts"; | | | - | ; + | + | + | + | ; = pause -> { actionName: "pause" } | pause music -> { actionName: "pause" } | pause the music -> { actionName: "pause" }; @@ -18,6 +21,12 @@ import { PlayerActions } from "./playerSchema.ts"; = next -> { actionName: "next" } | skip -> { actionName: "next" } | skip -> { actionName: "next" }; + = (log in | login | sign in) (to)? spotify + -> { actionName: "spotifyLogin" }; + = (log out | logout | sign out) (of)? spotify + -> { actionName: "spotifyLogout" }; + = (load | import) (my)? spotify (user)? data (from)? $(file:wildcard) + -> { actionName: "loadSpotifyUserData", parameters: { file } }; = | ; = play (the)? $(n:) ()? -> { diff --git a/ts/packages/agents/player/src/agent/playerSchema.ts b/ts/packages/agents/player/src/agent/playerSchema.ts index f8e77cdd06..b5380172b3 100644 --- a/ts/packages/agents/player/src/agent/playerSchema.ts +++ b/ts/packages/agents/player/src/agent/playerSchema.ts @@ -2,6 +2,9 @@ // Licensed under the MIT License. export type PlayerActions = + | SpotifyLoginAction + | SpotifyLogoutAction + | LoadSpotifyUserDataAction | PlayMusicAction | FindMusicAction | PlayFromCurrentTrackListAction @@ -34,6 +37,31 @@ export type PlayerActions = export type PlayerEntities = MusicDevice; export type MusicDevice = string; +// user: log in to Spotify +// agent: { "actionName": "spotifyLogin" } +// Sign in to the configured Spotify account. +export interface SpotifyLoginAction { + actionName: "spotifyLogin"; +} + +// user: log out of Spotify +// agent: { "actionName": "spotifyLogout" } +// Sign out of Spotify and clear the saved refresh token. +export interface SpotifyLogoutAction { + actionName: "spotifyLogout"; +} + +// user: load my Spotify user data from streaming-history.json +// agent: { "actionName": "loadSpotifyUserData", "parameters": { "file": "streaming-history.json" } } +// Import Spotify listening-history data from a stored JSON file. +export interface LoadSpotifyUserDataAction { + actionName: "loadSpotifyUserData"; + parameters: { + // Path of the Spotify history JSON file in instance storage. + file: string; + }; +} + // Specification for a song by title and optional artist/album export interface SongSpecification { trackName: string; diff --git a/ts/packages/agents/player/test/playerManagement.spec.ts b/ts/packages/agents/player/test/playerManagement.spec.ts new file mode 100644 index 0000000000..eb6c333f60 --- /dev/null +++ b/ts/packages/agents/player/test/playerManagement.spec.ts @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import * as fs from "node:fs"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; +import { + compileGrammarToNFA, + loadGrammarRulesNoThrow, + matchNFA, +} from "@typeagent/action-grammar"; +import type { + CommandDescriptor, + CommandDescriptorTable, +} from "@typeagent/agent-sdk"; +import { getPlayerCommandInterface } from "../src/agent/playerCommands.js"; +import { + runLoadSpotifyUserData, + runSpotifyLogin, + runSpotifyLogout, +} from "../src/agent/playerHandlers.js"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const grammarPath = path.resolve( + here, + "..", + "..", + "src", + "agent", + "playerSchema.agr", +); + +function makeMatcher() { + const errors: string[] = []; + const grammar = loadGrammarRulesNoThrow( + "playerSchema.agr", + fs.readFileSync(grammarPath, "utf8"), + errors, + ); + if (grammar === undefined || errors.length > 0) { + throw new Error(`Failed to parse player grammar: ${errors.join("; ")}`); + } + const nfa = compileGrammarToNFA(grammar, "player"); + return (input: string) => { + const result = matchNFA(nfa, input.toLowerCase().split(/\s+/), false); + return result.matched ? (result.actionValue as any) : undefined; + }; +} + +function makeContext(spotify?: object, instanceStorage?: object) { + const displays: unknown[] = []; + const sessionContext = { + agentContext: { spotify }, + instanceStorage, + }; + return { + sessionContext, + displays, + context: { + sessionContext, + actionIO: { + setDisplay: (value: unknown) => displays.push(value), + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any, + }; +} + +describe("player Spotify management actions", () => { + it("matches login, logout, and history-load requests", () => { + const match = makeMatcher(); + + expect(match("log in to spotify")).toEqual({ + actionName: "spotifyLogin", + }); + expect(match("sign out of spotify")).toEqual({ + actionName: "spotifyLogout", + }); + expect(match("load my spotify user data history.json")).toEqual({ + actionName: "loadSpotifyUserData", + parameters: { file: "history.json" }, + }); + }); + + it("links all nested commands to their actions", async () => { + const root = (await getPlayerCommandInterface().getCommands( + {} as any, + )) as CommandDescriptorTable; + const spotify = root.commands.spotify as CommandDescriptorTable; + + expect((spotify.commands.load as CommandDescriptor).action).toBe( + "loadSpotifyUserData", + ); + expect((spotify.commands.login as CommandDescriptor).action).toBe( + "spotifyLogin", + ); + expect((spotify.commands.logout as CommandDescriptor).action).toBe( + "spotifyLogout", + ); + }); + + it("logs in only when no Spotify context exists", async () => { + const { context, sessionContext } = makeContext(); + const calls: unknown[] = []; + + await runSpotifyLogin(context, async (value) => { + calls.push(value); + return "Ada"; + }); + + expect(calls).toEqual([sessionContext]); + }); + + it("does not log in twice", async () => { + const spotify = { + service: { retrieveUser: () => ({ username: "Ada" }) }, + }; + const { context } = makeContext(spotify); + const calls: unknown[] = []; + + await runSpotifyLogin(context, async (value) => { + calls.push(value); + return "ignored"; + }); + + expect(calls).toEqual([]); + }); + + it("logs out with refresh-token clearing", async () => { + const spotify = {}; + const { context, sessionContext } = makeContext(spotify); + const calls: unknown[][] = []; + + await runSpotifyLogout(context, async (...args) => { + calls.push(args); + }); + + expect(calls).toEqual([[sessionContext, true]]); + }); + + it("passes storage, file, and client context to history loading", async () => { + const spotify = {}; + const storage = {}; + const { context } = makeContext(spotify, storage); + const calls: unknown[][] = []; + + await runLoadSpotifyUserData( + context, + "history.json", + async (...args: any[]) => { + calls.push(args); + }, + ); + + expect(calls).toEqual([[storage, "history.json", spotify]]); + }); +}); diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts new file mode 100644 index 0000000000..5569053cfc --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { CommandHandlerContext } from "../commandHandlerContext.js"; +import { DispatcherDiagnosticsActions } from "./schema/diagnosticsActionSchema.js"; + +type DiagnosticsCommandHandler = { + run( + context: ActionContext, + params: any, + ): Promise; +}; + +export type DiagnosticsCommandHandlers = { + request: DiagnosticsCommandHandler; + match: DiagnosticsCommandHandler; + translate: DiagnosticsCommandHandler; + reason: DiagnosticsCommandHandler; + explain: DiagnosticsCommandHandler; +}; + +export async function executeDispatcherDiagnosticsAction( + action: TypeAgentAction, + context: ActionContext, + handlers: DiagnosticsCommandHandlers, +): Promise { + switch (action.actionName) { + case "dispatchRequest": + await handlers.request.run(context, { + args: { request: action.parameters?.request }, + flags: undefined, + }); + return undefined; + case "matchDispatcherRequest": + await handlers.match.run(context, { + args: { request: action.parameters.request }, + flags: undefined, + }); + return undefined; + case "translateDispatcherRequest": + await handlers.translate.run(context, { + args: { request: action.parameters.request }, + flags: { history: action.parameters.useHistory ?? false }, + }); + return undefined; + case "reasonAboutRequest": + return ( + (await handlers.reason.run(context, { + args: { request: action.parameters.request }, + flags: { engine: action.parameters.engine ?? "" }, + })) ?? undefined + ); + case "explainDispatcherRequest": + await handlers.explain.run(context, { + args: { requestAction: action.parameters.requestAction }, + flags: { + repeat: action.parameters.repeat ?? 1, + filterValueInRequest: + action.parameters.filterValueInRequest ?? false, + filterReference: action.parameters.filterReference ?? false, + concurrency: action.parameters.concurrency ?? 5, + }, + }); + return undefined; + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts index 8e453100ab..6975173146 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts @@ -54,22 +54,27 @@ import { executeReasoning as executeCopilotReasoning, } from "../../reasoning/copilot.js"; import { ReasonCommandHandler } from "./handlers/reasonCommandHandler.js"; +import { DispatcherDiagnosticsActions } from "./schema/diagnosticsActionSchema.js"; +import { executeDispatcherDiagnosticsAction } from "./diagnosticsActionHandler.js"; import registerDebug from "debug"; const debugConversationAnswer = registerDebug( "typeagent:dispatcher:conversationAnswer", ); +const reasonCommandHandler = new ReasonCommandHandler(); +const diagnosticsCommandHandlers = { + request: new RequestCommandHandler(), + match: new MatchCommandHandler(), + translate: new TranslateCommandHandler(), + reason: reasonCommandHandler, + reasoning: reasonCommandHandler, + explain: new ExplainCommandHandler(), +}; + const dispatcherHandlers: CommandHandlerTable = { description: "Type Agent Dispatcher Commands", - commands: { - request: new RequestCommandHandler(), - match: new MatchCommandHandler(), - translate: new TranslateCommandHandler(), - reason: new ReasonCommandHandler(), - reasoning: new ReasonCommandHandler(), - explain: new ExplainCommandHandler(), - }, + commands: diagnosticsCommandHandlers, }; /** @@ -111,10 +116,17 @@ async function executeDispatcherAction( | ActivityActions | ClarifyEntityAction | ReasoningAction + | DispatcherDiagnosticsActions >, context: ActionContext, ) { switch (action.schemaName) { + case "dispatcher.diagnostics": + return executeDispatcherDiagnosticsAction( + action as TypeAgentAction, + context, + diagnosticsCommandHandlers, + ); case "dispatcher.clarify": switch (action.actionName) { case "clarifyMultiplePossibleActionName": @@ -549,6 +561,17 @@ export const dispatcherManifest: AppAgentManifest = { cached: false, }, subActionManifests: { + diagnostics: { + schema: { + description: + "Explicit TypeAgent dispatcher diagnostics for submitting, matching, translating, reasoning about, and explaining nested requests.", + schemaFile: + "./src/context/dispatcher/schema/diagnosticsActionSchema.ts", + schemaType: "DispatcherDiagnosticsActions", + injected: true, + cached: false, + }, + }, clarify: { schema: { description: "Action that helps you clarify your request.", diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/explainCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/explainCommandHandler.ts index 1e2a2a5465..e1d338d111 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/explainCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/explainCommandHandler.ts @@ -13,6 +13,10 @@ import chalk from "chalk"; export class ExplainCommandHandler implements CommandHandler { public readonly description = "Explain a translated request with action"; + public readonly action = { + schema: "dispatcher.diagnostics", + actionName: "explainDispatcherRequest", + }; public readonly parameters = { args: { requestAction: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts index c91a0bf718..ea5cf01657 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts @@ -20,6 +20,10 @@ import { requestCompletion } from "../../../translation/requestCompletion.js"; export class MatchCommandHandler implements CommandHandler { public readonly description = "Match a request"; + public readonly action = { + schema: "dispatcher.diagnostics", + actionName: "matchDispatcherRequest", + }; public readonly parameters = { args: { request: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts index 63f143e671..29e620df20 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts @@ -16,6 +16,10 @@ const validEngines = ["claude", "copilot", "none"]; export class ReasonCommandHandler implements CommandHandler { public readonly description = "Reason about a request"; + public readonly action = { + schema: "dispatcher.diagnostics", + actionName: "reasonAboutRequest", + }; public readonly parameters = { flags: { engine: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/requestCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/requestCommandHandler.ts index fddbc17417..2f577e2c2d 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/requestCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/requestCommandHandler.ts @@ -821,6 +821,10 @@ async function requestExplain( export class RequestCommandHandler implements CommandHandler { public readonly description = "Translate and explain a request"; + public readonly action = { + schema: "dispatcher.diagnostics", + actionName: "dispatchRequest", + }; public readonly parameters = { args: { request: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/translateCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/translateCommandHandler.ts index 84b1c485e7..4a6c22e60a 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/translateCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/handlers/translateCommandHandler.ts @@ -19,6 +19,10 @@ import { createHistoryContext } from "../../../translation/interpretRequest.js"; export class TranslateCommandHandler implements CommandHandler { public readonly description = "Translate a request"; + public readonly action = { + schema: "dispatcher.diagnostics", + actionName: "translateDispatcherRequest", + }; public readonly parameters = { args: { request: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/schema/diagnosticsActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/schema/diagnosticsActionSchema.ts new file mode 100644 index 0000000000..377192e7bc --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/schema/diagnosticsActionSchema.ts @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type DispatcherDiagnosticsActions = + | DispatchRequestAction + | MatchDispatcherRequestAction + | TranslateDispatcherRequestAction + | ReasonAboutRequestAction + | ExplainDispatcherRequestAction; + +// user: ask the TypeAgent dispatcher to handle "play some jazz" +// agent: { "actionName": "dispatchRequest", "parameters": { "request": "play some jazz" } } +// Submit a nested request through the normal TypeAgent dispatcher pipeline. +export type DispatchRequestAction = { + actionName: "dispatchRequest"; + parameters?: { + // The nested request to dispatch; defaults to an empty request. + request?: string; + }; +}; + +// user: show how the TypeAgent dispatcher grammar matches "play some jazz" +// agent: { "actionName": "matchDispatcherRequest", "parameters": { "request": "play some jazz" } } +// Match a request without executing its actions. +export type MatchDispatcherRequestAction = { + actionName: "matchDispatcherRequest"; + parameters: { + // The request to match. + request: string; + }; +}; + +// user: translate "play some jazz" with TypeAgent dispatcher history +// agent: { "actionName": "translateDispatcherRequest", "parameters": { "request": "play some jazz", "useHistory": true } } +// Translate a request into actions without executing them. +export type TranslateDispatcherRequestAction = { + actionName: "translateDispatcherRequest"; + parameters: { + // The request to translate. + request: string; + // Whether translation should include conversation history; defaults to false. + useHistory?: boolean; + }; +}; + +// user: use the Copilot reasoning engine on "plan my afternoon" +// agent: { "actionName": "reasonAboutRequest", "parameters": { "request": "plan my afternoon", "engine": "copilot" } } +// Run a request through a selected TypeAgent reasoning engine. +export type ReasonAboutRequestAction = { + actionName: "reasonAboutRequest"; + parameters: { + // The request to reason about. + request: string; + // Reasoning engine override; defaults to the configured engine. + engine?: "claude" | "copilot" | "none"; + }; +}; + +// user: explain the TypeAgent translation "play jazz => player.playMusic" +// agent: { "actionName": "explainDispatcherRequest", "parameters": { "requestAction": "play jazz => player.playMusic" } } +// Explain a serialized TypeAgent request/action translation. +export type ExplainDispatcherRequestAction = { + actionName: "explainDispatcherRequest"; + parameters: { + // The serialized request/action translation to explain. + requestAction: string; + // Number of explanation runs; defaults to 1. + repeat?: number; + // Whether to filter values copied from the request; defaults to false. + filterValueInRequest?: boolean; + // Whether to filter reference words; defaults to false. + filterReference?: boolean; + // Maximum concurrent explanation runs; defaults to 5. + concurrency?: number; + }; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts index 6857153344..abfb682ac4 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts @@ -33,6 +33,9 @@ export async function executeConversationAction( let resultEntity: { name: string; type: string[] } | undefined; let command: string; switch (action.actionName) { + case "showConversationHelp": + command = "@conversation help"; + break; case "newConversation": { // Grammar matches that emit `parameters: {}` are normalized away // by the grammar engine, so `action.parameters` may be missing on diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/describeActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/describeActionHandler.ts index 15df7d92fd..6e0d00a85e 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/describeActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/describeActionHandler.ts @@ -26,6 +26,25 @@ export async function executeDescribeAction( let markdown: string; let historyText: string; switch (nlAction.actionName) { + case "describeAgentOrAction": { + const { name, targetActionName, all } = nlAction.parameters; + markdown = + targetActionName !== undefined + ? await describeAction( + systemContext, + targetActionName, + name, + ) + : await describeAgentOrAction( + systemContext, + name, + all ?? false, + ); + historyText = targetActionName + ? `Described the "${targetActionName}" action from "${name}".` + : `Described "${name}".`; + break; + } case "describeAgent": { const { agentName, all } = nlAction.parameters; markdown = await describeAgentOrAction( diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/conversationCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/conversationCommandHandlers.ts index d5601b6d78..036241a611 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/conversationCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/conversationCommandHandlers.ts @@ -246,6 +246,7 @@ class ConversationFindCommandHandler implements CommandHandler { class ConversationHelpCommandHandler implements CommandHandlerNoParams { public readonly description = "Show conversation command help"; + public readonly action = "showConversationHelp"; public async run(context: ActionContext) { dispatchManageConversation(context, { subcommand: "help" }); } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/describeCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/describeCommandHandlers.ts index 80e9b16e85..2a86bfe43a 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/describeCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/describeCommandHandlers.ts @@ -20,6 +20,10 @@ import { export class DescribeCommandHandler implements CommandHandler { public readonly description = "Describe what an agent or action can do (installed-but-disabled agents included)"; + public readonly action = { + schema: "system.describe", + actionName: "describeAgentOrAction", + }; public readonly parameters = { args: { name: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts index b329056ba8..362b23a4f6 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts @@ -7,7 +7,6 @@ import { CommandHandlerTable, } from "@typeagent/agent-sdk/helpers/command"; import { - displayResult, displayStatus, displayWarn, } from "@typeagent/agent-sdk/helpers/display"; @@ -32,10 +31,7 @@ import * as fs from "node:fs"; import * as path from "node:path"; import { getGrammarContent } from "../../../translation/actionConfig.js"; import { getAppAgentName } from "../../../translation/agentTranslators.js"; -import { - renderRulesTable, - renderRuleDetail, -} from "../action/grammarActionHandler.js"; +import { executeGrammarAction } from "../action/grammarActionHandler.js"; // --------------------------------------------------------------------------- // Stored grammar rules (mirrors system.grammar NL actions) @@ -44,6 +40,7 @@ import { class GrammarListCommandHandler implements CommandHandler { public readonly description = "List grammar rules learned at runtime (optionally filtered by agent)"; + public readonly action = "listRules"; public readonly parameters = { args: { agent: { @@ -58,35 +55,22 @@ class GrammarListCommandHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const systemContext = context.sessionContext.agentContext; - const store = systemContext.persistedGrammarStore; - if (!store) { - displayWarn( - "Grammar rule management is not available in this session (no session directory).", - context, - ); - return; - } - const agentFilter = params.args.agent?.toLowerCase().trim(); - let rules = store.getAllRules(); - if (agentFilter) { - rules = rules.filter( - (r) => r.schemaName.toLowerCase() === agentFilter, - ); - } - rules.sort((a, b) => b.timestamp - a.timestamp); - const title = agentFilter - ? `Grammar rules for "${agentFilter}"` - : "All grammar rules"; - context.actionIO.appendDisplay({ - type: "html", - content: renderRulesTable(rules, title), - }); + return executeGrammarAction( + { + schemaName: "system.grammar", + actionName: "listRules", + ...(params.args.agent === undefined + ? {} + : { parameters: { agentName: params.args.agent } }), + }, + context, + ); } } class GrammarShowCommandHandler implements CommandHandler { public readonly description = "Show a stored grammar rule by ID"; + public readonly action = "showRule"; public readonly parameters = { args: { id: { @@ -100,33 +84,20 @@ class GrammarShowCommandHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const systemContext = context.sessionContext.agentContext; - const store = systemContext.persistedGrammarStore; - if (!store) { - displayWarn( - "Grammar rule management is not available in this session (no session directory).", - context, - ); - return; - } - const id = params.args.id; - const rule = store.getAllRules().find((r) => r.id === id); - if (!rule) { - displayResult( - `No grammar rule with ID ${id}. Use '@grammar list' to see available IDs.`, - context, - ); - return; - } - context.actionIO.appendDisplay({ - type: "html", - content: renderRuleDetail(rule), - }); + return executeGrammarAction( + { + schemaName: "system.grammar", + actionName: "showRule", + parameters: { id: params.args.id }, + }, + context, + ); } } class GrammarDeleteCommandHandler implements CommandHandler { public readonly description = "Delete a stored grammar rule by ID"; + public readonly action = "deleteRule"; public readonly parameters = { args: { id: { @@ -140,27 +111,12 @@ class GrammarDeleteCommandHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const systemContext = context.sessionContext.agentContext; - const store = systemContext.persistedGrammarStore; - if (!store) { - displayWarn( - "Grammar rule management is not available in this session (no session directory).", - context, - ); - return; - } - const id = params.args.id; - const deleted = await store.deleteRuleById(id); - if (!deleted) { - displayResult( - `No grammar rule with ID ${id}. Use '@grammar list' to see available IDs.`, - context, - ); - return; - } - systemContext.agentCache.syncAgentGrammar(deleted.schemaName); - displayResult( - `Deleted rule #${id} (${deleted.schemaName}${deleted.actionName ? `.${deleted.actionName}` : ""}).`, + return executeGrammarAction( + { + schemaName: "system.grammar", + actionName: "deleteRule", + parameters: { id: params.args.id }, + }, context, ); } @@ -169,6 +125,7 @@ class GrammarDeleteCommandHandler implements CommandHandler { class GrammarClearCommandHandler implements CommandHandler { public readonly description = "Clear stored grammar rules (optionally for a specific agent)"; + public readonly action = "clearRules"; public readonly parameters = { args: { agent: { @@ -184,30 +141,14 @@ class GrammarClearCommandHandler implements CommandHandler { context: ActionContext, params: ParsedCommandParams, ) { - const systemContext = context.sessionContext.agentContext; - const store = systemContext.persistedGrammarStore; - if (!store) { - displayWarn( - "Grammar rule management is not available in this session (no session directory).", - context, - ); - return; - } - const agentFilter = params.args.agent?.trim(); - const schemas = agentFilter ? [agentFilter] : store.getSchemaNames(); - let totalCount = 0; - for (const schema of schemas) { - const count = await store.clearSchema(schema); - if (count > 0) { - systemContext.agentCache.syncAgentGrammar(schema); - totalCount += count; - } - } - const scope = agentFilter ? ` for "${agentFilter}"` : ""; - displayResult( - totalCount === 0 - ? `No grammar rules found${scope}.` - : `Cleared ${totalCount} rule${totalCount === 1 ? "" : "s"}${scope}.`, + return executeGrammarAction( + { + schemaName: "system.grammar", + actionName: "clearRules", + ...(params.args.agent === undefined + ? {} + : { parameters: { agentName: params.args.agent } }), + }, context, ); } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.agr b/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.agr index 5e1574b00a..98430e6ca7 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.agr +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.agr @@ -145,7 +145,12 @@ parameters: { query } }; - = + = (show | open | display)? (command)? help -> { + actionName: "showConversationHelp" +}; + + = + | | | | diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.ts index 66d9970e28..a69e91a8de 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/conversationActionSchema.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. export type ConversationAction = + | ShowConversationHelpAction | NewConversationAction | ListConversationAction | FindConversationAction @@ -12,6 +13,11 @@ export type ConversationAction = | RenameConversationAction | DeleteConversationAction; +// Show help for TypeAgent conversation management commands. +export type ShowConversationHelpAction = { + actionName: "showConversationHelp"; +}; + // Create a new conversation and optionally give it a name. // Use this when the user wants to create, start, make, or open a brand-new conversation. // Examples: "create a new conversation", "start a new conversation called test", diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/describeActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/describeActionSchema.ts index 146e44aed5..8470983d1d 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/describeActionSchema.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/describeActionSchema.ts @@ -1,7 +1,23 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export type DescribeAction = DescribeAgentAction | DescribeActionAction; +export type DescribeAction = + | DescribeAgentOrAction + | DescribeAgentAction + | DescribeActionAction; + +// Describe an agent, or one action when actionName is supplied. +export type DescribeAgentOrAction = { + actionName: "describeAgentOrAction"; + parameters: { + // Agent name, or an action name when no owning agent is supplied. + name: string; + // Action name when name identifies the owning agent. + targetActionName?: string; + // Whether to show all actions instead of the default subset. + all?: boolean; + }; +}; // Describe what an agent can do: a natural-language summary plus its actions. // Works for installed-but-disabled agents too — describing is informational diff --git a/ts/packages/dispatcher/dispatcher/test/conversationActionHandler.spec.ts b/ts/packages/dispatcher/dispatcher/test/conversationActionHandler.spec.ts index 9a35d5d72f..bb0c8ba8a4 100644 --- a/ts/packages/dispatcher/dispatcher/test/conversationActionHandler.spec.ts +++ b/ts/packages/dispatcher/dispatcher/test/conversationActionHandler.spec.ts @@ -41,6 +41,11 @@ function expectCommand(command: string) { } describe("executeConversationAction delegates to @conversation commands", () => { + it("showConversationHelp runs help", async () => { + await run({ actionName: "showConversationHelp" }); + expectCommand("@conversation help"); + }); + it("newConversation with a name runs a quoted new command", async () => { const r = await run({ actionName: "newConversation", diff --git a/ts/packages/dispatcher/dispatcher/test/conversationGrammar.spec.ts b/ts/packages/dispatcher/dispatcher/test/conversationGrammar.spec.ts index cd4e3d78c8..0c22d52001 100644 --- a/ts/packages/dispatcher/dispatcher/test/conversationGrammar.spec.ts +++ b/ts/packages/dispatcher/dispatcher/test/conversationGrammar.spec.ts @@ -49,6 +49,17 @@ function makeMatcher() { describe("system.conversation grammar", () => { const match = makeMatcher(); + describe("showConversationHelp", () => { + it.each(["conversation help", "show conversation command help"])( + "matches %p", + (input) => { + expect(match(input)).toEqual({ + actionName: "showConversationHelp", + }); + }, + ); + }); + describe("listConversation", () => { it.each([ "list conversations", diff --git a/ts/packages/dispatcher/dispatcher/test/dispatcherDiagnosticsAction.spec.ts b/ts/packages/dispatcher/dispatcher/test/dispatcherDiagnosticsAction.spec.ts new file mode 100644 index 0000000000..b71bf2461e --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/test/dispatcherDiagnosticsAction.spec.ts @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { executeDispatcherDiagnosticsAction } from "../src/context/dispatcher/diagnosticsActionHandler.js"; + +function makeHandlers(calls: Record) { + const handler = (name: string, result?: object) => ({ + run: async (...args: unknown[]) => { + calls[name].push(args); + return result; + }, + }); + return { + request: handler("request"), + match: handler("match"), + translate: handler("translate"), + reason: handler("reason", { entities: [] }), + explain: handler("explain"), + } as any; +} + +function emptyCalls() { + return { + request: [] as unknown[][], + match: [] as unknown[][], + translate: [] as unknown[][], + reason: [] as unknown[][], + explain: [] as unknown[][], + }; +} + +describe("dispatcher diagnostics actions", () => { + it("maps request, match, and translate parameters", async () => { + const calls = emptyCalls(); + const handlers = makeHandlers(calls); + const context = { id: "context" } as any; + + await executeDispatcherDiagnosticsAction( + { + schemaName: "dispatcher.diagnostics", + actionName: "dispatchRequest", + }, + context, + handlers, + ); + await executeDispatcherDiagnosticsAction( + { + schemaName: "dispatcher.diagnostics", + actionName: "matchDispatcherRequest", + parameters: { request: "play jazz" }, + }, + context, + handlers, + ); + await executeDispatcherDiagnosticsAction( + { + schemaName: "dispatcher.diagnostics", + actionName: "translateDispatcherRequest", + parameters: { request: "play jazz", useHistory: true }, + }, + context, + handlers, + ); + + expect(calls.request[0]).toEqual([ + context, + { args: { request: undefined }, flags: undefined }, + ]); + expect(calls.match[0]).toEqual([ + context, + { args: { request: "play jazz" }, flags: undefined }, + ]); + expect(calls.translate[0]).toEqual([ + context, + { + args: { request: "play jazz" }, + flags: { history: true }, + }, + ]); + }); + + it("maps reasoning defaults and returns the handler result", async () => { + const calls = emptyCalls(); + const handlers = makeHandlers(calls); + const context = { id: "context" } as any; + + const result = await executeDispatcherDiagnosticsAction( + { + schemaName: "dispatcher.diagnostics", + actionName: "reasonAboutRequest", + parameters: { request: "plan my afternoon" }, + }, + context, + handlers, + ); + + expect(calls.reason[0]).toEqual([ + context, + { + args: { request: "plan my afternoon" }, + flags: { engine: "" }, + }, + ]); + expect(result).toEqual({ entities: [] }); + }); + + it("maps explanation defaults exactly", async () => { + const calls = emptyCalls(); + const handlers = makeHandlers(calls); + const context = { id: "context" } as any; + + await executeDispatcherDiagnosticsAction( + { + schemaName: "dispatcher.diagnostics", + actionName: "explainDispatcherRequest", + parameters: { requestAction: "play jazz => player.playMusic" }, + }, + context, + handlers, + ); + + expect(calls.explain[0]).toEqual([ + context, + { + args: { requestAction: "play jazz => player.playMusic" }, + flags: { + repeat: 1, + filterValueInRequest: false, + filterReference: false, + concurrency: 5, + }, + }, + ]); + }); +}); diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index 479762cd37..42188db642 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -2247,6 +2247,9 @@ importers: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) devDependencies: + '@typeagent/action-grammar': + specifier: workspace:* + version: link:../../actionGrammar '@typeagent/action-grammar-compiler': specifier: workspace:* version: link:../../actionGrammarCompiler @@ -3115,6 +3118,9 @@ importers: specifier: ^0.1.1 version: 0.1.1(typescript@5.4.5)(zod@3.25.76) devDependencies: + '@typeagent/action-grammar': + specifier: workspace:* + version: link:../../actionGrammar '@typeagent/action-grammar-compiler': specifier: workspace:* version: link:../../actionGrammarCompiler From b80591fa06ddd2682caaf8272fdf3a3404ff9853 Mon Sep 17 00:00:00 2001 From: Robert Gruen Date: Fri, 31 Jul 2026 16:51:30 -0700 Subject: [PATCH 04/22] next phase of actions --- ts/docs/plans/agent-command-actions/STATUS.md | 50 +- .../agentSdk/src/helpers/commandHelpers.ts | 4 +- .../calendar/src/calendarActionHandlerV3.ts | 45 +- .../agents/calendar/test/calendarAuth.spec.ts | 41 +- .../agents/email/src/emailActionHandler.ts | 71 ++- .../agents/email/test/emailAuth.spec.ts | 48 ++ .../agents/email/test/emailIndex.spec.ts | 9 +- .../dispatcher/src/context/memory.ts | 48 +- .../system/action/collisionActionHandler.ts | 435 ++++++++++++++++++ .../system/action/configActionHandler.ts | 179 ++++++- .../action/constructionActionHandler.ts | 102 ++++ .../system/action/copilotActionHandler.ts | 68 +++ .../system/action/feedbackActionHandler.ts | 95 ++++ .../system/action/grammarActionHandler.ts | 24 + .../system/action/historyActionHandler.ts | 47 ++ .../system/action/indexActionHandler.ts | 71 +++ .../system/action/memoryActionHandler.ts | 71 +++ .../action/notificationActionHandler.ts | 38 ++ .../system/action/sessionActionHandler.ts | 90 ++++ .../system/action/settingsActionHandler.ts | 14 + .../action/systemDiagnosticsActionHandler.ts | 55 +++ .../action/systemOperationsActionHandler.ts | 106 +++++ .../system/handlers/actionCommandHandler.ts | 4 + .../handlers/collisionCommandHandlers.ts | 51 +- .../handlers/collisionCorpusHandlers.ts | 32 ++ .../handlers/collisionKeywordHandlers.ts | 8 + .../handlers/collisionNeighborhoodHandlers.ts | 4 + .../handlers/collisionOptimizeHandlers.ts | 28 ++ .../handlers/collisionPreferenceHandlers.ts | 16 + .../system/handlers/configCommandHandlers.ts | 209 +++++---- .../handlers/constructionCommandHandlers.ts | 208 ++++++--- .../system/handlers/copilotCommandHandlers.ts | 32 +- .../system/handlers/debugCommandHandlers.ts | 4 + .../system/handlers/demoCommandHandlers.ts | 4 + .../system/handlers/displayCommandHandler.ts | 4 + .../system/handlers/envCommandHandler.ts | 26 +- .../handlers/feedbackCommandHandlers.ts | 44 +- .../system/handlers/grammarCommandHandlers.ts | 4 + .../system/handlers/helpCommandHandler.ts | 4 + .../system/handlers/historyCommandHandler.ts | 42 +- .../system/handlers/indexCommandHandler.ts | 44 +- .../system/handlers/notifyCommandHandler.ts | 49 +- .../system/handlers/openCommandHandler.ts | 4 + .../system/handlers/portsCommandHandler.ts | 4 + .../system/handlers/randomCommandHandler.ts | 26 +- .../handlers/runScriptCommandHandler.ts | 4 + .../system/handlers/sessionCommandHandlers.ts | 54 ++- .../handlers/settingsCommandHandlers.ts | 6 + .../system/handlers/tokenCommandHandler.ts | 26 +- .../system/handlers/traceCommandHandler.ts | 4 + .../system/schema/collisionActionSchema.ts | 326 +++++++++++++ .../system/schema/configActionSchema.ts | 187 +++++++- .../system/schema/constructionActionSchema.ts | 112 +++++ .../system/schema/copilotActionSchema.ts | 36 ++ .../system/schema/feedbackActionSchema.ts | 54 +++ .../system/schema/grammarActionSchema.ts | 11 +- .../system/schema/historyActionSchema.ts | 38 +- .../system/schema/indexActionSchema.ts | 44 ++ .../system/schema/memoryActionSchema.ts | 48 ++ .../system/schema/notificationActionSchema.ts | 28 +- .../system/schema/sessionActionSchema.ts | 51 ++ .../system/schema/settingsActionSchema.ts | 12 + .../schema/systemDiagnosticsActionSchema.ts | 44 ++ .../schema/systemOperationsActionSchema.ts | 104 +++++ .../src/context/system/systemAgent.ts | 188 +++++++- .../dispatcher/src/helpers/command.ts | 8 +- .../test/collisionActionHandler.spec.ts | 162 +++++++ .../test/configActionHandler.spec.ts | 122 +++++ .../grammarCollisionActionHandler.spec.ts | 47 ++ .../test/historyInsertActionHandler.spec.ts | 61 +++ .../test/systemActionHandlerImports.spec.ts | 31 ++ .../test/commandActionCoverage.spec.ts | 85 ++++ 72 files changed, 4048 insertions(+), 407 deletions(-) create mode 100644 ts/packages/agents/email/test/emailAuth.spec.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/collisionActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/constructionActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/copilotActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/feedbackActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/indexActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/memoryActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/sessionActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/systemDiagnosticsActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/schema/systemOperationsActionSchema.ts create mode 100644 ts/packages/dispatcher/dispatcher/test/collisionActionHandler.spec.ts create mode 100644 ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts create mode 100644 ts/packages/dispatcher/dispatcher/test/grammarCollisionActionHandler.spec.ts create mode 100644 ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts create mode 100644 ts/packages/dispatcher/dispatcher/test/systemActionHandlerImports.spec.ts create mode 100644 ts/tools/actionBrowser/test/commandActionCoverage.spec.ts diff --git a/ts/docs/plans/agent-command-actions/STATUS.md b/ts/docs/plans/agent-command-actions/STATUS.md index e6d51f4797..c198b4b672 100644 --- a/ts/docs/plans/agent-command-actions/STATUS.md +++ b/ts/docs/plans/agent-command-actions/STATUS.md @@ -18,8 +18,8 @@ collection, not manual estimates. | Metric | Count | | ------------------------------------ | ------------------: | | Executable command endpoints | 387 | -| Valid linked endpoints | 96 | -| Missing action declarations | 291 | +| Valid linked endpoints | 387 | +| Missing action declarations | 0 | | Invalid / dangling / ambiguous links | 0 | | Runtime-only static omissions | 1 (`mcpfilesystem`) | @@ -33,12 +33,12 @@ collection, not manual estimates. - [x] Fail strict manifest, authored-schema, and command-table collection. - [x] Report runtime-only schema omissions explicitly. - [x] Add missing/invalid endpoint counters and migration check mode. -- [ ] Generate and maintain the per-host endpoint ledger. +- [x] Generate and maintain the per-host endpoint ledger. - [x] Audit and link exact existing equivalents. - [x] Complete all remaining agent-host actions. -- [ ] Complete existing system action families. -- [ ] Add remaining system action families. -- [ ] Enable permanent zero-gap regression check. +- [x] Complete existing system action families. +- [x] Add remaining system action families. +- [x] Enable permanent zero-gap regression check. ## Implemented hosts and slices @@ -59,16 +59,29 @@ All non-system command hosts are now fully covered. ## System progress -| Family | Completed in this milestone | -| ------------ | --------------------------------------------------------------- | -| conversation | Added help action for bare `@conversation` and explicit `help`. | -| grammar | Unified and linked list/show/delete/clear plus bare default. | -| describe | Added exact multiplexing action for `@describe`. | - -The current migration check is: +| Family | Completed in this milestone | +| ------------ | ------------------------------------------------------------------------------------------------ | +| conversation | Added help and completed every conversation endpoint. | +| grammar | Linked rule management and collision scanning, including the bare default. | +| describe | Added exact multiplexing for `@describe`. | +| settings | Completed all seven persistent user-setting endpoints. | +| notify | Completed all eight notification endpoints. | +| history | Completed all history, entity, attachment, and transcript endpoints. | +| index | Added create/list/show/delete actions for all five endpoints. | +| diagnostics | Added environment, token, and random-request actions for all nine endpoints. | +| session | Added create/open/reset/clear/list/delete/info actions for all seven endpoints. | +| memory | Added legacy toggle, query, search, and answer actions for all six endpoints. | +| copilot | Added import, fix handoff, and login actions for all four endpoints. | +| feedback | Added list/summary/filter/export/count actions for all six endpoints. | +| operations | Added help, display, scripts, tracing, debugging, lifecycle, demo, and other small operations. | +| construction | Added store lifecycle, inspection, import, pruning, and toggle actions for all 24 endpoints. | +| collision | Added telemetry, corpus, keyword, neighborhood, optimization, and preference actions (30 total). | +| config | Added an explicit 165-path config action that delegates to the canonical command parser. | + +The strict coverage check is: ```text -Command action coverage: 96 / 387 endpoints (291 missing, 0 invalid) +Command action coverage: 387 / 387 endpoints (0 missing, 0 invalid) Runtime-only schemas omitted: mcpfilesystem ``` @@ -80,12 +93,13 @@ pnpm --filter @typeagent/action-browser test:local node tools/actionBrowser/dist/cli.js --check --allow-missing ``` -Strict completion command (expected to fail until all 291 remaining gaps -close): +Permanent regression coverage is also enforced by +`test/commandActionCoverage.spec.ts`. The strict completion command is: ```powershell node tools/actionBrowser/dist/cli.js --check ``` -The remaining gaps are all system command families. No built-in command is -excluded; every remaining endpoint stays in the ledger until covered. +No bundled executable command is excluded. `mcpfilesystem` remains an explicit +runtime-only action-schema omission because its actions are generated from the +connected MCP server rather than authored statically. diff --git a/ts/packages/agentSdk/src/helpers/commandHelpers.ts b/ts/packages/agentSdk/src/helpers/commandHelpers.ts index 0bfd8f4e02..413c23a6d3 100644 --- a/ts/packages/agentSdk/src/helpers/commandHelpers.ts +++ b/ts/packages/agentSdk/src/helpers/commandHelpers.ts @@ -54,7 +54,7 @@ export type CommandHandler = CommandDescriptor & { ): Promise; }; -type CommandHandlerTypes = CommandHandlerNoParams | CommandHandler; +export type CommandHandlerTypes = CommandHandlerNoParams | CommandHandler; function isCommandHandlerNoParams( handler: CommandHandlerTypes, @@ -104,7 +104,7 @@ export function isCommandDescriptorTable( return (entry as CommandDescriptorTable).commands !== undefined; } -function getCommandHandler( +export function getCommandHandler( handlers: CommandDefinitions, commands: string[], ): CommandHandlerTypes { diff --git a/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts b/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts index ade065b384..c1f99f87c4 100644 --- a/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts +++ b/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts @@ -37,6 +37,7 @@ import { CalendarClient, ICalendarProvider, CalendarProviderType, + CalendarUser, createCalendarProviderFromConfig, claimSilentRestoreAnnouncement, evaluateGraphReadiness, @@ -85,16 +86,7 @@ export class CalendarClientLoginCommandHandler const name = user.displayName || "Unknown"; const email = user.email || "Unknown"; displayWarn(`Already logged in as ${name}<${email}>`, context); - // Re-emit the signed-in marker so the avatar (name + photo) - // resyncs even when the user was already authenticated — e.g. - // restored silently on launch before the photo had been fetched. - const photoAttr = user.photoUrl - ? ` data-photo="${escapeHtml(user.photoUrl)}"` - : ""; - context.actionIO.appendDisplay({ - type: "html", - content: ``, - }); + await applyCalendarLoginState(context, user); return; } @@ -123,18 +115,7 @@ export class CalendarClientLoginCommandHandler `Successfully logged in as ${name} <${email}>`, context, ); - // Hidden marker the chat-ui / shell scan for after each agent - // message. Lifts the signed-in identity into UI state so the - // user-letter avatar shows the real initial and stops triggering - // login on click. data-photo carries the base64 profile photo - // (when the provider has one) so the avatar can render the image. - const photoAttr = user.photoUrl - ? ` data-photo="${escapeHtml(user.photoUrl)}"` - : ""; - context.actionIO.appendDisplay({ - type: "html", - content: ``, - }); + await applyCalendarLoginState(context, user); } else { displayWarn( "Login failed. If using Google Calendar, you can also try '@calendar google-auth ' with a manual authorization code.", @@ -227,6 +208,7 @@ export class GoogleAuthCommandHandler implements CommandHandler { `Successfully logged in to Google Calendar as ${user.displayName || "Unknown"} <${user.email || "Unknown"}>`, context, ); + await applyCalendarLoginState(context, user); } else { displayWarn( "Failed to complete authorization. Please try '@calendar login' again to get a new code.", @@ -259,6 +241,22 @@ function escapeHtml(text: string): string { .replace(/"/g, """); } +async function applyCalendarLoginState( + context: ActionContext, + user: CalendarUser, +): Promise { + const name = user.displayName || "Unknown"; + const email = user.email || "Unknown"; + const photoAttr = user.photoUrl + ? ` data-photo="${escapeHtml(user.photoUrl)}"` + : ""; + context.actionIO.appendDisplay({ + type: "html", + content: ``, + }); + await context.sessionContext.notifyReadinessChanged(); +} + // Attempt a silent, non-interactive sign-in using cached MS Graph // credentials so a previously signed-in user sees the signed-in avatar // (name + photo) on app launch without clicking login. Only runs for the @@ -1394,8 +1392,9 @@ export async function runCalendarLogin( ); } const user = await provider.getUser(); + await applyCalendarLoginState(actionContext, user); return createActionResultFromTextDisplay( - `[${ts()}] Signed in as ${user.displayName || user.email || "Unknown"}. Re-run your calendar command — readiness was re-checked automatically.`, + `[${ts()}] Signed in as ${user.displayName || user.email || "Unknown"}. Re-run your calendar command - readiness was re-checked automatically.`, ); } catch (e: any) { return createActionResultFromError( diff --git a/ts/packages/agents/calendar/test/calendarAuth.spec.ts b/ts/packages/agents/calendar/test/calendarAuth.spec.ts index 06799af7e1..515b5b6b65 100644 --- a/ts/packages/agents/calendar/test/calendarAuth.spec.ts +++ b/ts/packages/agents/calendar/test/calendarAuth.spec.ts @@ -13,7 +13,10 @@ import type { CommandDescriptor, CommandDescriptorTable, } from "@typeagent/agent-sdk"; -import { instantiate } from "../src/calendarActionHandlerV3.js"; +import { + instantiate, + runCalendarLogin, +} from "../src/calendarActionHandlerV3.js"; const here = path.dirname(fileURLToPath(import.meta.url)); const grammarPath = path.resolve(here, "..", "..", "src", "calendarSchema.agr"); @@ -75,6 +78,7 @@ describe("calendar auth actions", () => { it("re-emits identity when login is already authenticated", async () => { const agent = instantiate(); + let readinessCalls = 0; const displays: unknown[] = []; const context = { sessionContext: { @@ -88,6 +92,9 @@ describe("calendar auth actions", () => { }, providerType: "microsoft", }, + notifyReadinessChanged: async () => { + readinessCalls++; + }, }, actionIO: { setDisplay: (value: unknown) => displays.push(value), @@ -102,6 +109,7 @@ describe("calendar auth actions", () => { expect(JSON.stringify(displays)).toMatch(/ada@example\.com/); expect(JSON.stringify(displays)).toMatch(/typeagent-user-signed-in/); + expect(readinessCalls).toBe(1); }); it("logs out and refreshes cached readiness", async () => { @@ -139,6 +147,37 @@ describe("calendar auth actions", () => { expect(JSON.stringify(displays)).toMatch(/typeagent-user-signed-out/); }); + it("refreshes readiness after setup login completes", async () => { + let readinessCalls = 0; + const displays: unknown[] = []; + const context = { + sessionContext: { + agentContext: { + calendarProvider: { + login: async () => true, + getUser: async () => ({ + displayName: "Ada", + email: "ada@example.com", + }), + }, + providerType: "microsoft", + }, + notifyReadinessChanged: async () => { + readinessCalls++; + }, + }, + actionIO: { + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await runCalendarLogin(context); + + expect(readinessCalls).toBe(1); + expect(JSON.stringify(displays)).toMatch(/typeagent-user-signed-in/); + expect(JSON.stringify(displays)).toMatch(/ada@example\.com/); + }); + it("forwards the Google authorization code unchanged", async () => { const agent = instantiate(); const codes: string[] = []; diff --git a/ts/packages/agents/email/src/emailActionHandler.ts b/ts/packages/agents/email/src/emailActionHandler.ts index 5252f82cee..00bf99cdb0 100644 --- a/ts/packages/agents/email/src/emailActionHandler.ts +++ b/ts/packages/agents/email/src/emailActionHandler.ts @@ -3,6 +3,7 @@ import { IEmailProvider, + EmailUser, EmailMessage, EmailProviderType, EmailSearchQuery, @@ -131,16 +132,7 @@ class EmailLoginCommandHandler implements CommandHandlerNoParams { const name = user.displayName || "Unknown"; const email = user.email || "Unknown"; displayWarn(`Already logged in as ${name}<${email}>`, context); - // Re-emit the signed-in marker so the avatar (name + photo) - // resyncs even when the user was already authenticated — e.g. - // restored silently on launch before the photo had been fetched. - const photoAttr = user.photoUrl - ? ` data-photo="${escapeHtml(user.photoUrl)}"` - : ""; - context.actionIO.appendDisplay({ - type: "html", - content: ``, - }); + await applyEmailLoginState(context, user, false); return; } @@ -168,28 +160,7 @@ class EmailLoginCommandHandler implements CommandHandlerNoParams { `Successfully logged in as ${name} <${email}>`, context, ); - // Hidden marker the chat-ui / shell scan for after each agent - // message. Lifts the signed-in identity into UI state so the - // user-letter avatar shows the real initial and stops triggering - // login on click. data-photo carries the base64 profile photo - // (when the provider has one) so the avatar can render the image. - const photoAttr = user.photoUrl - ? ` data-photo="${escapeHtml(user.photoUrl)}"` - : ""; - context.actionIO.appendDisplay({ - type: "html", - content: ``, - }); - - // Kick off async index build/sync after successful login - const agentCtx = context.sessionContext.agentContext; - if (!agentCtx.kpIndex.loaded) { - // First time: build initial index in background - startBackgroundInitialIndex(agentCtx); - } else { - // Index exists: forward sync in background - startBackgroundSync(agentCtx); - } + await applyEmailLoginState(context, user, true); } else { displayWarn( "Login failed. If using Google, you can also try '@email google-auth ' with a manual authorization code.", @@ -278,13 +249,7 @@ class GoogleAuthCommandHandler implements CommandHandler { context, ); - // Kick off async index build/sync after successful auth - const agentCtx = context.sessionContext.agentContext; - if (!agentCtx.kpIndex.loaded) { - startBackgroundInitialIndex(agentCtx); - } else { - startBackgroundSync(agentCtx); - } + await applyEmailLoginState(context, user, true); } else { displayWarn( "Failed to complete authorization. Please try '@email login' again to get a new code.", @@ -476,8 +441,9 @@ export async function runEmailLogin( ); } const user = await provider.getUser(); + await applyEmailLoginState(actionContext, user, true); return createActionResultFromTextDisplay( - `[${emailTs()}] Signed in as ${user.displayName || user.email || "Unknown"}. Re-run your email command — readiness was re-checked automatically.`, + `[${emailTs()}] Signed in as ${user.displayName || user.email || "Unknown"}. Re-run your email command - readiness was re-checked automatically.`, ); } catch (e: any) { return createActionResultFromError( @@ -867,6 +833,31 @@ function escapeHtml(text: string): string { .replace(/"/g, """); } +async function applyEmailLoginState( + context: ActionContext, + user: EmailUser, + startIndex: boolean, +): Promise { + const name = user.displayName || "Unknown"; + const email = user.email || "Unknown"; + const photoAttr = user.photoUrl + ? ` data-photo="${escapeHtml(user.photoUrl)}"` + : ""; + context.actionIO.appendDisplay({ + type: "html", + content: ``, + }); + if (startIndex) { + const agentContext = context.sessionContext.agentContext; + if (!agentContext.kpIndex.loaded) { + startBackgroundInitialIndex(agentContext); + } else { + startBackgroundSync(agentContext); + } + } + await context.sessionContext.notifyReadinessChanged(); +} + // Attempt a silent, non-interactive sign-in using cached MS Graph // credentials so a previously signed-in user sees the signed-in avatar // (name + photo) on app launch without clicking login. Only runs for the diff --git a/ts/packages/agents/email/test/emailAuth.spec.ts b/ts/packages/agents/email/test/emailAuth.spec.ts new file mode 100644 index 0000000000..f80e0bb383 --- /dev/null +++ b/ts/packages/agents/email/test/emailAuth.spec.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import assert from "node:assert/strict"; +import * as path from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(here, "..", ".."); +const { runEmailLogin } = await import( + pathToFileURL(path.join(packageRoot, "dist", "emailActionHandler.js")).href +); + +describe("email auth actions", () => { + it("refreshes readiness after setup login completes", async () => { + let readinessCalls = 0; + const displays: unknown[] = []; + const context = { + sessionContext: { + agentContext: { + emailProvider: { + login: async () => true, + getUser: async () => ({ + displayName: "Ada", + email: "ada@example.com", + }), + }, + providerType: "microsoft", + kpIndex: { loaded: false }, + indexingInProgress: true, + }, + notifyReadinessChanged: async () => { + readinessCalls++; + }, + }, + actionIO: { + appendDisplay: (value: unknown) => displays.push(value), + }, + } as any; + + await runEmailLogin(context); + + assert.equal(readinessCalls, 1); + assert.match(JSON.stringify(displays), /typeagent-user-signed-in/); + assert.match(JSON.stringify(displays), /ada@example\.com/); + }); +}); diff --git a/ts/packages/agents/email/test/emailIndex.spec.ts b/ts/packages/agents/email/test/emailIndex.spec.ts index 0ab2dcd149..cd17a9596a 100644 --- a/ts/packages/agents/email/test/emailIndex.spec.ts +++ b/ts/packages/agents/email/test/emailIndex.spec.ts @@ -156,6 +156,7 @@ describe("email auth actions", () => { it("re-emits identity when login is already authenticated", async () => { const agent = instantiate(); + let readinessCalls = 0; const displays: unknown[] = []; const agentContext = { emailProvider: { @@ -168,7 +169,12 @@ describe("email auth actions", () => { providerType: "microsoft", }; const context = { - sessionContext: { agentContext }, + sessionContext: { + agentContext, + notifyReadinessChanged: async () => { + readinessCalls++; + }, + }, actionIO: { setDisplay: (value: unknown) => displays.push(value), appendDisplay: (value: unknown) => displays.push(value), @@ -182,6 +188,7 @@ describe("email auth actions", () => { assert.match(JSON.stringify(displays), /ada@example\.com/); assert.match(JSON.stringify(displays), /typeagent-user-signed-in/); + assert.equal(readinessCalls, 1); }); it("logs out and refreshes cached readiness", async () => { diff --git a/ts/packages/dispatcher/dispatcher/src/context/memory.ts b/ts/packages/dispatcher/dispatcher/src/context/memory.ts index 5e4dde02f8..198d719e1c 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/memory.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/memory.ts @@ -23,7 +23,7 @@ import type { } from "@typeagent/agent-sdk"; import { ExecutableAction, getFullActionName } from "@typeagent/agent-cache"; import { CachedImageWithDetails } from "@typeagent/typechat-utils"; -import { getAppAgentName } from "../internal.js"; +import { getAppAgentName } from "../translation/agentTranslators.js"; import { CommandHandler, CommandHandlerTable, @@ -279,6 +279,10 @@ function ensureMemory(context: ActionContext) { class MemorySearchCommandHandler implements CommandHandler { public readonly description = "Search conversation memory"; + public readonly action = { + schema: "system.memory", + actionName: "queryMemory", + }; public readonly parameters = { args: { terms: { @@ -405,7 +409,13 @@ class MemoryAnswerCommandHandler implements CommandHandler { }, }, } as const; - constructor(private search: boolean) {} + constructor( + private search: boolean, + public readonly action: { + schema: string; + actionName: string; + }, + ) {} private async getResult( memory: ConversationMemory, @@ -478,22 +488,32 @@ export function getMemoryCommandHandlers(): CommandHandlerTable { return { description: "Memory commands", commands: { - legacy: getToggleHandlerTable("legacy", async (context, enable) => { - await changeContextConfig( - { - execution: { - memory: { - legacy: enable, + legacy: getToggleHandlerTable( + "legacy", + async (context, enable) => { + await changeContextConfig( + { + execution: { + memory: { + legacy: enable, + }, }, }, - }, - context, - ); - }), + context, + ); + }, + { schema: "system.memory", actionName: "setLegacyMemory" }, + ), query: new MemorySearchCommandHandler(), - search: new MemoryAnswerCommandHandler(true), - answer: new MemoryAnswerCommandHandler(false), + search: new MemoryAnswerCommandHandler(true, { + schema: "system.memory", + actionName: "searchMemory", + }), + answer: new MemoryAnswerCommandHandler(false, { + schema: "system.memory", + actionName: "answerFromMemory", + }), }, }; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts new file mode 100644 index 0000000000..9d1948e95c --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts @@ -0,0 +1,435 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { CollisionAction } from "../schema/collisionActionSchema.js"; + +function csv(values: string[] | undefined): string | undefined { + return values?.join(","); +} + +export function executeCollisionAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, + commandExecutor: typeof executeCommandFromHandlers = executeCommandFromHandlers, +): Promise { + const execute = (commands: string[], params?: ParsedCommandParams) => + commandExecutor(handlers, commands, params, context); + const params: any = "parameters" in action ? action.parameters : undefined; + + switch (action.actionName) { + case "showCollisionEvents": + return execute(["events"], { + args: {}, + flags: { + limit: params?.limit ?? 10, + ...(params?.kind === undefined + ? {} + : { kind: params.kind }), + }, + }); + case "findSimilarActions": + return execute(["similar"], { + args: {}, + flags: { + threshold: params?.threshold ?? 0.85, + strategy: params?.strategy ?? "balanced", + "all-strategies": params?.allStrategies ?? false, + pairs: params?.pairs ?? false, + top: params?.top ?? 50, + ...(params?.jsonPath === undefined + ? {} + : { json: params.jsonPath }), + "no-cache": params?.noCache ?? false, + }, + }); + case "listCollisionStrategies": + return execute(["list-strategies"], { args: {}, flags: {} }); + case "probeCollisionPhrase": + return execute(["probe"], { + args: { phrase: params.phrase }, + flags: { + top: params.top ?? 5, + ...(params.expected === undefined + ? {} + : { expected: params.expected }), + delta: params.delta ?? 0.05, + "include-inactive": params.includeInactive ?? false, + }, + }); + case "generateCollisionCorpus": + return execute(["corpus", "generate"], { + args: {}, + flags: { + ...(params?.schemas === undefined + ? {} + : { schemas: csv(params.schemas) }), + ...(params?.models === undefined + ? {} + : { models: csv(params.models) }), + ...(params?.styles === undefined + ? {} + : { styles: csv(params.styles) }), + concurrency: params?.concurrency ?? 8, + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "probeCollisionCorpus": + return execute(["corpus", "probe"], { + args: {}, + flags: { + ...(params?.inputPath === undefined + ? {} + : { in: params.inputPath }), + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + top: params?.top ?? 5, + delta: params?.delta ?? 0.05, + concurrency: params?.concurrency ?? 8, + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "translateCollisionCorpus": + return execute(["corpus", "translate"], { + args: {}, + flags: { + ...(params?.inputPath === undefined + ? {} + : { in: params.inputPath }), + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + concurrency: params?.concurrency ?? 4, + strategy: params?.strategy ?? "first-match", + ...(params?.maxPhrases === undefined + ? {} + : { "max-phrases": params.maxPhrases }), + ...(params?.modelLabel === undefined + ? {} + : { "model-label": params.modelLabel }), + "user-context-mode": params?.userContextMode ?? "none", + ...(params?.userContextJson === undefined + ? {} + : { "user-context-json": params.userContextJson }), + ...(params?.outputSuffix === undefined + ? {} + : { "output-suffix": params.outputSuffix }), + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "reanalyzeCollisionCorpus": + return execute(["corpus", "reanalyze"], { + args: {}, + flags: { + ...(params?.inputPath === undefined + ? {} + : { in: params.inputPath }), + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + delta: params?.delta ?? 0.05, + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "visualizeCollisionCorpus": + return execute(["corpus", "visualize"], { + args: {}, + flags: { + ...(params?.inputPath === undefined + ? {} + : { in: params.inputPath }), + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + top: params?.top ?? 60, + "similarity-strategy": + params?.similarityStrategy ?? "balanced", + "similarity-threshold": String( + params?.similarityThreshold ?? 0.85, + ), + "no-similarity": params?.noSimilarity ?? false, + ...(params?.translatorPath === undefined + ? {} + : { translator: params.translatorPath }), + "no-translator": params?.noTranslator ?? false, + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "runCollisionCorpusPipeline": + return execute(["corpus", "run"], { + args: {}, + flags: { + from: params?.from ?? "generate", + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + ...(params?.schemas === undefined + ? {} + : { schemas: csv(params.schemas) }), + ...(params?.models === undefined + ? {} + : { models: csv(params.models) }), + ...(params?.styles === undefined + ? {} + : { styles: csv(params.styles) }), + concurrency: params?.concurrency ?? 8, + delta: params?.delta ?? 0.05, + top: params?.top ?? 5, + "sankey-top": params?.sankeyTop ?? 60, + }, + }); + case "analyzeCollisionRecovery": + return execute(["corpus", "recovery"], { + args: {}, + flags: { + ...(params?.inputPath === undefined + ? {} + : { in: params.inputPath }), + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + delta: params?.delta ?? 0.05, + }, + }); + case "visualizeCollisionRecovery": + return execute(["corpus", "visualize-recovery"], { + args: {}, + flags: { + ...(params?.inputPath === undefined + ? {} + : { in: params.inputPath }), + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + delta: params?.delta ?? 0.05, + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "manageCollisionKeywords": { + const operation = + params?.operation ?? + (params?.target === undefined ? "listOverrides" : "show"); + if (operation === "listOverrides") { + return execute(["keywords"], { + args: {}, + flags: {}, + }); + } + if (params?.target === undefined) { + throw new Error( + `A target is required to ${operation} collision keywords.`, + ); + } + return execute(["keywords"], { + args: { + tokens: [ + params.target, + operation, + ...(params.keywords ?? []), + ], + }, + flags: {}, + } as unknown as ParsedCommandParams); + } + case "backfillCollisionKeywords": + return execute(["keywords", "backfill"], { + args: { + ...(params?.schemas === undefined + ? {} + : { schemas: params.schemas }), + }, + flags: { + llm: params?.useLlm ?? false, + force: params?.force ?? false, + }, + } as unknown as ParsedCommandParams); + case "buildCollisionNeighborhoods": + return execute(["neighborhoods"], { + args: {}, + flags: { + ...(params?.corpusPath === undefined + ? {} + : { corpus: params.corpusPath }), + "min-misroute": params?.minMisroute ?? 2, + "include-same-schema": params?.includeSameSchema ?? true, + "samples-per-category": params?.samplesPerCategory ?? 5, + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + ...(params?.outputHtmlPath === undefined + ? {} + : { "out-html": params.outputHtmlPath }), + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "listCollisionOptimizationLevers": + return execute(["optimize", "list-levers"], { + args: {}, + flags: {}, + }); + case "exploreCollisionOptimizations": + return execute(["optimize", "explore"], { + args: {}, + flags: { + ...(params?.corpusPath === undefined + ? {} + : { corpus: params.corpusPath }), + ...(params?.baselinePath === undefined + ? {} + : { baseline: params.baselinePath }), + top: params?.top ?? 5, + "hypotheses-per-lever": params?.hypothesesPerLever ?? 3, + depth: params?.depth ?? 2, + ...(params?.levers === undefined + ? {} + : { lever: csv(params.levers) }), + severity: csv(params?.severities) ?? "blocker,leaky", + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + "dry-run": params?.dryRun ?? false, + concurrency: params?.concurrency ?? 8, + }, + }); + case "validateCollisionOptimizations": + return execute(["optimize", "validate"], { + args: {}, + flags: { + ...(params?.runId === undefined + ? {} + : { run: params.runId }), + ...(params?.neighborhoodId === undefined + ? {} + : { phrases: params.neighborhoodId }), + ...(params?.baselinePath === undefined + ? {} + : { baseline: params.baselinePath }), + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + ...(params?.winners === undefined + ? {} + : { winners: csv(params.winners) }), + ...(params?.leaveOneOut === undefined + ? {} + : { "leave-one-out": csv(params.leaveOneOut) }), + }, + }); + case "mineCollisionOptimizationPatterns": + return execute(["optimize", "patterns"], { + args: {}, + flags: { + ...(params?.patternsFile === undefined + ? {} + : { "patterns-file": params.patternsFile }), + "min-attempts": params?.minAttempts ?? 5, + "surface-disagreement": String( + params?.surfaceDisagreement ?? 0.5, + ), + ...(params?.outputPath === undefined + ? {} + : { out: params.outputPath }), + ...(params?.outputHtmlPath === undefined + ? {} + : { "out-html": params.outputHtmlPath }), + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "runCollisionOptimizationPipeline": + return execute(["optimize", "run"], { + args: {}, + flags: { + from: params?.from ?? "neighborhoods", + top: params?.top ?? 5, + depth: params?.depth ?? 2, + ...(params?.levers === undefined + ? {} + : { lever: csv(params.levers) }), + severity: csv(params?.severities) ?? "blocker,leaky", + "dry-run": params?.dryRun ?? false, + "skip-distill": params?.skipDistill ?? false, + "distill-min-attempts": params?.distillMinAttempts ?? 10, + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "distillCollisionOptimizationPatterns": + return execute(["optimize", "distill"], { + args: {}, + flags: { + "min-attempts": params?.minAttempts ?? 10, + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "browseCollisionOptimizationRuns": + return execute(["optimize", "browse"], { + args: {}, + flags: { + ...(params?.runId === undefined + ? {} + : { run: params.runId }), + all: params?.all ?? false, + ...(params?.workdir === undefined + ? {} + : { workdir: params.workdir }), + }, + }); + case "listCollisionPreferences": + return execute(["preferences", "list"], { + args: {}, + flags: {}, + }); + case "setCollisionPreference": + return execute(["preferences", "set"], { + args: { + candidates: params.candidates.join(","), + chosen: params.chosen, + }, + flags: {}, + }); + case "removeCollisionPreference": + return execute(["preferences", "remove"], { + args: { key: params.key }, + flags: {}, + }); + case "clearCollisionPreferences": + return execute(["preferences", "clear"], { + args: {}, + flags: {}, + }); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts index 084f530b2c..ab8cf022d5 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts @@ -4,16 +4,168 @@ import { processCommandNoLock } from "../../../command/command.js"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConfigAction } from "../schema/configActionSchema.js"; -import { AppAction, ActionContext } from "@typeagent/agent-sdk"; +import { + AppAction, + ActionContext, + ActionResult, + ParsedCommandParams, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, + getCommandHandler, + getFlagType, +} from "@typeagent/agent-sdk/helpers/command"; + +type RunConfigCommandAction = ConfigAction & { + actionName: "runConfigCommand"; +}; + +type ConfigActionDependencies = { + processCommand?: typeof processCommandNoLock; + handlers?: CommandHandlerTable; + executeCommand?: typeof executeCommandFromHandlers; +}; + +function parseConfigValue( + value: string | boolean, + type: "string" | "number" | "boolean" | "json", + name: string, +): unknown { + if (type === "string") { + if (typeof value !== "string") { + throw new Error(`Config parameter '${name}' expects a string.`); + } + return value; + } + if (type === "boolean") { + if (typeof value === "boolean") { + return value; + } + if (value === "true" || value === "1") { + return true; + } + if (value === "false" || value === "0") { + return false; + } + throw new Error(`Config parameter '${name}' expects a boolean.`); + } + if (typeof value !== "string") { + throw new Error(`Config parameter '${name}' expects a ${type}.`); + } + if (type === "number") { + const parsed = parseInt(value); + if (parsed.toString() !== value) { + throw new Error(`Config parameter '${name}' expects a number.`); + } + return parsed; + } + const parsed = JSON.parse(value); + if (parsed === null || typeof parsed !== "object") { + throw new Error(`Config parameter '${name}' expects a JSON object.`); + } + return parsed; +} + +function getConfigCommandParams( + action: RunConfigCommandAction, + handlers: CommandHandlerTable, +): ParsedCommandParams | undefined { + const { command, arguments: args = [], flags } = action.parameters; + const handler = getCommandHandler(handlers, command.split(" ")); + if (handler.parameters === undefined || handler.parameters === false) { + const hasFlagValue = + flags !== undefined && + Object.values(flags).some((value) => value !== undefined); + if (args.length > 0 || hasFlagValue) { + throw new Error(`Config command '${command}' takes no parameters.`); + } + return undefined; + } + + const parsedArgs: Record = {}; + let argumentIndex = 0; + for (const [name, definition] of Object.entries( + handler.parameters.args ?? {}, + )) { + const type = definition.type ?? "string"; + if (definition.multiple) { + const values = args.slice(argumentIndex); + if (values.length === 0 && !definition.optional) { + throw new Error(`Missing argument '${name}'.`); + } + if (values.length > 0) { + parsedArgs[name] = values.map((value) => + parseConfigValue(value, type, name), + ); + } + argumentIndex = args.length; + continue; + } + const value = args[argumentIndex]; + if (value === undefined) { + if (!definition.optional) { + throw new Error(`Missing argument '${name}'.`); + } + continue; + } + parsedArgs[name] = parseConfigValue(value, type, name); + argumentIndex++; + } + if (argumentIndex !== args.length) { + throw new Error(`Too many arguments for config command '${command}'.`); + } + + const flagDefinitions = handler.parameters.flags ?? {}; + const suppliedFlags = flags ?? {}; + for (const [name, value] of Object.entries(suppliedFlags)) { + if (value !== undefined && flagDefinitions[name] === undefined) { + throw new Error( + `Config command '${command}' does not accept flag '${name}'.`, + ); + } + } + const parsedFlags: Record = {}; + for (const [name, definition] of Object.entries(flagDefinitions)) { + const value = suppliedFlags[name as keyof typeof suppliedFlags]; + const type = getFlagType(definition); + if (value === undefined) { + if (definition.default !== undefined) { + parsedFlags[name] = structuredClone(definition.default); + } + continue; + } + if (definition.multiple) { + if (!Array.isArray(value)) { + throw new Error(`Config flag '${name}' expects an array.`); + } + parsedFlags[name] = value.map((item) => + parseConfigValue(item, type, name), + ); + } else { + if (Array.isArray(value)) { + throw new Error(`Config flag '${name}' is not repeatable.`); + } + parsedFlags[name] = parseConfigValue(value, type, name); + } + } + + return { + args: handler.parameters.args === undefined ? undefined : parsedArgs, + flags: handler.parameters.flags === undefined ? undefined : parsedFlags, + } as ParsedCommandParams; +} export async function executeConfigAction( action: AppAction, context: ActionContext, -) { + dependencies: ConfigActionDependencies = {}, +): Promise { + const processCommand = dependencies.processCommand ?? processCommandNoLock; const configAction = action as unknown as ConfigAction; switch (configAction.actionName) { case "listAgents": - await processCommandNoLock( + await processCommand( `@config agent`, context.sessionContext.agentContext, ); @@ -23,40 +175,51 @@ export async function executeConfigAction( ? `` : `--off`; - await processCommandNoLock( + await processCommand( `@config agent ${cmdParam} ${configAction.parameters.agentNames.join(" ")}`, context.sessionContext.agentContext, ); break; case "toggleExplanation": - await processCommandNoLock( + await processCommand( `@config explainer ${configAction.parameters.enable ? "on" : "off"}`, context.sessionContext.agentContext, ); break; case "toggleDeveloperMode": - await processCommandNoLock( + await processCommand( `@config dev ${configAction.parameters.enable ? "on" : "off"}`, context.sessionContext.agentContext, ); break; case "enterAgentPriorityMode": - await processCommandNoLock( + await processCommand( `@config agent --priority ${configAction.parameters.agentName}`, context.sessionContext.agentContext, ); break; case "exitAgentPriorityMode": - await processCommandNoLock( + await processCommand( `@config agent --reset`, context.sessionContext.agentContext, ); break; + case "runConfigCommand": + if (dependencies.handlers === undefined) { + throw new Error("Config command handlers are unavailable."); + } + return (dependencies.executeCommand ?? executeCommandFromHandlers)( + dependencies.handlers, + configAction.parameters.command.split(" "), + getConfigCommandParams(configAction, dependencies.handlers), + context, + ); + default: throw new Error(`Invalid action name: ${action.actionName}`); } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts new file mode 100644 index 0000000000..9401d6e770 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { ConstructionAction } from "../schema/constructionActionSchema.js"; + +export function executeConstructionAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, +): Promise { + const execute = (commands: string[], params?: ParsedCommandParams) => + executeCommandFromHandlers(handlers, commands, params, context); + const toggle = (commands: string[], enabled: boolean) => + execute([...commands, enabled ? "on" : "off"]); + + switch (action.actionName) { + case "newConstructionStore": + case "loadConstructionStore": + case "saveConstructionStore": + return execute( + [ + action.actionName === "newConstructionStore" + ? "new" + : action.actionName === "loadConstructionStore" + ? "load" + : "save", + ], + { + args: { + ...(action.parameters?.file === undefined + ? {} + : { file: action.parameters.file }), + }, + flags: {}, + }, + ); + case "setConstructionAutoSave": + return toggle(["auto"], action.parameters.enabled); + case "disableConstructionStore": + return execute(["off"]); + case "showConstructionInfo": + return execute(["info"]); + case "listConstructions": + return execute(["list"], { + args: {}, + flags: { + verbose: action.parameters?.verbose ?? false, + all: action.parameters?.allMatchStrings ?? false, + builtin: action.parameters?.builtIn ?? false, + ...(action.parameters?.match === undefined + ? {} + : { match: action.parameters.match }), + ...(action.parameters?.part === undefined + ? {} + : { part: action.parameters.part }), + ...(action.parameters?.ids === undefined + ? {} + : { id: action.parameters.ids }), + }, + } as unknown as ParsedCommandParams); + case "importConstructions": + return execute(["import"], { + args: { + ...(action.parameters?.files === undefined + ? {} + : { file: action.parameters.files }), + }, + flags: { + extended: action.parameters?.extended ?? false, + }, + } as unknown as ParsedCommandParams); + case "pruneConstructions": + return execute(["prune"]); + case "deleteConstruction": + return execute(["delete"], { + args: { + namespace: action.parameters.namespace, + id: action.parameters.id, + }, + flags: {}, + }); + case "setBuiltInConstructionCache": + return toggle(["builtin"], action.parameters.enabled); + case "setConstructionMerge": + return toggle(["merge"], action.parameters.enabled); + case "setWildcardMatching": + return toggle(["wildcard"], action.parameters.enabled); + case "setEntityWildcardMatching": + return toggle(["wildcard", "entity"], action.parameters.enabled); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts new file mode 100644 index 0000000000..d0219a6c36 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { CopilotAction } from "../schema/copilotActionSchema.js"; + +export function executeCopilotAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, +): Promise { + switch (action.actionName) { + case "importCopilotSessions": + return executeCommandFromHandlers( + handlers, + ["import"], + undefined, + context, + ); + case "fixWithCopilot": + return executeCommandFromHandlers( + handlers, + ["fix"], + { + args: { + ...(action.parameters?.instructions === undefined + ? {} + : { instructions: action.parameters.instructions }), + }, + flags: { + mode: action.parameters?.mode ?? "agent", + "no-screenshot": + action.parameters?.includeScreenshot === false, + "dev-captures": + action.parameters?.devCaptures ?? "auto", + target: action.parameters?.target ?? "native", + "no-send": action.parameters?.autoSend === false, + "reuse-session": + action.parameters?.reuseSession ?? false, + location: action.parameters?.location ?? "editor", + }, + }, + context, + ); + case "loginToCopilot": + return executeCommandFromHandlers( + handlers, + ["login"], + { + args: {}, + flags: { + host: action.parameters?.host ?? "https://github.com", + "no-open": action.parameters?.openBrowser === false, + }, + }, + context, + ); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts new file mode 100644 index 0000000000..e0627f82e7 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { FeedbackAction } from "../schema/feedbackActionSchema.js"; + +export function executeFeedbackAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, +): Promise { + switch (action.actionName) { + case "listFeedback": + return executeCommandFromHandlers( + handlers, + ["list"], + { + args: {}, + flags: { + limit: action.parameters?.limit ?? 20, + all: action.parameters?.includeAllEntries ?? false, + }, + }, + context, + ); + case "summarizeFeedback": + return executeCommandFromHandlers( + handlers, + ["top"], + { + args: {}, + flags: { + limit: action.parameters?.categoryLimit ?? 10, + }, + }, + context, + ); + case "filterFeedback": + return executeCommandFromHandlers( + handlers, + ["filter"], + { + args: {}, + flags: { + ...(action.parameters?.rating === undefined + ? {} + : { rating: action.parameters.rating }), + ...(action.parameters?.category === undefined + ? {} + : { category: action.parameters.category }), + ...(action.parameters?.since === undefined + ? {} + : { since: action.parameters.since }), + ...(action.parameters?.until === undefined + ? {} + : { until: action.parameters.until }), + limit: action.parameters?.limit ?? 50, + all: action.parameters?.includeAllEntries ?? false, + }, + }, + context, + ); + case "exportFeedback": + return executeCommandFromHandlers( + handlers, + ["export"], + { + args: { file: action.parameters.file }, + flags: { + ...(action.parameters.format === undefined + ? {} + : { format: action.parameters.format }), + all: action.parameters.includeAllEntries ?? false, + }, + }, + context, + ); + case "countFeedback": + return executeCommandFromHandlers( + handlers, + ["count"], + undefined, + context, + ); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts index c048354e51..adc904f9cd 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts @@ -6,6 +6,10 @@ import { ActionResult, TypeAgentAction, } from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; import { createActionResultFromTextDisplay, createActionResultFromHtmlDisplay, @@ -17,7 +21,27 @@ import { GrammarAction } from "../schema/grammarActionSchema.js"; export async function executeGrammarAction( action: TypeAgentAction, context: ActionContext, + systemHandlers?: CommandHandlerTable, ): Promise { + if (action.actionName === "scanGrammarCollisions") { + if (systemHandlers === undefined) { + throw new Error("System command handlers are unavailable."); + } + return executeCommandFromHandlers( + systemHandlers, + ["grammar", "collisions"], + { + args: {}, + flags: { + ...(action.parameters?.jsonPath === undefined + ? {} + : { json: action.parameters.jsonPath }), + }, + }, + context, + ); + } + const chc = context.sessionContext.agentContext; const store = chc.persistedGrammarStore; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts index 6ee9432220..233507a187 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts @@ -8,6 +8,8 @@ import { DeleteHistoryAction, HistoryAction, } from "../schema/historyActionSchema.js"; +import { executeCommandFromHandlers } from "@typeagent/agent-sdk/helpers/command"; +import { historyCommandHandlers } from "../handlers/historyCommandHandler.js"; export async function executeHistoryAction( action: AppAction, @@ -34,6 +36,51 @@ export async function executeHistoryAction( context.sessionContext.agentContext, ); break; + case "saveHistory": + await executeCommandFromHandlers( + historyCommandHandlers, + ["save"], + { + args: { file: historyAction.parameters.file }, + flags: undefined, + }, + context, + ); + break; + case "insertHistory": + await executeCommandFromHandlers( + historyCommandHandlers, + ["insert"], + { + args: { + messages: JSON.parse( + historyAction.parameters.messagesJson, + ), + }, + flags: undefined, + } as any, + context, + ); + break; + case "listHistoryEntities": + await executeCommandFromHandlers( + historyCommandHandlers, + ["entities", "list"], + { args: {}, flags: undefined }, + context, + ); + break; + case "deleteHistoryEntity": + await executeCommandFromHandlers( + historyCommandHandlers, + ["entities", "delete"], + { + args: { entityId: historyAction.parameters.entityId }, + flags: undefined, + }, + context, + ); + break; default: throw new Error(`Invalid action name: ${action.actionName}`); } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts new file mode 100644 index 0000000000..c9d68eca95 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { indexCommandHandlers } from "../handlers/indexCommandHandler.js"; +import { IndexAction } from "../schema/indexActionSchema.js"; + +type CommandExecutor = ( + handlers: CommandHandlerTable, + commands: string[], + params: ParsedCommandParams | undefined, + context: ActionContext, +) => Promise; + +export function executeIndexAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable = indexCommandHandlers, + execute: CommandExecutor = executeCommandFromHandlers, +): Promise { + switch (action.actionName) { + case "listIndexes": + return execute( + handlers, + ["list"], + { args: {}, flags: undefined }, + context, + ); + case "showIndexInfo": + return execute( + handlers, + ["info"], + { args: { name: action.parameters.name }, flags: {} }, + context, + ); + case "createIndex": + return execute( + handlers, + ["create"], + { + args: { + type: action.parameters.type, + name: action.parameters.name, + location: action.parameters.location, + }, + flags: {}, + }, + context, + ); + case "deleteIndex": + return execute( + handlers, + ["delete"], + { + args: { name: action.parameters.name }, + flags: undefined, + }, + context, + ); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts new file mode 100644 index 0000000000..21cb236cd0 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { + MemoryAction, + MemoryQuestionParameters, +} from "../schema/memoryActionSchema.js"; + +function questionFlags(parameters: MemoryQuestionParameters) { + return { + asc: parameters.ascending ?? true, + message: parameters.displayMessages ?? false, + knowledge: parameters.displayKnowledge ?? false, + count: parameters.count ?? 25, + distinct: parameters.distinct ?? false, + }; +} + +export function executeMemoryAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, +): Promise { + switch (action.actionName) { + case "setLegacyMemory": + return executeCommandFromHandlers( + handlers, + ["legacy", action.parameters.enabled ? "on" : "off"], + undefined, + context, + ); + case "queryMemory": + return executeCommandFromHandlers( + handlers, + ["query"], + { + args: { terms: action.parameters.terms }, + flags: { + asc: action.parameters.ascending ?? true, + message: action.parameters.displayMessages ?? true, + knowledge: action.parameters.displayKnowledge ?? true, + count: action.parameters.count ?? 25, + distinct: action.parameters.distinct ?? false, + }, + } as unknown as ParsedCommandParams, + context, + ); + case "searchMemory": + case "answerFromMemory": + return executeCommandFromHandlers( + handlers, + [action.actionName === "searchMemory" ? "search" : "answer"], + { + args: { question: action.parameters.question }, + flags: questionFlags(action.parameters), + }, + context, + ); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts index c4dd350df4..33ac99a540 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts @@ -8,6 +8,11 @@ import { } from "../schema/notificationActionSchema.js"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { processCommandNoLock } from "../../../command/command.js"; +import { executeCommandFromHandlers } from "@typeagent/agent-sdk/helpers/command"; +import { + notifyCommandHandlers, + STATUS_NOTICE_DEFAULT_MESSAGE, +} from "../handlers/notifyCommandHandler.js"; export async function executeNotificationAction( action: AppAction, @@ -34,6 +39,39 @@ export async function executeNotificationAction( context.sessionContext.agentContext, ); break; + case "testNotification": + await executeCommandFromHandlers( + notifyCommandHandlers, + ["test"], + { + args: { message: notificationAction.parameters.message }, + flags: { + mode: notificationAction.parameters.mode ?? "toast", + }, + }, + context, + ); + break; + case "testStatusNotice": + await executeCommandFromHandlers( + notifyCommandHandlers, + ["status"], + { + args: { + message: + notificationAction.parameters?.message ?? + STATUS_NOTICE_DEFAULT_MESSAGE, + }, + flags: { + level: + notificationAction.parameters?.level ?? "warning", + restart: + notificationAction.parameters?.restart ?? false, + }, + }, + context, + ); + break; default: throw new Error(`Invalid action name: ${action.actionName}`); } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts new file mode 100644 index 0000000000..6b135852dc --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { SessionAction } from "../schema/sessionActionSchema.js"; + +export function executeSessionAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, +): Promise { + switch (action.actionName) { + case "newSession": + return executeCommandFromHandlers( + handlers, + ["new"], + { + args: {}, + flags: { + keep: action.parameters?.keepSettings ?? false, + ...(action.parameters?.persist === undefined + ? {} + : { persist: action.parameters.persist }), + }, + }, + context, + ); + case "openSession": + return executeCommandFromHandlers( + handlers, + ["open"], + { + args: { session: action.parameters.session }, + flags: undefined, + }, + context, + ); + case "resetSession": + return executeCommandFromHandlers( + handlers, + ["reset"], + undefined, + context, + ); + case "clearSession": + return executeCommandFromHandlers( + handlers, + ["clear"], + undefined, + context, + ); + case "listSessions": + return executeCommandFromHandlers( + handlers, + ["list"], + undefined, + context, + ); + case "deleteSession": + return executeCommandFromHandlers( + handlers, + ["delete"], + { + args: { + ...(action.parameters?.session === undefined + ? {} + : { session: action.parameters.session }), + }, + flags: { all: action.parameters?.all ?? false }, + }, + context, + ); + case "showSessionInfo": + return executeCommandFromHandlers( + handlers, + ["info"], + undefined, + context, + ); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts index 8a8ac873e4..81866c9ef4 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts @@ -12,6 +12,20 @@ export async function executeSettingsAction( ) { const settingsAction = action as unknown as UserSettingsAction; switch (settingsAction.actionName) { + case "showSettings": + await processCommandNoLock( + "@settings show", + context.sessionContext.agentContext, + ); + break; + + case "resetSettings": + await processCommandNoLock( + "@settings reset", + context.sessionContext.agentContext, + ); + break; + case "setServerHidden": await processCommandNoLock( `@settings server hidden ${settingsAction.parameters.enable}`, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts new file mode 100644 index 0000000000..b901a57010 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { SystemDiagnosticsAction } from "../schema/systemDiagnosticsActionSchema.js"; + +type CommandExecutor = ( + handlers: CommandHandlerTable, + commands: string[], + params: ParsedCommandParams | undefined, + context: ActionContext, +) => Promise; + +export function executeSystemDiagnosticsAction( + action: TypeAgentAction, + context: ActionContext, + systemHandlers: CommandHandlerTable, + execute: CommandExecutor = executeCommandFromHandlers, +): Promise { + const handlers = (name: "env" | "token" | "random") => + systemHandlers.commands[name] as CommandHandlerTable; + + switch (action.actionName) { + case "listEnvironmentVariables": + return execute(handlers("env"), ["all"], undefined, context); + case "getEnvironmentVariable": + return execute( + handlers("env"), + ["get"], + { + args: { name: action.parameters.name }, + flags: undefined, + }, + context, + ); + case "showTokenSummary": + return execute(handlers("token"), ["summary"], undefined, context); + case "showTokenDetails": + return execute(handlers("token"), ["details"], undefined, context); + case "runRandomOfflineRequest": + return execute(handlers("random"), ["offline"], undefined, context); + case "runRandomOnlineRequest": + return execute(handlers("random"), ["online"], undefined, context); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts new file mode 100644 index 0000000000..c97f393ae5 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ActionContext, + ActionResult, + ParsedCommandParams, + TypeAgentAction, +} from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { SystemOperationsAction } from "../schema/systemOperationsActionSchema.js"; + +export function executeSystemOperationsAction( + action: TypeAgentAction, + context: ActionContext, + systemHandlers: CommandHandlerTable, +): Promise { + const execute = (commands: string[], params?: ParsedCommandParams) => + executeCommandFromHandlers(systemHandlers, commands, params, context); + + switch (action.actionName) { + case "executeTypedAction": { + const actionParameters = + action.parameters.actionParametersJson === undefined + ? undefined + : JSON.parse(action.parameters.actionParametersJson); + return execute(["action"], { + args: { + schemaName: action.parameters.schemaName, + actionName: action.parameters.actionName, + }, + flags: { + ...(actionParameters === undefined + ? {} + : { parameters: actionParameters }), + ...(action.parameters.naturalLanguage === undefined + ? {} + : { + naturalLanguage: + action.parameters.naturalLanguage, + }), + }, + } as unknown as ParsedCommandParams); + } + case "clearConsole": + return execute(["clear"]); + case "deepClearConsole": + return execute(["clear", "deep"]); + case "startDebugger": + return execute(["debug"]); + case "showQuestionCards": + return execute(["demo", "questionCards"], { + args: {}, + flags: { paged: action.parameters?.paged ?? false }, + }); + case "displayContent": + return execute(["display"], { + args: { text: action.parameters.content }, + flags: { + speak: action.parameters.speak ?? false, + type: action.parameters.type ?? "text", + inline: action.parameters.inline ?? false, + }, + } as unknown as ParsedCommandParams); + case "exitTypeAgent": + return execute(["exit"]); + case "showCommandHelp": + return execute(["help"], { + args: { + ...(action.parameters?.command === undefined + ? {} + : { command: action.parameters.command }), + }, + flags: { all: action.parameters?.all ?? false }, + }); + case "openFolder": + return execute(["open"], { + args: { folder: action.parameters.folder }, + flags: {}, + }); + case "listRegisteredPorts": + return execute(["ports"], { args: {}, flags: {} }); + case "runCommandScript": + return execute(["run"], { + args: { input: action.parameters.input }, + flags: {}, + }); + case "restartAgentServer": + return execute(["server", "restart"]); + case "shutdownAgentServer": + return execute(["shutdown"]); + case "configureTrace": + return execute(["trace"], { + args: { + ...(action.parameters?.namespaces === undefined + ? {} + : { namespaces: action.parameters.namespaces }), + }, + flags: { clear: action.parameters?.clear ?? false }, + } as unknown as ParsedCommandParams); + } +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/actionCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/actionCommandHandler.ts index 830396d897..02a576c39b 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/actionCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/actionCommandHandler.ts @@ -40,6 +40,10 @@ const debugExplain = registerDebug("typeagent:action:explain"); export class ActionCommandHandler implements CommandHandler { public readonly description = "Execute an action"; + public readonly action = { + schema: "system.operations", + actionName: "executeTypedAction", + }; public readonly parameters = { args: { schemaName: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts index 2b6a9425ce..f39e8749c6 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts @@ -54,6 +54,10 @@ const VALID_KINDS: readonly CollisionEventKind[] = [ class CollisionEventsCommandHandler implements CommandHandler { public readonly description = "Show recent collision events captured in the current session's ring buffer"; + public readonly action = { + schema: "system.collision", + actionName: "showCollisionEvents", + }; public readonly parameters = { flags: { limit: { @@ -380,6 +384,10 @@ const SIMILARITY_CACHE_RELATIVE = path.join( class CollisionSimilarCommandHandler implements CommandHandler { public readonly description = "Find semantically similar actions across agents (multi-vector embedding similarity, clusters by default)"; + public readonly action = { + schema: "system.collision", + actionName: "findSimilarActions", + }; public readonly parameters = { flags: { threshold: { @@ -569,6 +577,10 @@ class CollisionSimilarCommandHandler implements CommandHandler { class CollisionSimilarListStrategiesCommandHandler implements CommandHandler { public readonly description = "List the named strategies available for `@collision similar -s `"; + public readonly action = { + schema: "system.collision", + actionName: "listCollisionStrategies", + }; public readonly parameters = {} as const; public async run(context: ActionContext) { @@ -1029,6 +1041,10 @@ const LLM_SELECT_DELTA_DEFAULT = 0.05; class CollisionProbeCommandHandler implements CommandHandler { public readonly description = "Probe what action(s) a hand-crafted utterance would route to via the embedding ranker (top-K with cosine deltas)"; + public readonly action = { + schema: "system.collision", + actionName: "probeCollisionPhrase", + }; public readonly parameters = { flags: { top: { @@ -1270,22 +1286,23 @@ function renderProbeText( return lines; } +export const collisionCommandHandlers: CommandHandlerTable = { + description: + "Inspect collision detection telemetry and run static collision analyses", + defaultSubCommand: "events", + commands: { + events: new CollisionEventsCommandHandler(), + similar: new CollisionSimilarCommandHandler(), + probe: new CollisionProbeCommandHandler(), + corpus: getCollisionCorpusCommandHandlers(), + neighborhoods: new CollisionNeighborhoodsCommandHandler(), + optimize: getCollisionOptimizeCommandHandlers(), + preferences: getCollisionPreferenceCommandHandlers(), + keywords: getCollisionKeywordCommandHandlers(), + "list-strategies": new CollisionSimilarListStrategiesCommandHandler(), + }, +}; + export function getCollisionCommandHandlers(): CommandHandlerTable { - return { - description: - "Inspect collision detection telemetry and run static collision analyses", - defaultSubCommand: "events", - commands: { - events: new CollisionEventsCommandHandler(), - similar: new CollisionSimilarCommandHandler(), - probe: new CollisionProbeCommandHandler(), - corpus: getCollisionCorpusCommandHandlers(), - neighborhoods: new CollisionNeighborhoodsCommandHandler(), - optimize: getCollisionOptimizeCommandHandlers(), - preferences: getCollisionPreferenceCommandHandlers(), - keywords: getCollisionKeywordCommandHandlers(), - "list-strategies": - new CollisionSimilarListStrategiesCommandHandler(), - }, - }; + return collisionCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCorpusHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCorpusHandlers.ts index 1529fd3f57..3b42294b76 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCorpusHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionCorpusHandlers.ts @@ -3608,6 +3608,10 @@ function renderProbeSummaryText(probeFile: ProbeFile, label: string): string[] { class CollisionCorpusGenerateCommandHandler implements CommandHandler { public readonly description = "Generate an LLM-authored phrase corpus for every action in this dispatcher's loaded schemas (slow: ~12 min for the full set)"; + public readonly action = { + schema: "system.collision", + actionName: "generateCollisionCorpus", + }; public readonly parameters = { flags: { schemas: { @@ -3779,6 +3783,10 @@ class CollisionCorpusGenerateCommandHandler implements CommandHandler { class CollisionCorpusProbeCommandHandler implements CommandHandler { public readonly description = "Replay a phrase corpus through the embedding ranker and classify each phrase as CLEAN / TIGHT / MISROUTE"; + public readonly action = { + schema: "system.collision", + actionName: "probeCollisionCorpus", + }; public readonly parameters = { flags: { in: { @@ -3912,6 +3920,10 @@ class CollisionCorpusProbeCommandHandler implements CommandHandler { class CollisionCorpusTranslateCommandHandler implements CommandHandler { public readonly description = "Replay a phrase corpus through the LLM translator (cache/grammar/exec/fuzzy off) and classify each phrase as CLEAN / MISROUTE / CLARIFY / INVALID / ERROR. Distinct from 'corpus probe' — that one runs the embedding ranker; this runs the actual translator."; + public readonly action = { + schema: "system.collision", + actionName: "translateCollisionCorpus", + }; public readonly parameters = { flags: { in: { @@ -4167,6 +4179,10 @@ class CollisionCorpusTranslateCommandHandler implements CommandHandler { // ============================================================================= class CollisionCorpusReanalyzeCommandHandler implements CommandHandler { + public readonly action = { + schema: "system.collision", + actionName: "reanalyzeCollisionCorpus", + }; public readonly description = "Re-classify saved probe results with prefix-aware action matching (recovers misroutes that were just naming differences)"; public readonly parameters = { @@ -4367,6 +4383,10 @@ async function runSimilarityScan( } class CollisionCorpusVisualizeCommandHandler implements CommandHandler { + public readonly action = { + schema: "system.collision", + actionName: "visualizeCollisionCorpus", + }; public readonly description = "Build an interactive HTML visualization of misroute hotspots from reclassified probe results, overlaid with a cross-schema similarity scan"; public readonly parameters = { @@ -4603,6 +4623,10 @@ type RunStep = (typeof RUN_STEPS)[number]; class CollisionCorpusRunCommandHandler implements CommandHandler { public readonly description = "Run the full corpus pipeline (generate → probe → reanalyze → visualize) with consistent file naming"; + public readonly action = { + schema: "system.collision", + actionName: "runCollisionCorpusPipeline", + }; public readonly parameters = { flags: { from: { @@ -5051,6 +5075,10 @@ function renderRecoveryText(analysis: RecoveryAnalysis): string[] { } class CollisionCorpusRecoveryCommandHandler implements CommandHandler { + public readonly action = { + schema: "system.collision", + actionName: "analyzeCollisionRecovery", + }; public readonly description = "Decompose MISROUTE results by where the correct target ranks among the top-K candidates (which fix lever applies?)"; public readonly parameters = { @@ -5118,6 +5146,10 @@ class CollisionCorpusRecoveryCommandHandler implements CommandHandler { const DEFAULT_FILES_RECOVERY_HTML = "recovery-viz.html"; class CollisionCorpusVisualizeRecoveryCommandHandler implements CommandHandler { + public readonly action = { + schema: "system.collision", + actionName: "visualizeCollisionRecovery", + }; public readonly description = "Build an interactive HTML visualization of recovery-rank analysis (which fix lever applies, per action and per agent)"; public readonly parameters = { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionKeywordHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionKeywordHandlers.ts index 2d727246f0..b1791f5c1f 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionKeywordHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionKeywordHandlers.ts @@ -126,6 +126,10 @@ function listAllOverrides(context: ActionContext): void { class CollisionKeywordsCommandHandler implements CommandHandler { public readonly description = "Inspect/tune contextSelector keyword vectors: @collision keywords [ [list|add|remove|clear] [keywords…]]"; + public readonly action = { + schema: "system.collision", + actionName: "manageCollisionKeywords", + }; public readonly parameters = { args: { tokens: { @@ -473,6 +477,10 @@ function formatBackfillSummary( // ones) and invalidates the in-memory index so the fresh vectors take effect on // the next collision without a restart. class CollisionKeywordsBackfillCommandHandler implements CommandHandler { + public readonly action = { + schema: "system.collision", + actionName: "backfillCollisionKeywords", + }; public readonly description = "Backfill/refresh committed keyword files for agent actions. Lexical by default; --llm uses the preferred LLM distillation pass."; public readonly parameters = { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionNeighborhoodHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionNeighborhoodHandlers.ts index 9f5df2f3ee..5a4582a333 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionNeighborhoodHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionNeighborhoodHandlers.ts @@ -66,6 +66,10 @@ interface NeighborhoodsOutput { export class CollisionNeighborhoodsCommandHandler implements CommandHandler { public readonly description = "Build neighborhoods directly from translator misroute edges and write a persisted JSON index plus an HTML viz."; + public readonly action = { + schema: "system.collision", + actionName: "buildCollisionNeighborhoods", + }; public readonly parameters = { flags: { corpus: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionOptimizeHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionOptimizeHandlers.ts index de14dd53a1..728eab02b5 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionOptimizeHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionOptimizeHandlers.ts @@ -64,6 +64,10 @@ const DEFAULT_BASELINE = "translation-results.json"; class CollisionOptimizeListLeversCommandHandler implements CommandHandler { public readonly description = "List all registered optimization levers with their description, consumes, and probeType."; + public readonly action = { + schema: "system.collision", + actionName: "listCollisionOptimizationLevers", + }; public readonly parameters = {} as const; public async run( @@ -117,6 +121,10 @@ class CollisionOptimizeListLeversCommandHandler implements CommandHandler { class CollisionOptimizeExploreCommandHandler implements CommandHandler { public readonly description = "Run the optimize loop on the top-N collision neighborhoods. Writes an attempts archive under /optimization-run-/."; + public readonly action = { + schema: "system.collision", + actionName: "exploreCollisionOptimizations", + }; public readonly parameters = { flags: { corpus: { @@ -437,6 +445,10 @@ function parseSeverities( class CollisionOptimizeValidateCommandHandler implements CommandHandler { public readonly description = "Stack all winners from an optimization run and re-probe the full baseline corpus. Emits optimization-impact.{json,html} with cross-neighborhood regression flags."; + public readonly action = { + schema: "system.collision", + actionName: "validateCollisionOptimizations", + }; public readonly parameters = { flags: { run: { @@ -567,6 +579,10 @@ class CollisionOptimizeValidateCommandHandler implements CommandHandler { class CollisionOptimizePatternsCommandHandler implements CommandHandler { public readonly description = "Mine patterns.jsonl across all accumulated optimize runs. Emits patterns.{json,html} with three groupings (mechanism × pattern, per-lever, lever-effectiveness) plus classifier agreement."; + public readonly action = { + schema: "system.collision", + actionName: "mineCollisionOptimizationPatterns", + }; public readonly parameters = { flags: { "patterns-file": { @@ -689,6 +705,10 @@ class CollisionOptimizePatternsCommandHandler implements CommandHandler { class CollisionOptimizeRunCommandHandler implements CommandHandler { public readonly description = "Run the full optimize pipeline (neighborhoods → explore → validate → patterns → distill) with --from gating. Each step's predecessor must exist before it runs."; + public readonly action = { + schema: "system.collision", + actionName: "runCollisionOptimizationPipeline", + }; public readonly parameters = { flags: { from: { @@ -822,6 +842,10 @@ class CollisionOptimizeRunCommandHandler implements CommandHandler { class CollisionOptimizeDistillCommandHandler implements CommandHandler { public readonly description = "Distill winning attempts in patterns.jsonl into candidate schemaGuidelines additions. Groups winners by (mechanism, guidelineHook), calls the LLM with the current schemaGuidelines as context, writes schemaGuidelines.candidates.md for operator review."; + public readonly action = { + schema: "system.collision", + actionName: "distillCollisionOptimizationPatterns", + }; public readonly parameters = { flags: { "min-attempts": { @@ -901,6 +925,10 @@ class CollisionOptimizeDistillCommandHandler implements CommandHandler { class CollisionOptimizeBrowseCommandHandler implements CommandHandler { public readonly description = "Generate browse.html for one or more optimization-run-* directories. Walks the run, writes a sortable case index plus a self-contained case.html per case showing every attempt with before/after diffs."; + public readonly action = { + schema: "system.collision", + actionName: "browseCollisionOptimizationRuns", + }; public readonly parameters = { flags: { run: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionPreferenceHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionPreferenceHandlers.ts index d4616c4bab..e3a014fe44 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionPreferenceHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/collisionPreferenceHandlers.ts @@ -41,6 +41,10 @@ function memberLabel(m: PreferenceMember): string { class CollisionPreferenceListCommandHandler implements CommandHandler { public readonly description = "List stored collision preferences (Tier-1)"; + public readonly action = { + schema: "system.collision", + actionName: "listCollisionPreferences", + }; public readonly parameters = {} as const; public async run(context: ActionContext) { @@ -64,6 +68,10 @@ class CollisionPreferenceListCommandHandler implements CommandHandler { class CollisionPreferenceSetCommandHandler implements CommandHandler { public readonly description = "Set an explicit collision preference: among a candidate set, always pick the chosen option"; + public readonly action = { + schema: "system.collision", + actionName: "setCollisionPreference", + }; public readonly parameters = { args: { candidates: { @@ -141,6 +149,10 @@ class CollisionPreferenceSetCommandHandler implements CommandHandler { class CollisionPreferenceRemoveCommandHandler implements CommandHandler { public readonly description = "Remove a stored collision preference by key (see `@collision preferences list`)"; + public readonly action = { + schema: "system.collision", + actionName: "removeCollisionPreference", + }; public readonly parameters = { args: { key: { @@ -167,6 +179,10 @@ class CollisionPreferenceRemoveCommandHandler implements CommandHandler { class CollisionPreferenceClearCommandHandler implements CommandHandler { public readonly description = "Remove every stored collision preference"; + public readonly action = { + schema: "system.collision", + actionName: "clearCollisionPreferences", + }; public readonly parameters = {} as const; public async run(context: ActionContext) { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts index 89ba88428c..53beca7895 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts @@ -3298,102 +3298,131 @@ class DevModeOnCommandHandler implements CommandHandler { } } -export function getConfigCommandHandlers(): CommandHandlerTable { - return { - description: "Configuration commands", - commands: { - schema: new AgentToggleCommandHandler(AgentToggle.Schema), - action: new AgentToggleCommandHandler(AgentToggle.Action), - command: new AgentToggleCommandHandler(AgentToggle.Command), - agent: { - description: "Manage agents (enable/disable, setup, refresh)", - defaultSubCommand: new AgentToggleCommandHandler( - AgentToggle.Agent, - ), - commands: { - setup: new AgentSetupCommandHandler(), - refresh: new AgentRefreshCommandHandler(), - }, +const configCommandAction = { + schema: "system.config", + actionName: "runConfigCommand", +} as const; + +type ConfigCommandDefinition = CommandHandlerTable["commands"][string]; + +function addConfigActionLink(definition: ConfigCommandDefinition): void { + if ("commands" in definition) { + for (const command of Object.values(definition.commands)) { + addConfigActionLink(command); + } + if ( + definition.defaultSubCommand !== undefined && + typeof definition.defaultSubCommand !== "string" + ) { + addConfigActionLink(definition.defaultSubCommand); + } + return; + } + definition.action ??= configCommandAction; +} + +function addConfigActionLinks(table: CommandHandlerTable): CommandHandlerTable { + for (const command of Object.values(table.commands)) { + addConfigActionLink(command); + } + return table; +} + +export const configCommandHandlers: CommandHandlerTable = addConfigActionLinks({ + description: "Configuration commands", + commands: { + schema: new AgentToggleCommandHandler(AgentToggle.Schema), + action: new AgentToggleCommandHandler(AgentToggle.Action), + command: new AgentToggleCommandHandler(AgentToggle.Command), + agent: { + description: "Manage agents (enable/disable, setup, refresh)", + defaultSubCommand: new AgentToggleCommandHandler(AgentToggle.Agent), + commands: { + setup: new AgentSetupCommandHandler(), + refresh: new AgentRefreshCommandHandler(), }, - request: new ConfigRequestCommandHandler(), - scrub: getToggleHandlerTable( - "outbound secret scrubbing", - async (_context, enable: boolean) => { - setEgressSecretRedactionEnabled(enable); - }, - ), - match: { - description: "Configure match behavior", - commands: { - grammar: getToggleHandlerTable( - "grammar cache usage", - async (context, enable: boolean) => { - await changeContextConfig( - { cache: { grammar: enable } }, - context, - ); - }, - ), - }, + }, + request: new ConfigRequestCommandHandler(), + scrub: getToggleHandlerTable( + "outbound secret scrubbing", + async (_context, enable: boolean) => { + setEgressSecretRedactionEnabled(enable); }, - cache: { - description: "Configure cache behavior", - commands: { - grammarSystem: new GrammarSystemCommandHandler(), - useDFA: new GrammarUseDFACommandHandler(), - }, + ), + match: { + description: "Configure match behavior", + commands: { + grammar: getToggleHandlerTable( + "grammar cache usage", + async (context, enable: boolean) => { + await changeContextConfig( + { cache: { grammar: enable } }, + context, + ); + }, + ), }, - translation: configTranslationCommandHandlers, - explainer: configExplainerCommandHandlers, - execution: configExecutionCommandHandlers, - modelProvider: new ConfigModelProviderCommandHandler(), - dev: { - description: "Toggle development mode", - defaultSubCommand: "on", - commands: { - on: new DevModeOnCommandHandler(), - off: { - description: "Turn off development mode", - run: async ( - context: ActionContext, - ) => { - const systemContext = - context.sessionContext.agentContext; - systemContext.developerMode = false; - systemContext.confirmActions = false; - systemContext.clientIO.notify( - undefined, - "developerMode", - { enabled: false }, - "dispatcher", - ); - displaySuccess( - "development mode is disabled.", - context, - ); - }, + }, + cache: { + description: "Configure cache behavior", + commands: { + grammarSystem: new GrammarSystemCommandHandler(), + useDFA: new GrammarUseDFACommandHandler(), + }, + }, + translation: configTranslationCommandHandlers, + explainer: configExplainerCommandHandlers, + execution: configExecutionCommandHandlers, + modelProvider: new ConfigModelProviderCommandHandler(), + dev: { + description: "Toggle development mode", + defaultSubCommand: "on", + commands: { + on: new DevModeOnCommandHandler(), + off: { + description: "Turn off development mode", + run: async ( + context: ActionContext, + ) => { + const systemContext = + context.sessionContext.agentContext; + systemContext.developerMode = false; + systemContext.confirmActions = false; + systemContext.clientIO.notify( + undefined, + "developerMode", + { enabled: false }, + "dispatcher", + ); + displaySuccess( + "development mode is disabled.", + context, + ); }, }, }, - log: { - description: "Toggle logging", - commands: { - db: getToggleHandlerTable( - "logging", - async (context, enable) => { - // Honor the toggle: previously hardcoded to - // false regardless of `enable`, which made - // `@config log db on` a no-op and blocked - // every collision-rollout experiment from - // uploading to Cosmos. - context.sessionContext.agentContext.dblogging = - enable; - }, - ), - }, + }, + log: { + description: "Toggle logging", + commands: { + db: getToggleHandlerTable( + "logging", + async (context, enable) => { + // Honor the toggle: previously hardcoded to + // false regardless of `enable`, which made + // `@config log db on` a no-op and blocked + // every collision-rollout experiment from + // uploading to Cosmos. + context.sessionContext.agentContext.dblogging = enable; + }, + ), }, - - collision: getCollisionCommandHandlers(), }, - }; + + collision: getCollisionCommandHandlers(), + }, +}); + +export function getConfigCommandHandlers(): CommandHandlerTable { + return configCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/constructionCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/constructionCommandHandlers.ts index f3de7fd471..da5c3e205b 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/constructionCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/constructionCommandHandlers.ts @@ -80,6 +80,10 @@ function resolvePathWithSession( class ConstructionNewCommandHandler implements CommandHandler { public readonly description = "Create a new construction store"; + public readonly action = { + schema: "system.construction", + actionName: "newConstructionStore", + }; public readonly parameters = { args: { file: { @@ -118,6 +122,10 @@ class ConstructionNewCommandHandler implements CommandHandler { class ConstructionLoadCommandHandler implements CommandHandler { public readonly description = "Load a construction store from disk"; + public readonly action = { + schema: "system.construction", + actionName: "loadConstructionStore", + }; public readonly parameters = { args: { file: { @@ -160,6 +168,10 @@ class ConstructionLoadCommandHandler implements CommandHandler { class ConstructionSaveCommandHandler implements CommandHandler { public readonly description = "Save construction store to disk"; + public readonly action = { + schema: "system.construction", + actionName: "saveConstructionStore", + }; public readonly parameters = { args: { file: { @@ -192,6 +204,10 @@ class ConstructionSaveCommandHandler implements CommandHandler { class ConstructionInfoCommandHandler implements CommandHandlerNoParams { public readonly description = "Show current construction store info"; + public readonly action = { + schema: "system.construction", + actionName: "showConstructionInfo", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; const info = systemContext.agentCache.getInfo(); @@ -234,6 +250,10 @@ class ConstructionInfoCommandHandler implements CommandHandlerNoParams { class ConstructionOffCommandHandler implements CommandHandlerNoParams { public readonly description = "Disable construction store"; + public readonly action = { + schema: "system.construction", + actionName: "disableConstructionStore", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; const constructionStore = systemContext.agentCache.constructionStore; @@ -245,6 +265,10 @@ class ConstructionOffCommandHandler implements CommandHandlerNoParams { class ConstructionListCommandHandler implements CommandHandler { public readonly description = "List constructions"; + public readonly action = { + schema: "system.construction", + actionName: "listConstructions", + }; public readonly parameters = { flags: { verbose: { @@ -319,6 +343,10 @@ async function expandPaths(paths: string[]) { class ConstructionImportCommandHandler implements CommandHandler { public readonly description = "Import constructions from test data"; + public readonly action = { + schema: "system.construction", + actionName: "importConstructions", + }; public readonly parameters = { flags: { extended: { @@ -408,6 +436,10 @@ class ConstructionImportCommandHandler implements CommandHandler { class ConstructionPruneCommandHandler implements CommandHandlerNoParams { public readonly description = "Prune out of date construction from the cache"; + public readonly action = { + schema: "system.construction", + actionName: "pruneConstructions", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; const count = await systemContext.agentCache.prune(); @@ -417,6 +449,10 @@ class ConstructionPruneCommandHandler implements CommandHandlerNoParams { class ConstructionDeleteCommandHandler implements CommandHandler { public readonly description = "Delete a construction by id"; + public readonly action = { + schema: "system.construction", + actionName: "deleteConstruction", + }; public readonly parameters = { args: { namespace: { @@ -439,81 +475,103 @@ class ConstructionDeleteCommandHandler implements CommandHandler { } } -export function getConstructionCommandHandlers(): CommandHandlerTable { - return { - description: "Command to manage the construction store", - commands: { - new: new ConstructionNewCommandHandler(), - load: new ConstructionLoadCommandHandler(), - save: new ConstructionSaveCommandHandler(), - auto: getToggleHandlerTable( - "construction auto save", - async (context, enable) => { - await changeContextConfig( - { cache: { autoSave: enable } }, - context, - ); - }, - ), - off: new ConstructionOffCommandHandler(), - info: new ConstructionInfoCommandHandler(), - list: new ConstructionListCommandHandler(), - import: new ConstructionImportCommandHandler(), - prune: new ConstructionPruneCommandHandler(), - delete: new ConstructionDeleteCommandHandler(), - builtin: getToggleHandlerTable( - "construction built-in cache", - async (context, enable) => { - await changeContextConfig( - { cache: { builtInCache: enable } }, - context, - ); - }, - ), - merge: getToggleHandlerTable( - "construction merge", - async ( - context: ActionContext, - enable: boolean, - ) => { - await changeContextConfig( - { cache: { mergeMatchSets: enable } }, - context, - ); - }, - ), - wildcard: { - description: "wildcard matching", - defaultSubCommand: "on", - commands: { - ...getToggleCommandHandlers( - "wildcard matching", - async ( - context: ActionContext, - enable: boolean, - ) => { - await changeContextConfig( - { cache: { matchWildcard: enable } }, - context, - ); - }, - ), - entity: getToggleHandlerTable( - "entity wildcard matching", - async ( - context: ActionContext, - enable: boolean, - ) => { - await changeContextConfig( - { - cache: { matchEntityWildcard: enable }, - }, - context, - ); - }, - ), - }, +export const constructionCommandHandlers: CommandHandlerTable = { + description: "Command to manage the construction store", + commands: { + new: new ConstructionNewCommandHandler(), + load: new ConstructionLoadCommandHandler(), + save: new ConstructionSaveCommandHandler(), + auto: getToggleHandlerTable( + "construction auto save", + async (context, enable) => { + await changeContextConfig( + { cache: { autoSave: enable } }, + context, + ); + }, + { + schema: "system.construction", + actionName: "setConstructionAutoSave", + }, + ), + off: new ConstructionOffCommandHandler(), + info: new ConstructionInfoCommandHandler(), + list: new ConstructionListCommandHandler(), + import: new ConstructionImportCommandHandler(), + prune: new ConstructionPruneCommandHandler(), + delete: new ConstructionDeleteCommandHandler(), + builtin: getToggleHandlerTable( + "construction built-in cache", + async (context, enable) => { + await changeContextConfig( + { cache: { builtInCache: enable } }, + context, + ); + }, + { + schema: "system.construction", + actionName: "setBuiltInConstructionCache", + }, + ), + merge: getToggleHandlerTable( + "construction merge", + async ( + context: ActionContext, + enable: boolean, + ) => { + await changeContextConfig( + { cache: { mergeMatchSets: enable } }, + context, + ); + }, + { + schema: "system.construction", + actionName: "setConstructionMerge", + }, + ), + wildcard: { + description: "wildcard matching", + defaultSubCommand: "on", + commands: { + ...getToggleCommandHandlers( + "wildcard matching", + async ( + context: ActionContext, + enable: boolean, + ) => { + await changeContextConfig( + { cache: { matchWildcard: enable } }, + context, + ); + }, + { + schema: "system.construction", + actionName: "setWildcardMatching", + }, + ), + entity: getToggleHandlerTable( + "entity wildcard matching", + async ( + context: ActionContext, + enable: boolean, + ) => { + await changeContextConfig( + { + cache: { matchEntityWildcard: enable }, + }, + context, + ); + }, + { + schema: "system.construction", + actionName: "setEntityWildcardMatching", + }, + ), }, }, - }; + }, +}; + +export function getConstructionCommandHandlers(): CommandHandlerTable { + return constructionCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/copilotCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/copilotCommandHandlers.ts index 0c4dad364a..29c870de55 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/copilotCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/copilotCommandHandlers.ts @@ -28,6 +28,10 @@ import { askYesNoWithContext } from "../../interactiveIO.js"; class CopilotImportCommandHandler implements CommandHandlerNoParams { public readonly description = "Import GitHub Copilot Chat sessions as conversation mirrors"; + public readonly action = { + schema: "system.copilot", + actionName: "importCopilotSessions", + }; public async run(context: ActionContext) { const importCopilot = context.sessionContext.agentContext.copilotImport; if (importCopilot === undefined) { @@ -229,6 +233,10 @@ function describeAttachments( class FixWithCopilotCommandHandler implements CommandHandler { public readonly description = "Hand the current conversation to GitHub Copilot Chat in VS Code to diagnose and fix"; + public readonly action = { + schema: "system.copilot", + actionName: "fixWithCopilot", + }; public readonly parameters = { args: { instructions: { @@ -452,6 +460,10 @@ function openUrl(url: string): void { class CopilotLoginCommandHandler implements CommandHandler { public readonly description = "Sign in to GitHub Copilot via the browser device flow"; + public readonly action = { + schema: "system.copilot", + actionName: "loginToCopilot", + }; public readonly parameters = { flags: { host: { @@ -657,14 +669,16 @@ class CopilotLoginCommandHandler implements CommandHandler { } } +export const copilotCommandHandlers: CommandHandlerTable = { + description: "GitHub Copilot session commands", + defaultSubCommand: "import", + commands: { + import: new CopilotImportCommandHandler(), + fix: new FixWithCopilotCommandHandler(), + login: new CopilotLoginCommandHandler(), + }, +}; + export function getCopilotCommandHandlers(): CommandHandlerTable { - return { - description: "GitHub Copilot session commands", - defaultSubCommand: "import", - commands: { - import: new CopilotImportCommandHandler(), - fix: new FixWithCopilotCommandHandler(), - login: new CopilotLoginCommandHandler(), - }, - }; + return copilotCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/debugCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/debugCommandHandlers.ts index daa3b1ed4a..ca29e2dc16 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/debugCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/debugCommandHandlers.ts @@ -13,6 +13,10 @@ import { export class DebugCommandHandler implements CommandHandlerNoParams { public readonly description = "Start node inspector"; + public readonly action = { + schema: "system.operations", + actionName: "startDebugger", + }; private debugging = false; public async run(context: ActionContext) { if (this.debugging) { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/demoCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/demoCommandHandlers.ts index ada4b43755..83b499985a 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/demoCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/demoCommandHandlers.ts @@ -129,6 +129,10 @@ function summaryContent(response: QuestionFormResponse): DisplayContent { export class QuestionCardsCommandHandler implements CommandHandler { public readonly description = "Walk the interactive question types (single-select, multi-select, yes/no, free-text). Add --paged for a one-at-a-time Back/Next wizard."; + public readonly action = { + schema: "system.operations", + actionName: "showQuestionCards", + }; public readonly parameters = { flags: { paged: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/displayCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/displayCommandHandler.ts index 10360c4cc1..5e08b992ea 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/displayCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/displayCommandHandler.ts @@ -7,6 +7,10 @@ import { CommandHandlerContext } from "../../commandHandlerContext.js"; export class DisplayCommandHandler implements CommandHandler { public readonly description = "Send text to display"; + public readonly action = { + schema: "system.operations", + actionName: "displayContent", + }; public readonly parameters = { flags: { speak: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/envCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/envCommandHandler.ts index 0380d609fe..9dfd7e89a4 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/envCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/envCommandHandler.ts @@ -16,6 +16,10 @@ import { export class EnvCommandHandler implements CommandHandlerNoParams { public readonly description = "Echos environment variables to the user interface."; + public readonly action = { + schema: "system.diagnostics", + actionName: "listEnvironmentVariables", + }; public async run(context: ActionContext) { const table: string[][] = [["Variable Name", "Value"]]; @@ -45,6 +49,10 @@ export class EnvCommandHandler implements CommandHandlerNoParams { export class EnvVarCommandHandler implements CommandHandler { public readonly description: string = "Echos the value of a named environment variable to the user interface"; + public readonly action = { + schema: "system.diagnostics", + actionName: "getEnvironmentVariable", + }; public readonly parameters = { args: { name: { @@ -67,13 +75,15 @@ export class EnvVarCommandHandler implements CommandHandler { } } +export const envCommandHandlers: CommandHandlerTable = { + description: "Environment variable commands", + defaultSubCommand: "all", + commands: { + all: new EnvCommandHandler(), + get: new EnvVarCommandHandler(), + }, +}; + export function getEnvCommandHandlers(): CommandHandlerTable { - return { - description: "Environment variable commands", - defaultSubCommand: "all", - commands: { - all: new EnvCommandHandler(), - get: new EnvVarCommandHandler(), - }, - }; + return envCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/feedbackCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/feedbackCommandHandlers.ts index f393686a18..2dd893c135 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/feedbackCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/feedbackCommandHandlers.ts @@ -73,6 +73,10 @@ function fmtEntry(e: UserFeedbackEntry): string { class FeedbackListCommandHandler implements CommandHandler { public readonly description = "List recent user-feedback entries (most recent first)."; + public readonly action = { + schema: "system.feedback", + actionName: "listFeedback", + }; public readonly parameters = { flags: { limit: { @@ -117,6 +121,10 @@ class FeedbackListCommandHandler implements CommandHandler { class FeedbackTopCommandHandler implements CommandHandler { public readonly description = "Aggregate user feedback — counts by rating and category."; + public readonly action = { + schema: "system.feedback", + actionName: "summarizeFeedback", + }; public readonly parameters = { flags: { limit: { @@ -187,6 +195,10 @@ const categoryValues = [ class FeedbackFilterCommandHandler implements CommandHandler { public readonly description = "Filter feedback by rating, category, and/or date range."; + public readonly action = { + schema: "system.feedback", + actionName: "filterFeedback", + }; public readonly parameters = { flags: { rating: { @@ -297,6 +309,10 @@ class FeedbackFilterCommandHandler implements CommandHandler { class FeedbackExportCommandHandler implements CommandHandler { public readonly description = "Export user-feedback entries to a local file (JSON or JSONL)."; + public readonly action = { + schema: "system.feedback", + actionName: "exportFeedback", + }; public readonly parameters = { args: { file: { @@ -354,6 +370,10 @@ class FeedbackExportCommandHandler implements CommandHandler { // --------------------------------------------------------------------------- class FeedbackCountCommandHandler implements CommandHandlerNoParams { public readonly description = "Show the total number of feedback entries."; + public readonly action = { + schema: "system.feedback", + actionName: "countFeedback", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; const all = getAllFeedback(systemContext); @@ -365,16 +385,18 @@ class FeedbackCountCommandHandler implements CommandHandlerNoParams { } } +export const feedbackCommandHandlers: CommandHandlerTable = { + description: "Inspect and export user-feedback entries", + defaultSubCommand: "list", + commands: { + list: new FeedbackListCommandHandler(), + top: new FeedbackTopCommandHandler(), + filter: new FeedbackFilterCommandHandler(), + export: new FeedbackExportCommandHandler(), + count: new FeedbackCountCommandHandler(), + }, +}; + export function getFeedbackCommandHandlers(): CommandHandlerTable { - return { - description: "Inspect and export user-feedback entries", - defaultSubCommand: "list", - commands: { - list: new FeedbackListCommandHandler(), - top: new FeedbackTopCommandHandler(), - filter: new FeedbackFilterCommandHandler(), - export: new FeedbackExportCommandHandler(), - count: new FeedbackCountCommandHandler(), - }, - }; + return feedbackCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts index 362b23a4f6..b9de3c29fd 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts @@ -169,6 +169,10 @@ class GrammarClearCommandHandler implements CommandHandler { class GrammarCollisionsCommandHandler implements CommandHandler { public readonly description = "Scan all loaded agent grammars for cross-agent collisions, with concrete witness inputs"; + public readonly action = { + schema: "system.grammar", + actionName: "scanGrammarCollisions", + }; public readonly parameters = { flags: { json: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts index 2b0423df70..32ed9ced46 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts @@ -22,6 +22,10 @@ import { export class HelpCommandHandler implements CommandHandler { public readonly description = "Show help"; + public readonly action = { + schema: "system.operations", + actionName: "showCommandHelp", + }; public readonly defaultSubCommand = "command"; public readonly parameters = { args: { 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 0544ea24d2..4c995adeca 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts @@ -87,6 +87,7 @@ class HistoryDeleteCommandHandler implements CommandHandler { class HistorySaveCommandHandler implements CommandHandler { public readonly description: string = "Save the chat history to a file"; + public readonly action = "saveHistory"; public readonly parameters = { args: { file: { @@ -126,6 +127,7 @@ class HistorySaveCommandHandler implements CommandHandler { class HistoryInsertCommandHandler implements CommandHandler { public readonly description = "Insert messages to chat history"; + public readonly action = "insertHistory"; public readonly parameters = { args: { messages: { @@ -178,6 +180,7 @@ class HistoryInsertCommandHandler implements CommandHandler { class HistoryEntityListCommandHandler implements CommandHandler { public readonly description = "Shows all of the entities currently in 'working memory.'"; + public readonly action = "listHistoryEntities"; public readonly parameters = {} as const; public async run( @@ -200,6 +203,7 @@ class HistoryEntityListCommandHandler implements CommandHandler { class HistoryEntityDeleteCommandHandler implements CommandHandler { public readonly description = "Delete entities from the chat history (working memory)."; + public readonly action = "deleteHistoryEntity"; public readonly parameters = { args: { entityId: { @@ -230,24 +234,26 @@ class HistoryEntityDeleteCommandHandler implements CommandHandler { } } -export function getHistoryCommandHandlers(): CommandHandlerTable { - return { - description: "History commands", - defaultSubCommand: "list", - commands: { - list: new HistoryListCommandHandler(), - clear: new HistoryClearCommandHandler(), - delete: new HistoryDeleteCommandHandler(), - insert: new HistoryInsertCommandHandler(), - save: new HistorySaveCommandHandler(), - entities: { - description: "History entity commands", - defaultSubCommand: "list", - commands: { - list: new HistoryEntityListCommandHandler(), - delete: new HistoryEntityDeleteCommandHandler(), - }, +export const historyCommandHandlers: CommandHandlerTable = { + description: "History commands", + defaultSubCommand: "list", + commands: { + list: new HistoryListCommandHandler(), + clear: new HistoryClearCommandHandler(), + delete: new HistoryDeleteCommandHandler(), + insert: new HistoryInsertCommandHandler(), + save: new HistorySaveCommandHandler(), + entities: { + description: "History entity commands", + defaultSubCommand: "list", + commands: { + list: new HistoryEntityListCommandHandler(), + delete: new HistoryEntityDeleteCommandHandler(), }, }, - }; + }, +}; + +export function getHistoryCommandHandlers(): CommandHandlerTable { + return historyCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/indexCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/indexCommandHandler.ts index c5f7eb81d6..6d6724ddda 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/indexCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/indexCommandHandler.ts @@ -18,6 +18,10 @@ import { expandHome } from "../../../utils/fsUtils.js"; class IndexListCommandHandler implements CommandHandler { public readonly description = "List indexes"; + public readonly action = { + schema: "system.index", + actionName: "listIndexes", + }; public readonly parameters = {} as const; public async run( @@ -48,6 +52,10 @@ class IndexListCommandHandler implements CommandHandler { class IndexInfoCommandHandler implements CommandHandler { public readonly description = "Show index details"; + public readonly action = { + schema: "system.index", + actionName: "showIndexInfo", + }; public readonly parameters = { flags: {}, args: { @@ -90,6 +98,10 @@ class IndexInfoCommandHandler implements CommandHandler { class IndexCreateCommandHandler implements CommandHandler { public readonly description = "Create a new index"; + public readonly action = { + schema: "system.index", + actionName: "createIndex", + }; public readonly parameters = { flags: {}, args: { @@ -154,6 +166,10 @@ class IndexCreateCommandHandler implements CommandHandler { class IndexDeleteCommandHandler implements CommandHandler { public readonly description = "Delete an index"; + public readonly action = { + schema: "system.index", + actionName: "deleteIndex", + }; public readonly parameters = { args: { name: { @@ -190,18 +206,20 @@ class IndexDeleteCommandHandler implements CommandHandler { /* * Gets all of the available indexing commands */ +export const indexCommandHandlers: CommandHandlerTable = { + description: "Indexing commands", + defaultSubCommand: "list", + commands: { + list: new IndexListCommandHandler(), + create: new IndexCreateCommandHandler(), + delete: new IndexDeleteCommandHandler(), + info: new IndexInfoCommandHandler(), + // TODO: implement + // rebuild: new IndexRebuildCommandHandler(), // is this necessary? + // watch: new IndexWatchCommandHandler(), // Toggle file watching + }, +}; + export function getIndexCommandHandlers(): CommandHandlerTable { - return { - description: "Indexing commands", - defaultSubCommand: "list", - commands: { - list: new IndexListCommandHandler(), - create: new IndexCreateCommandHandler(), - delete: new IndexDeleteCommandHandler(), - info: new IndexInfoCommandHandler(), - // TODO: implement - // rebuild: new IndexRebuildCommandHandler(), // is this necessary? - // watch: new IndexWatchCommandHandler(), // Toggle file watching - }, - }; + return indexCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts index 58793cf53f..4f643135ac 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts @@ -20,6 +20,7 @@ import { DispatcherName } from "../../dispatcher/dispatcherUtils.js"; class NotifyInfoCommandHandler implements CommandHandlerNoParams { description: string = "Shows the number of notifications available"; + public readonly action = "showNotificationSummary"; help?: string; public async run( context: ActionContext, @@ -36,6 +37,7 @@ class NotifyInfoCommandHandler implements CommandHandlerNoParams { class NotifyClearCommandHandler implements CommandHandlerNoParams { description: string = "Clears notifications"; + public readonly action = "clearNotifications"; help?: string; public async run( context: ActionContext, @@ -52,6 +54,7 @@ class NotifyClearCommandHandler implements CommandHandlerNoParams { class NotifyShowUnreadCommandHandler implements CommandHandlerNoParams { description: string = "Shows unread notifications"; + public readonly action = "showNotifications"; help?: string; public async run( context: ActionContext, @@ -68,6 +71,7 @@ class NotifyShowUnreadCommandHandler implements CommandHandlerNoParams { class NotifyShowAllCommandHandler implements CommandHandlerNoParams { description: string = "Shows all notifications"; + public readonly action = "showNotifications"; help?: string; public async run( @@ -96,9 +100,13 @@ const NOTIFY_TEST_MODES = { type NotifyTestMode = keyof typeof NOTIFY_TEST_MODES; +export const STATUS_NOTICE_DEFAULT_MESSAGE = + "Dismissing this collapses it to the notification bell; click the bell to re-expand."; + class NotifyTestCommandHandler implements CommandHandler { public readonly description = "Fire a synthetic notification through the channel — for verifying chat rendering without an agent"; + public readonly action = "testNotification"; public readonly parameters = { args: { message: { @@ -148,6 +156,7 @@ class NotifyTestCommandHandler implements CommandHandler { class NotifyStatusTestCommandHandler implements CommandHandler { public readonly description = "Fire a persistent status notice (a toast that collapses to the notification bell) to verify the chat-ui affordance without a stale server"; + public readonly action = "testStatusNotice"; public readonly parameters = { args: { message: { @@ -193,9 +202,7 @@ class NotifyStatusTestCommandHandler implements CommandHandler { id: "notify-test-status", level, title: "Test status notice", - message: - params.args.message ?? - "Dismissing this collapses it to the notification bell; click the bell to re-expand.", + message: params.args.message ?? STATUS_NOTICE_DEFAULT_MESSAGE, }; if (params.flags.restart) { notice.actionLabel = "Restart server"; @@ -214,23 +221,25 @@ class NotifyStatusTestCommandHandler implements CommandHandler { } } -export function getNotifyCommandHandlers(): CommandHandlerTable { - return { - description: "Notify commands", - defaultSubCommand: "info", - commands: { - info: new NotifyInfoCommandHandler(), - clear: new NotifyClearCommandHandler(), - test: new NotifyTestCommandHandler(), - status: new NotifyStatusTestCommandHandler(), - show: { - description: "Show notifications", - defaultSubCommand: "unread", - commands: { - unread: new NotifyShowUnreadCommandHandler(), - all: new NotifyShowAllCommandHandler(), - }, +export const notifyCommandHandlers: CommandHandlerTable = { + description: "Notify commands", + defaultSubCommand: "info", + commands: { + info: new NotifyInfoCommandHandler(), + clear: new NotifyClearCommandHandler(), + test: new NotifyTestCommandHandler(), + status: new NotifyStatusTestCommandHandler(), + show: { + description: "Show notifications", + defaultSubCommand: "unread", + commands: { + unread: new NotifyShowUnreadCommandHandler(), + all: new NotifyShowAllCommandHandler(), }, }, - }; + }, +}; + +export function getNotifyCommandHandlers(): CommandHandlerTable { + return notifyCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/openCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/openCommandHandler.ts index a95ce43eb3..415c78fbd4 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/openCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/openCommandHandler.ts @@ -14,6 +14,10 @@ import path from "node:path"; export class OpenCommandHandler implements CommandHandler { public readonly description = "Shortcut for opening system related folders"; + public readonly action = { + schema: "system.operations", + actionName: "openFolder", + }; public readonly parameters = { args: { folder: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/portsCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/portsCommandHandler.ts index c76d138617..87997e0159 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/portsCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/portsCommandHandler.ts @@ -14,6 +14,10 @@ import { export class PortsCommandHandler implements CommandHandler { public readonly description = "Lists ports registered by agents and the number of clients connected to each."; + public readonly action = { + schema: "system.operations", + actionName: "listRegisteredPorts", + }; public readonly parameters = {}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/randomCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/randomCommandHandler.ts index 3e7088eb75..838d312ebc 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/randomCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/randomCommandHandler.ts @@ -47,6 +47,10 @@ class RandomOfflineCommandHandler implements CommandHandlerNoParams { public readonly description = "Issues a random request from a dataset of pre-generated requests."; + public readonly action = { + schema: "system.diagnostics", + actionName: "runRandomOfflineRequest", + }; public async run(context: ActionContext) { displayStatus(`Selecting random request...`, context); @@ -92,6 +96,10 @@ class RandomOnlineCommandHandler implements CommandHandlerNoParams { private instructions = `You are an Siri/Alexa/Cortana prompt generator. You create user prompts that are both supported and unsupported.`; public readonly description = "Uses the LLM to generate random requests."; + public readonly action = { + schema: "system.diagnostics", + actionName: "runRandomOnlineRequest", + }; public async run(context: ActionContext) { displayStatus(`Generating random request using LLM...`, context); @@ -179,13 +187,15 @@ class RandomOnlineCommandHandler implements CommandHandlerNoParams { } } +export const randomCommandHandlers: CommandHandlerTable = { + description: "Random request commands", + defaultSubCommand: "offline", + commands: { + online: new RandomOnlineCommandHandler(), + offline: new RandomOfflineCommandHandler(), + }, +}; + export function getRandomCommandHandlers(): CommandHandlerTable { - return { - description: "Random request commands", - defaultSubCommand: "offline", - commands: { - online: new RandomOnlineCommandHandler(), - offline: new RandomOfflineCommandHandler(), - }, - }; + return randomCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/runScriptCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/runScriptCommandHandler.ts index cbeb6120eb..fd9ed3547a 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/runScriptCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/runScriptCommandHandler.ts @@ -16,6 +16,10 @@ import { getStatusSummary } from "../../../helpers/status.js"; export class RunCommandScriptHandler implements CommandHandler { public readonly description = "Run a command script file"; + public readonly action = { + schema: "system.operations", + actionName: "runCommandScript", + }; public readonly parameters = { args: { input: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/sessionCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/sessionCommandHandlers.ts index 3f4f8ea318..7c8d353bc6 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/sessionCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/sessionCommandHandlers.ts @@ -32,6 +32,10 @@ import { appAgentStateKeys } from "../../appAgentStateConfig.js"; class SessionNewCommandHandler implements CommandHandler { public readonly description = "Create a new empty session"; + public readonly action = { + schema: "system.session", + actionName: "newSession", + }; public readonly parameters = { flags: { keep: { @@ -82,6 +86,10 @@ class SessionNewCommandHandler implements CommandHandler { class SessionOpenCommandHandler implements CommandHandler { public readonly description = "Open an existing session"; + public readonly action = { + schema: "system.session", + actionName: "openSession", + }; public readonly parameters = { args: { session: { @@ -110,6 +118,10 @@ class SessionOpenCommandHandler implements CommandHandler { class SessionResetCommandHandler implements CommandHandlerNoParams { public readonly description = "Reset config on session and keep the data"; + public readonly action = { + schema: "system.session", + actionName: "resetSession", + }; public async run(context: ActionContext) { await changeContextConfig(null, context); displaySuccess(`Session settings revert to default.`, context); @@ -119,6 +131,10 @@ class SessionResetCommandHandler implements CommandHandlerNoParams { class SessionClearCommandHandler implements CommandHandlerNoParams { public readonly description = "Delete all data on the current sessions, keeping current settings"; + public readonly action = { + schema: "system.session", + actionName: "clearSession", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; if (systemContext.session.sessionDirPath === undefined) { @@ -148,6 +164,10 @@ class SessionClearCommandHandler implements CommandHandlerNoParams { class SessionDeleteCommandHandler implements CommandHandler { public readonly description = "Delete a session. If no session is specified, delete the current session and start a new session.\n-a to delete all sessions"; + public readonly action = { + schema: "system.session", + actionName: "deleteSession", + }; public readonly parameters = { args: { session: { @@ -224,6 +244,10 @@ class SessionDeleteCommandHandler implements CommandHandler { class SessionListCommandHandler implements CommandHandlerNoParams { public readonly description = "List all sessions. The current session is marked green."; + public readonly action = { + schema: "system.session", + actionName: "listSessions", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; if (systemContext.persistDir === undefined) { @@ -245,6 +269,10 @@ class SessionListCommandHandler implements CommandHandlerNoParams { class SessionInfoCommandHandler implements CommandHandlerNoParams { public readonly description = "Show info about the current session"; + public readonly action = { + schema: "system.session", + actionName: "showSessionInfo", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; const constructionFiles = systemContext.session.sessionDirPath @@ -316,17 +344,19 @@ class SessionInfoCommandHandler implements CommandHandlerNoParams { } } +export const sessionCommandHandlers: CommandHandlerTable = { + description: "Session commands", + commands: { + new: new SessionNewCommandHandler(), + open: new SessionOpenCommandHandler(), + reset: new SessionResetCommandHandler(), + clear: new SessionClearCommandHandler(), + list: new SessionListCommandHandler(), + delete: new SessionDeleteCommandHandler(), + info: new SessionInfoCommandHandler(), + }, +}; + export function getSessionCommandHandlers(): CommandHandlerTable { - return { - description: "Session commands", - commands: { - new: new SessionNewCommandHandler(), - open: new SessionOpenCommandHandler(), - reset: new SessionResetCommandHandler(), - clear: new SessionClearCommandHandler(), - list: new SessionListCommandHandler(), - delete: new SessionDeleteCommandHandler(), - info: new SessionInfoCommandHandler(), - }, - }; + return sessionCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/settingsCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/settingsCommandHandlers.ts index f9b767db69..64117ebc7f 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/settingsCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/settingsCommandHandlers.ts @@ -25,6 +25,7 @@ import chalk from "chalk"; class SettingsShowCommandHandler implements CommandHandler { public readonly description = "Show all persistent user settings"; + public readonly action = "showSettings"; public readonly parameters = {}; public async run(context: ActionContext) { @@ -43,6 +44,7 @@ class SettingsShowCommandHandler implements CommandHandler { class SettingsResetCommandHandler implements CommandHandler { public readonly description = "Reset all settings to defaults"; + public readonly action = "resetSettings"; public readonly parameters = {}; public async run(context: ActionContext) { @@ -54,6 +56,7 @@ class SettingsResetCommandHandler implements CommandHandler { class SettingsServerHiddenCommandHandler implements CommandHandler { public readonly description = "Set whether the AgentServer starts hidden (true/false)"; + public readonly action = "setServerHidden"; public readonly parameters = { args: { value: { @@ -94,6 +97,7 @@ class SettingsServerHiddenCommandHandler implements CommandHandler { class SettingsServerIdleTimeoutCommandHandler implements CommandHandler { public readonly description = "Set idle timeout in seconds (0 to disable)"; + public readonly action = "setIdleTimeout"; public readonly parameters = { args: { seconds: { @@ -123,6 +127,7 @@ class SettingsServerIdleTimeoutCommandHandler implements CommandHandler { class SettingsConversationResumeCommandHandler implements CommandHandler { public readonly description = "Set whether to resume the last conversation on startup (true/false)"; + public readonly action = "setConversationResume"; public readonly parameters = { args: { value: { @@ -164,6 +169,7 @@ class SettingsConversationResumeCommandHandler implements CommandHandler { class SettingsUIAutoCompleteCommandHandler implements CommandHandler { public readonly description = "Set whether inline autocompletion is enabled in the CLI (true/false)"; + public readonly action = "setAutoComplete"; public readonly parameters = { args: { value: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/tokenCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/tokenCommandHandler.ts index 7dfa9c3b98..56b87a20e4 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/tokenCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/tokenCommandHandler.ts @@ -12,6 +12,10 @@ import { TokenCounter, openai } from "@typeagent/aiclient"; class TokenSummaryCommandHandler implements CommandHandlerNoParams { public readonly description = "Get overall LLM usage statistics."; + public readonly action = { + schema: "system.diagnostics", + actionName: "showTokenSummary", + }; public async run(context: ActionContext) { const total: openai.CompletionUsageStats = @@ -35,6 +39,10 @@ class TokenSummaryCommandHandler implements CommandHandlerNoParams { class TokenDetailsCommandHandler implements CommandHandlerNoParams { public readonly description = "Gets detailed LLM usage statistics."; + public readonly action = { + schema: "system.diagnostics", + actionName: "showTokenDetails", + }; public async run(context: ActionContext) { const retValue: string[] = []; @@ -48,13 +56,15 @@ class TokenDetailsCommandHandler implements CommandHandlerNoParams { } } +export const tokenCommandHandlers: CommandHandlerTable = { + description: "Get LLM token usage statistics for this session.", + defaultSubCommand: "summary", + commands: { + summary: new TokenSummaryCommandHandler(), + details: new TokenDetailsCommandHandler(), + }, +}; + export function getTokenCommandHandlers(): CommandHandlerTable { - return { - description: "Get LLM token usage statistics for this session.", - defaultSubCommand: "summary", - commands: { - summary: new TokenSummaryCommandHandler(), - details: new TokenDetailsCommandHandler(), - }, - }; + return tokenCommandHandlers; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/traceCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/traceCommandHandler.ts index 560ce2f82c..2365ed9c63 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/traceCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/traceCommandHandler.ts @@ -30,6 +30,10 @@ if (registerDebug.inspectOpts !== undefined) { export class TraceCommandHandler implements CommandHandler { public readonly description = "Enable or disable trace namespaces"; + public readonly action = { + schema: "system.operations", + actionName: "configureTrace", + }; public readonly parameters = { flags: { clear: { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/collisionActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/collisionActionSchema.ts new file mode 100644 index 0000000000..512f6664f0 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/collisionActionSchema.ts @@ -0,0 +1,326 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type CollisionAction = + | ShowCollisionEventsAction + | FindSimilarActionsAction + | ListCollisionStrategiesAction + | ProbeCollisionPhraseAction + | GenerateCollisionCorpusAction + | ProbeCollisionCorpusAction + | TranslateCollisionCorpusAction + | ReanalyzeCollisionCorpusAction + | VisualizeCollisionCorpusAction + | RunCollisionCorpusPipelineAction + | AnalyzeCollisionRecoveryAction + | VisualizeCollisionRecoveryAction + | ManageCollisionKeywordsAction + | BackfillCollisionKeywordsAction + | BuildCollisionNeighborhoodsAction + | ListCollisionOptimizationLeversAction + | ExploreCollisionOptimizationsAction + | ValidateCollisionOptimizationsAction + | MineCollisionOptimizationPatternsAction + | RunCollisionOptimizationPipelineAction + | DistillCollisionOptimizationPatternsAction + | BrowseCollisionOptimizationRunsAction + | ListCollisionPreferencesAction + | SetCollisionPreferenceAction + | RemoveCollisionPreferenceAction + | ClearCollisionPreferencesAction; + +export type CollisionSeverity = "blocker" | "leaky" | "minor"; + +// Show recent collision telemetry events from this session. +export type ShowCollisionEventsAction = { + actionName: "showCollisionEvents"; + parameters?: { + limit?: number; + kind?: "static" | "grammarMatch" | "llmSelect" | "fuzzy"; + }; +}; + +// Find semantically similar actions across agents. +export type FindSimilarActionsAction = { + actionName: "findSimilarActions"; + parameters?: { + threshold?: number; + strategy?: string; + allStrategies?: boolean; + pairs?: boolean; + top?: number; + jsonPath?: string; + noCache?: boolean; + }; +}; + +// List available action-similarity scoring strategies. +export type ListCollisionStrategiesAction = { + actionName: "listCollisionStrategies"; +}; + +// Probe how the embedding ranker routes one phrase. +export type ProbeCollisionPhraseAction = { + actionName: "probeCollisionPhrase"; + parameters: { + phrase: string; + top?: number; + expected?: string; + delta?: number; + includeInactive?: boolean; + }; +}; + +// Generate an LLM-authored phrase corpus for loaded action schemas. +export type GenerateCollisionCorpusAction = { + actionName: "generateCollisionCorpus"; + parameters?: { + schemas?: string[]; + models?: string[]; + styles?: string[]; + concurrency?: number; + outputPath?: string; + workdir?: string; + }; +}; + +// Replay a phrase corpus through the embedding ranker. +export type ProbeCollisionCorpusAction = { + actionName: "probeCollisionCorpus"; + parameters?: { + inputPath?: string; + outputPath?: string; + top?: number; + delta?: number; + concurrency?: number; + workdir?: string; + }; +}; + +// Replay a phrase corpus through the LLM translator. +export type TranslateCollisionCorpusAction = { + actionName: "translateCollisionCorpus"; + parameters?: { + inputPath?: string; + outputPath?: string; + concurrency?: number; + strategy?: "first-match" | "score-rank" | "priority" | "user-clarify"; + maxPhrases?: number; + modelLabel?: string; + userContextMode?: "none" | "expected-schema" | "fixed"; + userContextJson?: string; + outputSuffix?: string; + workdir?: string; + }; +}; + +// Reclassify saved collision probe results using a new threshold. +export type ReanalyzeCollisionCorpusAction = { + actionName: "reanalyzeCollisionCorpus"; + parameters?: { + inputPath?: string; + outputPath?: string; + delta?: number; + workdir?: string; + }; +}; + +// Render the collision corpus analysis as a self-contained HTML report. +export type VisualizeCollisionCorpusAction = { + actionName: "visualizeCollisionCorpus"; + parameters?: { + inputPath?: string; + outputPath?: string; + top?: number; + similarityStrategy?: string; + similarityThreshold?: number; + noSimilarity?: boolean; + translatorPath?: string; + noTranslator?: boolean; + workdir?: string; + }; +}; + +// Run or resume the collision corpus pipeline. +export type RunCollisionCorpusPipelineAction = { + actionName: "runCollisionCorpusPipeline"; + parameters?: { + from?: "generate" | "probe" | "reanalyze" | "visualize"; + workdir?: string; + schemas?: string[]; + models?: string[]; + styles?: string[]; + concurrency?: number; + delta?: number; + top?: number; + sankeyTop?: number; + }; +}; + +// Analyze whether alternate candidates could recover corpus misroutes. +export type AnalyzeCollisionRecoveryAction = { + actionName: "analyzeCollisionRecovery"; + parameters?: { + inputPath?: string; + workdir?: string; + delta?: number; + }; +}; + +// Render collision recovery analysis as HTML. +export type VisualizeCollisionRecoveryAction = { + actionName: "visualizeCollisionRecovery"; + parameters?: { + inputPath?: string; + outputPath?: string; + delta?: number; + workdir?: string; + }; +}; + +// Inspect or modify context-selector keyword overrides. +export type ManageCollisionKeywordsAction = { + actionName: "manageCollisionKeywords"; + parameters?: { + operation?: "listOverrides" | "show" | "add" | "remove" | "clear"; + target?: string; + keywords?: string[]; + }; +}; + +// Generate missing context-selector keywords for loaded schemas. +export type BackfillCollisionKeywordsAction = { + actionName: "backfillCollisionKeywords"; + parameters?: { + schemas?: string[]; + useLlm?: boolean; + force?: boolean; + }; +}; + +// Build collision neighborhoods from translator misroute edges. +export type BuildCollisionNeighborhoodsAction = { + actionName: "buildCollisionNeighborhoods"; + parameters?: { + corpusPath?: string; + minMisroute?: number; + includeSameSchema?: boolean; + samplesPerCategory?: number; + outputPath?: string; + outputHtmlPath?: string; + workdir?: string; + }; +}; + +// List registered collision-optimization levers. +export type ListCollisionOptimizationLeversAction = { + actionName: "listCollisionOptimizationLevers"; +}; + +// Explore optimization hypotheses for collision neighborhoods. +export type ExploreCollisionOptimizationsAction = { + actionName: "exploreCollisionOptimizations"; + parameters?: { + corpusPath?: string; + baselinePath?: string; + top?: number; + hypothesesPerLever?: number; + depth?: number; + levers?: string[]; + severities?: CollisionSeverity[]; + workdir?: string; + dryRun?: boolean; + concurrency?: number; + }; +}; + +// Stack optimization winners and re-probe the baseline corpus. +export type ValidateCollisionOptimizationsAction = { + actionName: "validateCollisionOptimizations"; + parameters?: { + runId?: string; + neighborhoodId?: string; + baselinePath?: string; + workdir?: string; + winners?: string[]; + leaveOneOut?: string[]; + }; +}; + +// Mine cross-run collision optimization patterns. +export type MineCollisionOptimizationPatternsAction = { + actionName: "mineCollisionOptimizationPatterns"; + parameters?: { + patternsFile?: string; + minAttempts?: number; + surfaceDisagreement?: number; + outputPath?: string; + outputHtmlPath?: string; + workdir?: string; + }; +}; + +// Run or resume the collision optimization pipeline. +export type RunCollisionOptimizationPipelineAction = { + actionName: "runCollisionOptimizationPipeline"; + parameters?: { + from?: + | "neighborhoods" + | "explore" + | "validate" + | "patterns" + | "distill"; + top?: number; + depth?: number; + levers?: string[]; + severities?: CollisionSeverity[]; + dryRun?: boolean; + skipDistill?: boolean; + distillMinAttempts?: number; + workdir?: string; + }; +}; + +// Distill winning optimization attempts into candidate schema guidelines. +export type DistillCollisionOptimizationPatternsAction = { + actionName: "distillCollisionOptimizationPatterns"; + parameters?: { + minAttempts?: number; + workdir?: string; + }; +}; + +// Generate browse pages for collision optimization runs. +export type BrowseCollisionOptimizationRunsAction = { + actionName: "browseCollisionOptimizationRuns"; + parameters?: { + runId?: string; + all?: boolean; + workdir?: string; + }; +}; + +// List stored collision preferences. +export type ListCollisionPreferencesAction = { + actionName: "listCollisionPreferences"; +}; + +// Set an explicit preference among a set of competing actions. +export type SetCollisionPreferenceAction = { + actionName: "setCollisionPreference"; + parameters: { + candidates: string[]; + chosen: string; + }; +}; + +// Remove one stored collision preference by key. +export type RemoveCollisionPreferenceAction = { + actionName: "removeCollisionPreference"; + parameters: { key: string }; +}; + +// Remove all stored collision preferences. +export type ClearCollisionPreferencesAction = { + actionName: "clearCollisionPreferences"; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/configActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/configActionSchema.ts index 250e1dc321..480769d186 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/configActionSchema.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/configActionSchema.ts @@ -7,7 +7,192 @@ export type ConfigAction = | ToggleExplanationAction | ToggleDeveloperModeAction | EnterAgentPriorityModeAction - | ExitAgentPriorityModeAction; + | ExitAgentPriorityModeAction + | RunConfigCommandAction; + +export type ConfigCommandPath = + | "action" + | "agent" + | "agent refresh" + | "agent setup" + | "cache grammarSystem" + | "cache useDFA" + | "collision" + | "collision contextSelector decay" + | "collision contextSelector detect" + | "collision contextSelector detect off" + | "collision contextSelector detect on" + | "collision contextSelector margin" + | "collision contextSelector minMass" + | "collision contextSelector minUniqueTokens" + | "collision contextSelector windowTurns" + | "collision fuzzy detect" + | "collision fuzzy detect off" + | "collision fuzzy detect on" + | "collision fuzzy strategy" + | "collision grammarMatch detect" + | "collision grammarMatch detect off" + | "collision grammarMatch detect on" + | "collision grammarMatch strategy" + | "collision llmSelect detect" + | "collision llmSelect detect off" + | "collision llmSelect detect on" + | "collision llmSelect strategy" + | "collision preference enabled" + | "collision preference enabled off" + | "collision preference enabled on" + | "collision preference registry" + | "collision preference registryFirst" + | "collision preference registryFirst off" + | "collision preference registryFirst on" + | "collision preference remember" + | "collision preference source" + | "collision priority" + | "collision show" + | "collision static detect" + | "collision static detect off" + | "collision static detect on" + | "collision static strategy" + | "collision telemetry debugLog" + | "collision telemetry debugLog off" + | "collision telemetry debugLog on" + | "collision telemetry emit" + | "collision telemetry emit off" + | "collision telemetry emit on" + | "collision telemetry experimentId" + | "command" + | "dev" + | "dev off" + | "dev on" + | "execution activity" + | "execution activity off" + | "execution activity on" + | "execution conversationAnswer" + | "execution entityPromptShape" + | "execution planReuse" + | "execution reasoning" + | "execution reasoningEffort" + | "execution reasoningForwardActions" + | "execution reasoningForwardActions off" + | "execution reasoningForwardActions on" + | "execution reasoningHistory" + | "execution reasoningModel" + | "execution recordUserMessages" + | "execution recordUserMessages off" + | "execution recordUserMessages on" + | "execution scriptReuse" + | "execution setupOnFirstUse" + | "execution setupOnFirstUse off" + | "execution setupOnFirstUse on" + | "execution subagents" + | "execution subagents off" + | "execution subagents on" + | "explainer" + | "explainer async" + | "explainer async off" + | "explainer async on" + | "explainer filter" + | "explainer filter multiple" + | "explainer filter multiple off" + | "explainer filter multiple on" + | "explainer filter off" + | "explainer filter on" + | "explainer filter reference" + | "explainer filter reference list" + | "explainer filter reference list off" + | "explainer filter reference list on" + | "explainer filter reference off" + | "explainer filter reference on" + | "explainer filter reference translate" + | "explainer filter reference translate off" + | "explainer filter reference translate on" + | "explainer filter reference value" + | "explainer filter reference value off" + | "explainer filter reference value on" + | "explainer model" + | "explainer name" + | "explainer off" + | "explainer on" + | "log db" + | "log db off" + | "log db on" + | "match grammar" + | "match grammar off" + | "match grammar on" + | "modelProvider" + | "request" + | "schema" + | "scrub" + | "scrub off" + | "scrub on" + | "translation" + | "translation entity clarify" + | "translation entity clarify off" + | "translation entity clarify on" + | "translation entity filter" + | "translation entity filter off" + | "translation entity filter on" + | "translation entity resolve" + | "translation entity resolve off" + | "translation entity resolve on" + | "translation history limit" + | "translation history off" + | "translation history on" + | "translation model" + | "translation multi off" + | "translation multi on" + | "translation multi pending" + | "translation multi pending off" + | "translation multi pending on" + | "translation multi result" + | "translation multi result off" + | "translation multi result on" + | "translation off" + | "translation on" + | "translation recentActions limit" + | "translation recentActions off" + | "translation recentActions on" + | "translation schema generation json" + | "translation schema generation json off" + | "translation schema generation json on" + | "translation schema generation jsonFunc" + | "translation schema generation jsonFunc off" + | "translation schema generation jsonFunc on" + | "translation schema optimize actions" + | "translation schema optimize off" + | "translation schema optimize on" + | "translation stream" + | "translation stream off" + | "translation stream on" + | "translation switch embedding" + | "translation switch embedding off" + | "translation switch embedding on" + | "translation switch fix" + | "translation switch inline" + | "translation switch inline off" + | "translation switch inline on" + | "translation switch off" + | "translation switch on" + | "translation switch search" + | "translation switch search off" + | "translation switch search on"; + +// Run one exact TypeAgent configuration command through the canonical command parser. +export type RunConfigCommandAction = { + actionName: "runConfigCommand"; + parameters: { + // Executable command path after "@config". + command: ConfigCommandPath; + // Positional argument values in command order. Use an empty string to clear settings that support it. + arguments?: string[]; + flags?: { + reset?: boolean; + off?: string[]; + priority?: string[]; + confirm?: boolean; + }; + }; +}; // Shows the list of available agents export type ListAgents = { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/constructionActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/constructionActionSchema.ts new file mode 100644 index 0000000000..2a13d93ad1 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/constructionActionSchema.ts @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type ConstructionAction = + | NewConstructionStoreAction + | LoadConstructionStoreAction + | SaveConstructionStoreAction + | SetConstructionAutoSaveAction + | DisableConstructionStoreAction + | ShowConstructionInfoAction + | ListConstructionsAction + | ImportConstructionsAction + | PruneConstructionsAction + | DeleteConstructionAction + | SetBuiltInConstructionCacheAction + | SetConstructionMergeAction + | SetWildcardMatchingAction + | SetEntityWildcardMatchingAction; + +// Create a new construction store, optionally at a specified path. +export type NewConstructionStoreAction = { + actionName: "newConstructionStore"; + parameters?: { file?: string }; +}; + +// Load a construction store from disk or the current session setting. +export type LoadConstructionStoreAction = { + actionName: "loadConstructionStore"; + parameters?: { file?: string }; +}; + +// Save the current construction store, optionally to a specified path. +export type SaveConstructionStoreAction = { + actionName: "saveConstructionStore"; + parameters?: { file?: string }; +}; + +// Enable or disable automatic construction-store saving. +export type SetConstructionAutoSaveAction = { + actionName: "setConstructionAutoSave"; + parameters: { enabled: boolean }; +}; + +// Disable the construction store. +export type DisableConstructionStoreAction = { + actionName: "disableConstructionStore"; +}; + +// Show information about the current construction store. +export type ShowConstructionInfoAction = { + actionName: "showConstructionInfo"; +}; + +// List constructions, optionally filtered by match, part, or ID. +export type ListConstructionsAction = { + actionName: "listConstructions"; + parameters?: { + verbose?: boolean; + allMatchStrings?: boolean; + builtIn?: boolean; + match?: string[]; + part?: string[]; + ids?: number[]; + }; +}; + +// Import constructions from files or host-provided test data. +export type ImportConstructionsAction = { + actionName: "importConstructions"; + parameters?: { + files?: string[]; + extended?: boolean; + }; +}; + +// Prune outdated constructions from the cache. +export type PruneConstructionsAction = { + actionName: "pruneConstructions"; +}; + +// Delete one construction by namespace and ID. +export type DeleteConstructionAction = { + actionName: "deleteConstruction"; + parameters: { + namespace: string; + id: number; + }; +}; + +// Enable or disable the built-in construction cache. +export type SetBuiltInConstructionCacheAction = { + actionName: "setBuiltInConstructionCache"; + parameters: { enabled: boolean }; +}; + +// Enable or disable construction match-set merging. +export type SetConstructionMergeAction = { + actionName: "setConstructionMerge"; + parameters: { enabled: boolean }; +}; + +// Enable or disable wildcard matching for constructions. +export type SetWildcardMatchingAction = { + actionName: "setWildcardMatching"; + parameters: { enabled: boolean }; +}; + +// Enable or disable entity wildcard matching for constructions. +export type SetEntityWildcardMatchingAction = { + actionName: "setEntityWildcardMatching"; + parameters: { enabled: boolean }; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/copilotActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/copilotActionSchema.ts new file mode 100644 index 0000000000..461f953667 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/copilotActionSchema.ts @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type CopilotAction = + | ImportCopilotSessionsAction + | FixWithCopilotAction + | LoginToCopilotAction; + +// Import GitHub Copilot Chat sessions as conversation mirrors. +export type ImportCopilotSessionsAction = { + actionName: "importCopilotSessions"; +}; + +// Hand the current conversation to GitHub Copilot Chat for diagnosis and repair. +export type FixWithCopilotAction = { + actionName: "fixWithCopilot"; + parameters?: { + instructions?: string; + mode?: "agent" | "ask"; + includeScreenshot?: boolean; + devCaptures?: "auto" | "on" | "off"; + target?: string; + autoSend?: boolean; + reuseSession?: boolean; + location?: "editor" | "view" | "window"; + }; +}; + +// Sign in to GitHub Copilot using the browser device flow. +export type LoginToCopilotAction = { + actionName: "loginToCopilot"; + parameters?: { + host?: string; + openBrowser?: boolean; + }; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/feedbackActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/feedbackActionSchema.ts new file mode 100644 index 0000000000..8e31840335 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/feedbackActionSchema.ts @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type FeedbackAction = + | ListFeedbackAction + | SummarizeFeedbackAction + | FilterFeedbackAction + | ExportFeedbackAction + | CountFeedbackAction; + +// List recent user feedback entries. +export type ListFeedbackAction = { + actionName: "listFeedback"; + parameters?: { + limit?: number; + includeAllEntries?: boolean; + }; +}; + +// Aggregate user feedback by rating and category. +export type SummarizeFeedbackAction = { + actionName: "summarizeFeedback"; + parameters?: { categoryLimit?: number }; +}; + +// Filter user feedback by rating, category, date range, and result limit. +export type FilterFeedbackAction = { + actionName: "filterFeedback"; + parameters?: { + rating?: "up" | "down" | "cleared"; + category?: + | "wrong-agent" + | "didnt-understand" + | "bad-response" + | "other"; + since?: string; + until?: string; + limit?: number; + includeAllEntries?: boolean; + }; +}; + +// Export user feedback to a JSON or JSONL file. +export type ExportFeedbackAction = { + actionName: "exportFeedback"; + parameters: { + file: string; + format?: "json" | "jsonl"; + includeAllEntries?: boolean; + }; +}; + +// Count total feedback entries and unique rated requests. +export type CountFeedbackAction = { actionName: "countFeedback" }; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/grammarActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/grammarActionSchema.ts index bd88a940aa..8d1f6f494e 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/grammarActionSchema.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/grammarActionSchema.ts @@ -37,8 +37,17 @@ export type ClearRulesAction = { }; }; +export type ScanGrammarCollisionsAction = { + actionName: "scanGrammarCollisions"; + parameters?: { + // Optional path for writing the structured scan result as JSON. + jsonPath?: string; + }; +}; + export type GrammarAction = | ListRulesAction | ShowRuleAction | DeleteRuleAction - | ClearRulesAction; + | ClearRulesAction + | ScanGrammarCollisionsAction; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/historyActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/historyActionSchema.ts index 20b03f05c9..5cd6681281 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/historyActionSchema.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/historyActionSchema.ts @@ -4,7 +4,11 @@ export type HistoryAction = | ListHistoryAction | ClearHistoryAction - | DeleteHistoryAction; + | DeleteHistoryAction + | SaveHistoryAction + | InsertHistoryAction + | ListHistoryEntitiesAction + | DeleteHistoryEntityAction; // Shows the chat history export type ListHistoryAction = { @@ -23,3 +27,35 @@ export type DeleteHistoryAction = { messageNumber: number; }; }; + +// Save the current TypeAgent chat history to a JSON file. +export type SaveHistoryAction = { + actionName: "saveHistory"; + parameters: { + // Destination file path. + file: string; + }; +}; + +// Insert structured user/assistant entries into TypeAgent chat history. +export type InsertHistoryAction = { + actionName: "insertHistory"; + parameters: { + // JSON object or array text in the same format produced by the history save command. + messagesJson: string; + }; +}; + +// List entities retained in TypeAgent working memory. +export type ListHistoryEntitiesAction = { + actionName: "listHistoryEntities"; +}; + +// Delete one entity from TypeAgent working memory by unique ID. +export type DeleteHistoryEntityAction = { + actionName: "deleteHistoryEntity"; + parameters: { + // Unique ID of the entity to delete. + entityId: string; + }; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/indexActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/indexActionSchema.ts new file mode 100644 index 0000000000..d96a650a9a --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/indexActionSchema.ts @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type IndexAction = + | ListIndexesAction + | ShowIndexInfoAction + | CreateIndexAction + | DeleteIndexAction; + +// List all TypeAgent indexes. +export type ListIndexesAction = { + actionName: "listIndexes"; +}; + +// Show details for one TypeAgent index. +export type ShowIndexInfoAction = { + actionName: "showIndexInfo"; + parameters: { + // Name of the index. + name: string; + }; +}; + +// Create a TypeAgent index. +export type CreateIndexAction = { + actionName: "createIndex"; + parameters: { + // Index kind; defaults to image for the command, but is explicit in this action. + type: "image" | "email" | "website"; + // Name of the new index. + name: string; + // Source location to index. + location: string; + }; +}; + +// Delete a TypeAgent index by name. +export type DeleteIndexAction = { + actionName: "deleteIndex"; + parameters: { + // Name of the index to delete. + name: string; + }; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/memoryActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/memoryActionSchema.ts new file mode 100644 index 0000000000..3eb57584fe --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/memoryActionSchema.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type MemoryAction = + | SetLegacyMemoryAction + | QueryMemoryAction + | SearchMemoryAction + | AnswerFromMemoryAction; + +// Enable or disable legacy conversation memory. +export type SetLegacyMemoryAction = { + actionName: "setLegacyMemory"; + parameters: { enabled: boolean }; +}; + +// Search conversation memory for explicit terms. +export type QueryMemoryAction = { + actionName: "queryMemory"; + parameters: { + terms: string[]; + ascending?: boolean; + displayMessages?: boolean; + displayKnowledge?: boolean; + count?: number; + distinct?: boolean; + }; +}; + +// Translate a question into a conversation-memory search and show matches. +export type SearchMemoryAction = { + actionName: "searchMemory"; + parameters: MemoryQuestionParameters; +}; + +// Answer a question using conversation memory and show supporting matches. +export type AnswerFromMemoryAction = { + actionName: "answerFromMemory"; + parameters: MemoryQuestionParameters; +}; + +export type MemoryQuestionParameters = { + question: string; + ascending?: boolean; + displayMessages?: boolean; + displayKnowledge?: boolean; + count?: number; + distinct?: boolean; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/notificationActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/notificationActionSchema.ts index cce3cb199e..6d5bd4fcbe 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/notificationActionSchema.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/notificationActionSchema.ts @@ -4,7 +4,9 @@ export type NotificationAction = | ShowNotificationsAction | ShowNotificationSummaryAction - | ClearNotificationsAction; + | ClearNotificationsAction + | TestNotificationAction + | TestStatusNoticeAction; // Shows notifications based on the supplied filter export type ShowNotificationsAction = { @@ -25,3 +27,27 @@ export type ShowNotificationSummaryAction = { export type ClearNotificationsAction = { actionName: "clearNotifications"; }; + +// Fire a synthetic notification to verify TypeAgent notification rendering. +export type TestNotificationAction = { + actionName: "testNotification"; + parameters: { + // Notification body text. + message: string; + // Rendering mode; defaults to toast. + mode?: "toast" | "inline" | "info" | "warning" | "error"; + }; +}; + +// Fire a persistent status notice to verify the TypeAgent notification bell. +export type TestStatusNoticeAction = { + actionName: "testStatusNotice"; + parameters?: { + // Optional notice text; defaults to the built-in test message. + message?: string; + // Severity accent; defaults to warning. + level?: "info" | "warning" | "error"; + // Whether to include a Restart server action button. + restart?: boolean; + }; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/sessionActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/sessionActionSchema.ts new file mode 100644 index 0000000000..d7286ea53f --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/sessionActionSchema.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type SessionAction = + | NewSessionAction + | OpenSessionAction + | ResetSessionAction + | ClearSessionAction + | ListSessionsAction + | DeleteSessionAction + | ShowSessionInfoAction; + +// Create a new TypeAgent session. +export type NewSessionAction = { + actionName: "newSession"; + parameters?: { + // Copy settings from the current session; defaults to false. + keepSettings?: boolean; + // Whether to persist the new session; defaults to the current session policy. + persist?: boolean; + }; +}; + +// Open a persisted TypeAgent session by name. +export type OpenSessionAction = { + actionName: "openSession"; + parameters: { session: string }; +}; + +// Reset current session settings to defaults while keeping data. +export type ResetSessionAction = { actionName: "resetSession" }; + +// Clear current persisted session data after confirmation. +export type ClearSessionAction = { actionName: "clearSession" }; + +// List persisted TypeAgent sessions. +export type ListSessionsAction = { actionName: "listSessions" }; + +// Delete one or all persisted sessions after confirmation. +export type DeleteSessionAction = { + actionName: "deleteSession"; + parameters?: { + // Session name; omit to delete the current persisted session. + session?: string; + // Delete all persisted sessions. + all?: boolean; + }; +}; + +// Show current TypeAgent session settings and construction files. +export type ShowSessionInfoAction = { actionName: "showSessionInfo" }; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/settingsActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/settingsActionSchema.ts index 3dbe023fe5..a41f5d0796 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/schema/settingsActionSchema.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/settingsActionSchema.ts @@ -2,11 +2,23 @@ // Licensed under the MIT License. export type UserSettingsAction = + | ShowSettingsAction + | ResetSettingsAction | SetServerHiddenAction | SetIdleTimeoutAction | SetConversationResumeAction | SetAutoCompleteAction; +// Show all persistent TypeAgent user settings. +export type ShowSettingsAction = { + actionName: "showSettings"; +}; + +// Reset all persistent TypeAgent user settings to their defaults. +export type ResetSettingsAction = { + actionName: "resetSettings"; +}; + // Set whether the agent server starts as a hidden background process. // Use when the user says things like "start the server hidden", "run the server in the background", // "don't show a server window", "show the server window on startup". diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/systemDiagnosticsActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/systemDiagnosticsActionSchema.ts new file mode 100644 index 0000000000..7d0c6b299b --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/systemDiagnosticsActionSchema.ts @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type SystemDiagnosticsAction = + | ListEnvironmentVariablesAction + | GetEnvironmentVariableAction + | ShowTokenSummaryAction + | ShowTokenDetailsAction + | RunRandomOfflineRequestAction + | RunRandomOnlineRequestAction; + +// List process environment variables with sensitive values redacted. +export type ListEnvironmentVariablesAction = { + actionName: "listEnvironmentVariables"; +}; + +// Show one process environment variable. +export type GetEnvironmentVariableAction = { + actionName: "getEnvironmentVariable"; + parameters: { + // Environment variable name. + name: string; + }; +}; + +// Show aggregate in-process LLM token usage. +export type ShowTokenSummaryAction = { + actionName: "showTokenSummary"; +}; + +// Show detailed per-request in-process LLM token usage. +export type ShowTokenDetailsAction = { + actionName: "showTokenDetails"; +}; + +// Select and execute a random request from the offline dataset. +export type RunRandomOfflineRequestAction = { + actionName: "runRandomOfflineRequest"; +}; + +// Generate and execute a random request using an LLM. +export type RunRandomOnlineRequestAction = { + actionName: "runRandomOnlineRequest"; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/schema/systemOperationsActionSchema.ts b/ts/packages/dispatcher/dispatcher/src/context/system/schema/systemOperationsActionSchema.ts new file mode 100644 index 0000000000..96c3adb9c3 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/schema/systemOperationsActionSchema.ts @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export type SystemOperationsAction = + | ExecuteTypedActionAction + | ClearConsoleAction + | DeepClearConsoleAction + | StartDebuggerAction + | ShowQuestionCardsAction + | DisplayContentAction + | ExitTypeAgentAction + | ShowCommandHelpAction + | OpenFolderAction + | ListRegisteredPortsAction + | RunCommandScriptAction + | RestartAgentServerAction + | ShutdownAgentServerAction + | ConfigureTraceAction; + +// Execute a specific typed action, optionally associating a natural-language phrase with it. +export type ExecuteTypedActionAction = { + actionName: "executeTypedAction"; + parameters: { + schemaName: string; + actionName: string; + // JSON object text containing parameters for the target action. + actionParametersJson?: string; + naturalLanguage?: string; + }; +}; + +// Clear displayed console content. +export type ClearConsoleAction = { actionName: "clearConsole" }; + +// Clear displayed content, chat history, reasoning state, activity, and the persistent display log. +export type DeepClearConsoleAction = { actionName: "deepClearConsole" }; + +// Start the Node.js inspector and wait for a debugger to attach. +export type StartDebuggerAction = { actionName: "startDebugger" }; + +// Show the interactive question-card demonstration. +export type ShowQuestionCardsAction = { + actionName: "showQuestionCards"; + parameters?: { paged?: boolean }; +}; + +// Send one or more content values to the TypeAgent display. +export type DisplayContentAction = { + actionName: "displayContent"; + parameters: { + content: string[]; + type?: "text" | "html" | "markdown" | "iframe"; + speak?: boolean; + inline?: boolean; + }; +}; + +// Exit the current TypeAgent client. +export type ExitTypeAgentAction = { actionName: "exitTypeAgent" }; + +// Show command help for one command or all commands. +export type ShowCommandHelpAction = { + actionName: "showCommandHelp"; + parameters?: { + command?: string; + all?: boolean; + }; +}; + +// Open a system, TypeAgent, session, or agent folder. +export type OpenFolderAction = { + actionName: "openFolder"; + parameters: { folder: string }; +}; + +// List ports registered by agents and their connected-client counts. +export type ListRegisteredPortsAction = { + actionName: "listRegisteredPorts"; +}; + +// Run TypeAgent commands from a script file. +export type RunCommandScriptAction = { + actionName: "runCommandScript"; + parameters: { input: string }; +}; + +// Restart the standalone TypeAgent agent server. +export type RestartAgentServerAction = { + actionName: "restartAgentServer"; +}; + +// Shut down the TypeAgent agent server and exit. +export type ShutdownAgentServerAction = { + actionName: "shutdownAgentServer"; +}; + +// Add trace namespaces or clear all trace namespaces. +export type ConfigureTraceAction = { + actionName: "configureTrace"; + parameters?: { + namespaces?: string[]; + clear?: boolean; + }; +}; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts b/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts index d875a16e47..449483b96e 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts @@ -40,6 +40,24 @@ import { HistoryAction } from "./schema/historyActionSchema.js"; import { ConversationAction } from "./schema/conversationActionSchema.js"; import { GrammarAction } from "./schema/grammarActionSchema.js"; import { UserSettingsAction } from "./schema/settingsActionSchema.js"; +import { IndexAction } from "./schema/indexActionSchema.js"; +import { executeIndexAction } from "./action/indexActionHandler.js"; +import { SystemDiagnosticsAction } from "./schema/systemDiagnosticsActionSchema.js"; +import { executeSystemDiagnosticsAction } from "./action/systemDiagnosticsActionHandler.js"; +import { SessionAction } from "./schema/sessionActionSchema.js"; +import { executeSessionAction } from "./action/sessionActionHandler.js"; +import { MemoryAction } from "./schema/memoryActionSchema.js"; +import { executeMemoryAction } from "./action/memoryActionHandler.js"; +import { CopilotAction } from "./schema/copilotActionSchema.js"; +import { executeCopilotAction } from "./action/copilotActionHandler.js"; +import { FeedbackAction } from "./schema/feedbackActionSchema.js"; +import { executeFeedbackAction } from "./action/feedbackActionHandler.js"; +import { SystemOperationsAction } from "./schema/systemOperationsActionSchema.js"; +import { executeSystemOperationsAction } from "./action/systemOperationsActionHandler.js"; +import { ConstructionAction } from "./schema/constructionActionSchema.js"; +import { executeConstructionAction } from "./action/constructionActionHandler.js"; +import { CollisionAction } from "./schema/collisionActionSchema.js"; +import { executeCollisionAction } from "./action/collisionActionHandler.js"; // handlers import { getConfigCommandHandlers } from "./handlers/configCommandHandlers.js"; @@ -50,7 +68,7 @@ import { getSessionCommandHandlers } from "./handlers/sessionCommandHandlers.js" import { getConversationCommandHandlers } from "./handlers/conversationCommandHandlers.js"; import { getCopilotCommandHandlers } from "./handlers/copilotCommandHandlers.js"; import { getDemoCommandHandlers } from "./handlers/demoCommandHandlers.js"; -import { getCollisionCommandHandlers } from "./handlers/collisionCommandHandlers.js"; +import { collisionCommandHandlers } from "./handlers/collisionCommandHandlers.js"; import { getGrammarCommandHandlers } from "./handlers/grammarCommandHandlers.js"; import { getHistoryCommandHandlers } from "./handlers/historyCommandHandler.js"; import { TraceCommandHandler } from "./handlers/traceCommandHandler.js"; @@ -71,6 +89,10 @@ import { PortsCommandHandler } from "./handlers/portsCommandHandler.js"; class ClearConsoleCommandHandler implements CommandHandlerNoParams { public readonly description = "Clear the console"; + public readonly action = { + schema: "system.operations", + actionName: "clearConsole", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; systemContext.clientIO.clear(getRequestId(systemContext)); @@ -80,6 +102,10 @@ class ClearConsoleCommandHandler implements CommandHandlerNoParams { class ClearDeepCommandHandler implements CommandHandlerNoParams { public readonly description = "Clear the console and wipe chat history, reasoning, activity, and persistent display log so nothing replays on rejoin"; + public readonly action = { + schema: "system.operations", + actionName: "deepClearConsole", + }; public async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; systemContext.chatHistory.clear(); @@ -102,7 +128,7 @@ export const systemHandlers: CommandHandlerTable = { session: getSessionCommandHandlers(), conversation: getConversationCommandHandlers(), copilot: getCopilotCommandHandlers(), - collision: getCollisionCommandHandlers(), + collision: collisionCommandHandlers, grammar: getGrammarCommandHandlers(), history: getHistoryCommandHandlers(), memory: getMemoryCommandHandlers(), @@ -123,6 +149,10 @@ export const systemHandlers: CommandHandlerTable = { run: new RunCommandScriptHandler(), exit: { description: "Exit the program", + action: { + schema: "system.operations", + actionName: "exitTypeAgent", + }, async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; systemContext.clientIO.exit(getRequestId(systemContext)); @@ -130,6 +160,10 @@ export const systemHandlers: CommandHandlerTable = { }, shutdown: { description: "Shut down the agent server and exit", + action: { + schema: "system.operations", + actionName: "shutdownAgentServer", + }, async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; systemContext.clientIO.shutdown(getRequestId(systemContext)); @@ -141,6 +175,10 @@ export const systemHandlers: CommandHandlerTable = { restart: { description: "Restart the agent server so it loads rebuilt code", + action: { + schema: "system.operations", + actionName: "restartAgentServer", + }, async run(context: ActionContext) { const systemContext = context.sessionContext.agentContext; @@ -179,24 +217,85 @@ function executeSystemAction( | TypeAgentAction | TypeAgentAction | TypeAgentAction - | TypeAgentAction, + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction + | TypeAgentAction, context: ActionContext, ) { switch (action.schemaName) { case "system.conversation": return executeConversationAction(action, context); case "system.config": - return executeConfigAction(action, context); + return executeConfigAction(action, context, { + handlers: systemHandlers.commands.config as CommandHandlerTable, + }); case "system.notify": return executeNotificationAction(action, context); case "system.history": return executeHistoryAction(action, context); case "system.grammar": - return executeGrammarAction(action, context); + return executeGrammarAction(action, context, systemHandlers); case "system.settings": return executeSettingsAction(action, context); case "system.describe": return executeDescribeAction(action, context); + case "system.index": + return executeIndexAction(action, context); + case "system.diagnostics": + return executeSystemDiagnosticsAction( + action, + context, + systemHandlers, + ); + case "system.session": + return executeSessionAction( + action, + context, + systemHandlers.commands.session as CommandHandlerTable, + ); + case "system.memory": + return executeMemoryAction( + action, + context, + systemHandlers.commands.memory as CommandHandlerTable, + ); + case "system.copilot": + return executeCopilotAction( + action, + context, + systemHandlers.commands.copilot as CommandHandlerTable, + ); + case "system.feedback": + return executeFeedbackAction( + action, + context, + systemHandlers.commands.feedback as CommandHandlerTable, + ); + case "system.operations": + return executeSystemOperationsAction( + action, + context, + systemHandlers, + ); + case "system.construction": + return executeConstructionAction( + action, + context, + systemHandlers.commands.const as CommandHandlerTable, + ); + case "system.collision": + return executeCollisionAction( + action, + context, + collisionCommandHandlers, + ); default: throw new Error( `Invalid system sub-translator: ${(action as TypeAgentAction).schemaName}`, @@ -209,6 +308,85 @@ export const systemManifest: AppAgentManifest = { description: "Built-in agent to manage system configuration and conversations", subActionManifests: { + collision: { + schema: { + description: + "Inspect collision telemetry and run collision corpus, keyword, neighborhood, optimization, and preference workflows.", + schemaFile: + "./src/context/system/schema/collisionActionSchema.ts", + schemaType: "CollisionAction", + }, + }, + construction: { + schema: { + description: + "Create, load, save, inspect, import, prune, and configure TypeAgent construction stores.", + schemaFile: + "./src/context/system/schema/constructionActionSchema.ts", + schemaType: "ConstructionAction", + }, + }, + operations: { + schema: { + description: + "Run low-level TypeAgent operations including help, display, scripts, tracing, debugging, and process lifecycle commands.", + schemaFile: + "./src/context/system/schema/systemOperationsActionSchema.ts", + schemaType: "SystemOperationsAction", + }, + }, + feedback: { + schema: { + description: + "List, summarize, filter, export, and count user feedback.", + schemaFile: + "./src/context/system/schema/feedbackActionSchema.ts", + schemaType: "FeedbackAction", + }, + }, + copilot: { + schema: { + description: + "Import Copilot sessions, hand off a problem to Copilot Chat, or sign in to GitHub Copilot.", + schemaFile: + "./src/context/system/schema/copilotActionSchema.ts", + schemaType: "CopilotAction", + }, + }, + memory: { + schema: { + description: + "Configure, query, search, and answer from TypeAgent conversation memory.", + schemaFile: "./src/context/system/schema/memoryActionSchema.ts", + schemaType: "MemoryAction", + }, + }, + session: { + schema: { + description: + "Create, open, reset, clear, list, delete, and inspect TypeAgent sessions.", + schemaFile: + "./src/context/system/schema/sessionActionSchema.ts", + schemaType: "SessionAction", + }, + }, + diagnostics: { + schema: { + description: + "Inspect environment and token diagnostics, or generate random test requests.", + schemaFile: + "./src/context/system/schema/systemDiagnosticsActionSchema.ts", + schemaType: "SystemDiagnosticsAction", + }, + }, + index: { + schema: { + description: + "Create, list, inspect, and delete TypeAgent indexes.", + schemaFile: "./src/context/system/schema/indexActionSchema.ts", + schemaType: "IndexAction", + }, + }, config: { schema: { description: diff --git a/ts/packages/dispatcher/dispatcher/src/helpers/command.ts b/ts/packages/dispatcher/dispatcher/src/helpers/command.ts index bf4a2a6072..62b17a67f6 100644 --- a/ts/packages/dispatcher/dispatcher/src/helpers/command.ts +++ b/ts/packages/dispatcher/dispatcher/src/helpers/command.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { ActionContext } from "@typeagent/agent-sdk"; +import { ActionContext, CommandDescriptor } from "@typeagent/agent-sdk"; import { CommandHandlerContext } from "../context/commandHandlerContext.js"; import { CommandHandlerNoParams, @@ -15,10 +15,12 @@ export function getToggleCommandHandlers( context: ActionContext, enable: boolean, ) => Promise, + action?: CommandDescriptor["action"], ): Record { return { on: { description: `Turn on ${name}`, + action, run: async (context: ActionContext) => { await toggle(context, true); displaySuccess(`${name} is enabled.`, context); @@ -26,6 +28,7 @@ export function getToggleCommandHandlers( }, off: { description: `Turn off ${name}`, + action, run: async (context: ActionContext) => { await toggle(context, false); displaySuccess(`${name} is disabled.`, context); @@ -40,10 +43,11 @@ export function getToggleHandlerTable( context: ActionContext, enable: boolean, ) => Promise, + action?: CommandDescriptor["action"], ): CommandHandlerTable { return { description: `Toggle ${name}`, defaultSubCommand: "on", - commands: getToggleCommandHandlers(name, toggle), + commands: getToggleCommandHandlers(name, toggle, action), }; } diff --git a/ts/packages/dispatcher/dispatcher/test/collisionActionHandler.spec.ts b/ts/packages/dispatcher/dispatcher/test/collisionActionHandler.spec.ts new file mode 100644 index 0000000000..55e8b9edca --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/test/collisionActionHandler.spec.ts @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { describe, expect, it } from "@jest/globals"; +import { executeCollisionAction } from "../src/context/system/action/collisionActionHandler.js"; + +type CommandCall = { + commands: string[]; + params: unknown; + context: unknown; +}; + +const handlers = { description: "test", commands: {} } as any; +const context = { id: "context" } as any; + +async function run(action: any) { + const calls: CommandCall[] = []; + const execute = async ( + _handlers: unknown, + commands: string[], + params: unknown, + actionContext: unknown, + ) => { + calls.push({ commands, params, context: actionContext }); + return undefined; + }; + await executeCollisionAction( + { schemaName: "system.collision", ...action }, + context, + handlers, + execute as any, + ); + expect(calls).toHaveLength(1); + return calls[0]; +} + +describe("collision actions", () => { + it("maps collision-event defaults", async () => { + expect(await run({ actionName: "showCollisionEvents" })).toEqual({ + commands: ["events"], + params: { args: {}, flags: { limit: 10 } }, + context, + }); + }); + + it("maps corpus arrays to command CSV flags", async () => { + expect( + await run({ + actionName: "generateCollisionCorpus", + parameters: { + schemas: ["calendar", "email"], + models: ["GPT_5", "GPT_5_NANO"], + styles: ["imperative", "casual"], + outputPath: "corpus.json", + }, + }), + ).toEqual({ + commands: ["corpus", "generate"], + params: { + args: {}, + flags: { + schemas: "calendar,email", + models: "GPT_5,GPT_5_NANO", + styles: "imperative,casual", + concurrency: 8, + out: "corpus.json", + }, + }, + context, + }); + }); + + it("preserves target-first keyword token ordering", async () => { + expect( + await run({ + actionName: "manageCollisionKeywords", + parameters: { + operation: "add", + target: "list.addItems", + keywords: ["grocery", "shopping"], + }, + }), + ).toEqual({ + commands: ["keywords"], + params: { + args: { + tokens: ["list.addItems", "add", "grocery", "shopping"], + }, + flags: {}, + }, + context, + }); + }); + + it("shows one target when the keyword operation is omitted", async () => { + expect( + await run({ + actionName: "manageCollisionKeywords", + parameters: { target: "list.addItems" }, + }), + ).toEqual({ + commands: ["keywords"], + params: { + args: { tokens: ["list.addItems", "show"] }, + flags: {}, + }, + context, + }); + }); + + it("maps optimization filters and defaults", async () => { + expect( + await run({ + actionName: "runCollisionOptimizationPipeline", + parameters: { + from: "explore", + levers: ["schema", "keywords"], + severities: ["blocker", "minor"], + dryRun: true, + }, + }), + ).toEqual({ + commands: ["optimize", "run"], + params: { + args: {}, + flags: { + from: "explore", + top: 5, + depth: 2, + lever: "schema,keywords", + severity: "blocker,minor", + "dry-run": true, + "skip-distill": false, + "distill-min-attempts": 10, + }, + }, + context, + }); + }); + + it("serializes preference candidate sets", async () => { + expect( + await run({ + actionName: "setCollisionPreference", + parameters: { + candidates: ["player.play", "list.play"], + chosen: "player.play", + }, + }), + ).toEqual({ + commands: ["preferences", "set"], + params: { + args: { + candidates: "player.play,list.play", + chosen: "player.play", + }, + flags: {}, + }, + context, + }); + }); +}); diff --git a/ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts b/ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts new file mode 100644 index 0000000000..178afc13b7 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { describe, expect, it, jest } from "@jest/globals"; +import { executeConfigAction } from "../src/context/system/action/configActionHandler.js"; +import { configCommandHandlers } from "../src/context/system/handlers/configCommandHandlers.js"; + +const agentContext = { id: "agent-context" } as any; +const context = { sessionContext: { agentContext } } as any; + +async function run(action: any) { + const processCommand = jest.fn(async () => undefined); + const executeCommand = jest.fn(async () => undefined); + await executeConfigAction( + { schemaName: "system.config", ...action }, + context, + { + processCommand, + handlers: configCommandHandlers, + executeCommand: executeCommand as any, + }, + ); + return { executeCommand, processCommand }; +} + +describe("config actions", () => { + it("serializes the finite config flags and ordered arguments", async () => { + const { executeCommand } = await run({ + actionName: "runConfigCommand", + parameters: { + command: "agent", + arguments: ["calendar", "agent with space"], + flags: { + reset: true, + off: ["player*", "email"], + priority: ['code "editor"', "browser"], + }, + }, + }); + + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["agent"], + { + args: { agentNames: ["calendar", "agent with space"] }, + flags: { + reset: true, + off: ["player*", "email"], + priority: ['code "editor"', "browser"], + }, + }, + context, + ); + }); + + it("preserves arbitrary string arguments without command quoting", async () => { + const { executeCommand } = await run({ + actionName: "runConfigCommand", + parameters: { + command: "collision telemetry experimentId", + arguments: [`Sam's "quoted" \\ value`], + }, + }); + + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["collision", "telemetry", "experimentId"], + { + args: { id: `Sam's "quoted" \\ value` }, + flags: undefined, + }, + context, + ); + }); + + it("serializes the developer confirmation flag", async () => { + const { executeCommand } = await run({ + actionName: "runConfigCommand", + parameters: { + command: "dev on", + flags: { confirm: true }, + }, + }); + + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["dev", "on"], + { args: undefined, flags: { confirm: true } }, + context, + ); + }); + + it("accepts empty parameter containers for parameterless commands", async () => { + const { executeCommand } = await run({ + actionName: "runConfigCommand", + parameters: { + command: "translation off", + arguments: [], + flags: {}, + }, + }); + + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["translation", "off"], + undefined, + context, + ); + }); + + it("keeps the existing developer-mode action behavior", async () => { + const { processCommand } = await run({ + actionName: "toggleDeveloperMode", + parameters: { enable: false }, + }); + + expect(processCommand).toHaveBeenCalledWith( + "@config dev off", + agentContext, + ); + }); +}); diff --git a/ts/packages/dispatcher/dispatcher/test/grammarCollisionActionHandler.spec.ts b/ts/packages/dispatcher/dispatcher/test/grammarCollisionActionHandler.spec.ts new file mode 100644 index 0000000000..68fee23e0c --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/test/grammarCollisionActionHandler.spec.ts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { expect, it, jest } from "@jest/globals"; +import { executeGrammarAction } from "../src/context/system/action/grammarActionHandler.js"; + +it("runs grammar collision scans without a persisted grammar store", async () => { + const run = jest.fn(async () => undefined); + const handlers = { + description: "system", + commands: { + grammar: { + description: "grammar", + commands: { + collisions: { + description: "collisions", + parameters: { + flags: { + json: { type: "string", optional: true }, + }, + }, + run, + }, + }, + }, + }, + } as any; + const context = { + sessionContext: { agentContext: { persistedGrammarStore: undefined } }, + } as any; + + await executeGrammarAction( + { + schemaName: "system.grammar", + actionName: "scanGrammarCollisions", + parameters: { jsonPath: "collisions.json" }, + }, + context, + handlers, + ); + + expect(run).toHaveBeenCalledWith( + context, + { args: {}, flags: { json: "collisions.json" } }, + undefined, + ); +}); diff --git a/ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts b/ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts new file mode 100644 index 0000000000..6e4d4f157a --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { expect, it, jest } from "@jest/globals"; +import { executeHistoryAction } from "../src/context/system/action/historyActionHandler.js"; + +it("inserts the complete saved-history JSON shape", async () => { + const imported: unknown[] = []; + const input = { + user: "What changed?", + assistant: { + text: "The task completed.", + source: "test", + entities: [ + { + name: "result", + type: ["artifact"], + facets: [{ name: "details", value: { nested: true } }], + }, + ], + additionalInstructions: ["Keep this context."], + activityContext: { + activityName: "test", + description: "Testing", + state: { step: 2 }, + activityEndAction: { actionName: "finish" }, + }, + action: { + schemaName: "test", + actionName: "complete", + parameters: { nested: { value: true } }, + }, + }, + }; + const context = { + sessionContext: { + agentContext: { + chatHistory: { + count: () => imported.length, + import: (value: unknown) => imported.push(value), + getLastActivityContextInfo: () => undefined, + }, + }, + }, + actionIO: { + appendDisplay: jest.fn(), + setDisplay: jest.fn(), + }, + } as any; + + await executeHistoryAction( + { + schemaName: "system.history", + actionName: "insertHistory", + parameters: { messagesJson: JSON.stringify(input) }, + }, + context, + ); + + expect(imported).toEqual([input]); +}); diff --git a/ts/packages/dispatcher/dispatcher/test/systemActionHandlerImports.spec.ts b/ts/packages/dispatcher/dispatcher/test/systemActionHandlerImports.spec.ts new file mode 100644 index 0000000000..46e7485458 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/test/systemActionHandlerImports.spec.ts @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { expect, it } from "@jest/globals"; +import { spawnSync } from "node:child_process"; +import { readdirSync } from "node:fs"; + +const actionDirectory = new URL("../context/system/action/", import.meta.url); +const modules = readdirSync(actionDirectory) + .filter((name) => name.endsWith("ActionHandler.js")) + .map((name) => name.slice(0, -3)); + +it.each(modules)("imports %s in a fresh native ESM process", (moduleName) => { + const moduleUrl = new URL( + `../context/system/action/${moduleName}.js`, + import.meta.url, + ).href; + const result = spawnSync( + process.execPath, + [ + "--input-type=module", + "--eval", + "await import(process.argv[1])", + moduleUrl, + ], + { encoding: "utf8" }, + ); + + expect(result.stderr).toBe(""); + expect(result.status).toBe(0); +}); diff --git a/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts b/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts new file mode 100644 index 0000000000..c52e71c259 --- /dev/null +++ b/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { parseSchemaSource } from "@typeagent/action-schema"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { collectCatalog } from "../src/collect.js"; +import type { Catalog } from "../src/types.js"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const workspaceRoot = path.resolve(here, "..", "..", "..", ".."); + +let catalog: Catalog; + +describe("command action coverage", () => { + beforeAll(async () => { + catalog = await collectCatalog({ strict: true }); + }, 30_000); + + it("links every bundled executable command to a valid action", () => { + expect(catalog.commandActionLinkIssues).toEqual([]); + expect(catalog.missingCommandActions).toEqual([]); + expect(catalog.counts.linkedCommandEndpoints).toBe( + catalog.counts.commandEndpoints, + ); + }); + + it("keeps ConfigCommandPath synchronized with executable config commands", () => { + const schemaPath = path.join( + workspaceRoot, + "packages", + "dispatcher", + "dispatcher", + "src", + "context", + "system", + "schema", + "configActionSchema.ts", + ); + const definitions = parseSchemaSource( + fs.readFileSync(schemaPath, "utf8"), + schemaPath, + ); + const commandPathType = definitions.get("ConfigCommandPath")?.type; + expect(commandPathType?.type).toBe("string-union"); + if (commandPathType?.type !== "string-union") { + return; + } + + const executablePaths = catalog.commands + .filter( + (command) => + command.host === "system" && + command.executable && + command.path.startsWith("config "), + ) + .map((command) => command.path.slice("config ".length)) + .sort(); + + expect([...commandPathType.typeEnum].sort()).toEqual(executablePaths); + + const actionType = definitions.get("RunConfigCommandAction") + ?.type as any; + const actionFlagNames = Object.keys( + actionType.fields.parameters.type.fields.flags.type.fields, + ).sort(); + const commandFlagNames = Array.from( + new Set( + catalog.commands + .filter( + (command) => + command.host === "system" && + command.executable && + command.path.startsWith("config "), + ) + .flatMap((command) => + command.flags.map((flag) => flag.name), + ), + ), + ).sort(); + + expect(actionFlagNames).toEqual(commandFlagNames); + }); +}); From 05c889e568f003625f37e3c3960c969bb061be7a Mon Sep 17 00:00:00 2001 From: Robert Gruen Date: Fri, 31 Jul 2026 17:04:35 -0700 Subject: [PATCH 05/22] updated lock file --- ts/pnpm-lock.yaml | 226 ++++++++++++++++++---------------------------- 1 file changed, 87 insertions(+), 139 deletions(-) diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index 810250ca48..96a20f3983 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -174,7 +174,7 @@ importers: version: 8.18.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) + version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3016,6 +3016,9 @@ importers: rimraf: specifier: ^6.0.1 version: 6.0.1 + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ~5.4.5 version: 5.4.5 @@ -3983,6 +3986,28 @@ importers: specifier: ~5.4.5 version: 5.4.5 + packages/benchmarks: + dependencies: + '@typeagent/agent-sdk': + specifier: workspace:* + version: link:../agentSdk + agent-dispatcher: + specifier: workspace:* + version: link:../dispatcher/dispatcher + default-agent-provider: + specifier: workspace:* + version: link:../defaultAgentProvider + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.20.1 + prettier: + specifier: ^3.5.3 + version: 3.5.3 + typescript: + specifier: ~5.4.5 + version: 5.4.5 + packages/cache: dependencies: '@typeagent/action-grammar': @@ -6604,7 +6629,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.1.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -21193,7 +21218,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -21206,14 +21231,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 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@26.1.1)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21241,14 +21266,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 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@26.1.1)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21276,14 +21301,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 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@26.1.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21311,14 +21336,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 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@26.1.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21343,7 +21368,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -21361,7 +21386,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 22.15.18 + '@types/node': 22.20.1 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -21383,7 +21408,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 26.1.1 + '@types/node': 22.20.1 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -23423,7 +23448,7 @@ snapshots: '@types/accepts@1.3.7': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/async@3.2.24': {} @@ -23452,7 +23477,7 @@ snapshots: '@types/better-sqlite3@7.6.11': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/better-sqlite3@7.6.13': dependencies: @@ -23466,17 +23491,17 @@ snapshots: '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/bonjour@3.5.13': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/cacheable-request@6.0.3': dependencies: '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 24.13.3 + '@types/node': 22.20.1 '@types/responselike': 1.0.3 '@types/chai-dom@1.11.3': @@ -23507,7 +23532,7 @@ snapshots: '@types/co-body@6.1.3': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/qs': 6.15.1 '@types/command-line-args@5.2.3': {} @@ -23517,11 +23542,11 @@ snapshots: '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 4.19.8 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/connect@3.4.38': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/content-disposition@0.5.9': {} @@ -23532,7 +23557,7 @@ snapshots: '@types/connect': 3.4.38 '@types/express': 5.0.6 '@types/keygrip': 1.0.6 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/cors@2.8.18': dependencies: @@ -23693,21 +23718,21 @@ snapshots: '@types/express-serve-static-core@4.17.41': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/qs': 6.15.0 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 '@types/express-serve-static-core@4.19.8': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/qs': 6.15.1 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 '@types/express-serve-static-core@5.1.2': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/qs': 6.15.1 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -23764,7 +23789,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 - '@types/node': 22.15.18 + '@types/node': 22.20.1 '@types/graceful-fs@4.1.9': dependencies: @@ -23792,7 +23817,7 @@ snapshots: '@types/http-proxy@1.17.17': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/istanbul-lib-coverage@2.0.6': {} @@ -23825,7 +23850,7 @@ snapshots: '@types/jsdom@20.0.1': dependencies: - '@types/node': 22.15.18 + '@types/node': 22.20.1 '@types/tough-cookie': 4.0.5 parse5: 7.3.0 @@ -23840,7 +23865,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/jsonpath@0.2.4': {} @@ -23850,7 +23875,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 24.13.3 + '@types/node': 22.20.1 '@types/koa-compose@3.2.9': dependencies: @@ -23865,7 +23890,7 @@ snapshots: '@types/http-errors': 2.0.5 '@types/keygrip': 1.0.6 '@types/koa-compose': 3.2.9 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/linkify-it@5.0.0': {} @@ -23887,7 +23912,7 @@ snapshots: '@types/mailparser@3.4.6': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 iconv-lite: 0.6.3 '@types/markdown-it@14.1.2': @@ -23919,7 +23944,7 @@ snapshots: '@types/node-fetch@2.6.12': dependencies: - '@types/node': 22.15.18 + '@types/node': 22.20.1 form-data: 4.0.6 '@types/node@18.19.130': @@ -23989,7 +24014,7 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 24.13.3 + '@types/node': 22.20.1 '@types/retry@0.12.2': {} @@ -24000,16 +24025,16 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/send@1.2.1': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/serve-index@1.9.4': dependencies: @@ -24018,19 +24043,19 @@ snapshots: '@types/serve-static@1.15.10': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/send': 0.17.6 '@types/serve-static@1.15.5': dependencies: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/sinon-chai@3.2.12': dependencies: @@ -24047,7 +24072,7 @@ snapshots: '@types/sockjs@0.3.36': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/spotify-api@0.0.25': {} @@ -24080,7 +24105,7 @@ snapshots: '@types/ws@7.4.7': dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 '@types/ws@8.18.1': dependencies: @@ -24098,7 +24123,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 24.13.3 + '@types/node': 22.20.1 optional: true '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': @@ -25624,7 +25649,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 26.1.1 + '@types/node': 22.20.1 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -26038,21 +26063,6 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(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@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(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@26.1.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)): dependencies: '@jest/types': 29.6.3 @@ -28777,7 +28787,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.0 @@ -28854,25 +28864,6 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.1)(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@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.3 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest-cli@29.7.0(@types/node@26.1.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) @@ -28954,7 +28945,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -28980,12 +28971,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.20.1 - ts-node: 10.9.2(@types/node@22.20.1)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@22.15.18)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29011,43 +29002,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.20.1 - ts-node: 10.9.2(@types/node@26.1.1)(typescript@5.4.5) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - jest-config@29.7.0(@types/node@26.1.1)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): - dependencies: - '@babel/core': 7.29.7 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.29.7) - 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': 26.1.1 - ts-node: 10.9.2(@types/node@22.15.18)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@22.19.19)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@26.1.1)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29072,13 +29032,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 26.1.1 - ts-node: 10.9.2(@types/node@22.19.19)(typescript@5.4.5) + '@types/node': 22.20.1 + ts-node: 10.9.2(@types/node@22.20.1)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@26.1.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29103,8 +29063,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 26.1.1 - ts-node: 10.9.2(@types/node@22.20.1)(typescript@5.4.5) + '@types/node': 22.20.1 + ts-node: 10.9.2(@types/node@26.1.1)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -29179,7 +29139,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -29228,7 +29188,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -29263,7 +29223,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -29291,7 +29251,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -29356,7 +29316,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.1 + '@types/node': 22.20.1 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -29412,18 +29372,6 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest@29.7.0(@types/node@26.1.1)(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.1)(typescript@5.4.5)) @@ -31542,7 +31490,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.1 - '@types/node': 26.1.1 + '@types/node': 22.20.1 long: 5.3.2 optional: true From 7ec47270cb7cbdc9ea4a81f2e49ec599be98dc7d Mon Sep 17 00:00:00 2001 From: Robert Gruen Date: Fri, 31 Jul 2026 17:14:33 -0700 Subject: [PATCH 06/22] fixed browser search provider action --- .../browser/src/agent/configActionHandler.mts | 5 ++- .../browser/src/agent/configActionSchema.mts | 6 +-- .../searchProviderCommandHandlers.mts | 11 ++++-- .../browser/test/configActionHandler.test.ts | 6 +++ .../searchProviderCommandHandlers.test.ts | 39 +++++++++++++++++++ 5 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 ts/packages/agents/browser/test/searchProviderCommandHandlers.test.ts diff --git a/ts/packages/agents/browser/src/agent/configActionHandler.mts b/ts/packages/agents/browser/src/agent/configActionHandler.mts index bc6b3aa11a..ca86a6f51c 100644 --- a/ts/packages/agents/browser/src/agent/configActionHandler.mts +++ b/ts/packages/agents/browser/src/agent/configActionHandler.mts @@ -77,7 +77,10 @@ export async function executeBrowserConfigAction( handlers, ["search", "show"], { - args: { provider: action.parameters.provider }, + args: { + provider: + action.parameters?.provider?.trim() || undefined, + }, flags: undefined, }, context, diff --git a/ts/packages/agents/browser/src/agent/configActionSchema.mts b/ts/packages/agents/browser/src/agent/configActionSchema.mts index 7d14e8fbc0..b0a65ee787 100644 --- a/ts/packages/agents/browser/src/agent/configActionSchema.mts +++ b/ts/packages/agents/browser/src/agent/configActionSchema.mts @@ -72,9 +72,9 @@ export type SetSearchProvider = { // Show one browser search provider's configuration. export type ShowSearchProvider = { actionName: "showSearchProvider"; - parameters: { - // Name of the configured search provider. - provider: string; + parameters?: { + // Name of the configured search provider. Omit to show the active provider. + provider?: string; }; }; diff --git a/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts b/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts index 3f6a10ad2a..5b50ce7e95 100644 --- a/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts +++ b/ts/packages/agents/browser/src/agent/searchProvider/searchProviderCommandHandlers.mts @@ -116,7 +116,8 @@ export class ShowCommandHandler implements CommandHandler { args: { provider: { description: - "The name of the search provider to show details for.", + "The name of the search provider to show details for. Omit to show the active provider.", + optional: true, }, }, } as const; @@ -126,12 +127,14 @@ export class ShowCommandHandler implements CommandHandler { ): Promise { const searchProviders: SearchProvider[] = context.sessionContext.agentContext.searchProviders; + const requestedProvider = + params.args.provider?.trim() || + context.sessionContext.agentContext.activeSearchProvider.name; let bFound: boolean = false; searchProviders.forEach((provider) => { if ( - provider.name.toLowerCase() === - params.args.provider.toLowerCase() + provider.name.toLowerCase() === requestedProvider.toLowerCase() ) { displayResult(JSON.stringify(provider, null, 2), context); bFound = true; @@ -141,7 +144,7 @@ export class ShowCommandHandler implements CommandHandler { if (!bFound) { displayError( - `Search provider '${params.args.provider}' not found.`, + `Search provider '${requestedProvider}' not found.`, context, ); } diff --git a/ts/packages/agents/browser/test/configActionHandler.test.ts b/ts/packages/agents/browser/test/configActionHandler.test.ts index 5b709b0943..d6ed31c387 100644 --- a/ts/packages/agents/browser/test/configActionHandler.test.ts +++ b/ts/packages/agents/browser/test/configActionHandler.test.ts @@ -58,6 +58,12 @@ describe("browser config actions", () => { ["search", "show"], { args: { provider: "Bing" }, flags: undefined }, ], + [ + "showSearchProvider", + { provider: "" }, + ["search", "show"], + { args: { provider: undefined }, flags: undefined }, + ], [ "addSearchProvider", { provider: "Example", url: "https://example.com/?q=%s" }, diff --git a/ts/packages/agents/browser/test/searchProviderCommandHandlers.test.ts b/ts/packages/agents/browser/test/searchProviderCommandHandlers.test.ts new file mode 100644 index 0000000000..8fecf0f23a --- /dev/null +++ b/ts/packages/agents/browser/test/searchProviderCommandHandlers.test.ts @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { ShowCommandHandler } from "../src/agent/searchProvider/searchProviderCommandHandlers.mjs"; + +describe("search provider show command", () => { + it("shows the active provider when no provider is specified", async () => { + const displays: unknown[] = []; + const bing = { + name: "Bing", + searchUrl: "https://www.bing.com/search?q=%s", + }; + const context = { + sessionContext: { + agentContext: { + searchProviders: [ + bing, + { + name: "Google", + searchUrl: "https://www.google.com/search?q=%s", + }, + ], + activeSearchProvider: bing, + }, + }, + actionIO: { + appendDisplay: (display: unknown) => displays.push(display), + }, + } as any; + + await new ShowCommandHandler().run(context, { + args: { provider: undefined }, + flags: undefined, + }); + + expect(displays).toContain(JSON.stringify(bing, null, 2)); + expect(JSON.stringify(displays)).not.toContain("not found"); + }); +}); From 2e66fdd4b15cd2ccaec60de9af3f6df9564b0ef7 Mon Sep 17 00:00:00 2001 From: robgruen Date: Fri, 31 Jul 2026 17:22:59 -0700 Subject: [PATCH 07/22] Potential fix for pull request finding 'CodeQL / Bad HTML filtering regexp' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- ts/tools/actionBrowser/test/render.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/tools/actionBrowser/test/render.spec.ts b/ts/tools/actionBrowser/test/render.spec.ts index 0329aa7de7..f168af2833 100644 --- a/ts/tools/actionBrowser/test/render.spec.ts +++ b/ts/tools/actionBrowser/test/render.spec.ts @@ -64,7 +64,7 @@ describe("renderHtml", () => { const html = renderHtml(catalog); const scripts = [ - ...html.matchAll(/]*)?>([\s\S]*?)<\/script>/g), + ...html.matchAll(/]*)?>([\s\S]*?)<\/script>/gi), ]; const executableScript = scripts.at(-1)?.[1]; From 8215b5fe9e69aab3b2bec63ac4bdffec852ea27b Mon Sep 17 00:00:00 2001 From: robgruen Date: Fri, 31 Jul 2026 18:15:42 -0700 Subject: [PATCH 08/22] Potential fix for pull request finding 'CodeQL / Bad HTML filtering regexp' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- ts/tools/actionBrowser/test/render.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/tools/actionBrowser/test/render.spec.ts b/ts/tools/actionBrowser/test/render.spec.ts index f168af2833..366a63ede1 100644 --- a/ts/tools/actionBrowser/test/render.spec.ts +++ b/ts/tools/actionBrowser/test/render.spec.ts @@ -64,7 +64,7 @@ describe("renderHtml", () => { const html = renderHtml(catalog); const scripts = [ - ...html.matchAll(/]*)?>([\s\S]*?)<\/script>/gi), + ...html.matchAll(/]*>([\s\S]*?)<\/script\s*>/gi), ]; const executableScript = scripts.at(-1)?.[1]; From 4b9ee8a92fd62102c2193fe94b66c196d859b105 Mon Sep 17 00:00:00 2001 From: robgruen Date: Fri, 31 Jul 2026 21:41:17 -0700 Subject: [PATCH 09/22] Potential fix for pull request finding 'CodeQL / Bad HTML filtering regexp' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- ts/tools/actionBrowser/test/render.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/tools/actionBrowser/test/render.spec.ts b/ts/tools/actionBrowser/test/render.spec.ts index 366a63ede1..8ff61ae022 100644 --- a/ts/tools/actionBrowser/test/render.spec.ts +++ b/ts/tools/actionBrowser/test/render.spec.ts @@ -64,7 +64,7 @@ describe("renderHtml", () => { const html = renderHtml(catalog); const scripts = [ - ...html.matchAll(/]*>([\s\S]*?)<\/script\s*>/gi), + ...html.matchAll(/]*>([\s\S]*?)<\/script(?:\s+[^>]*)?>/gi), ]; const executableScript = scripts.at(-1)?.[1]; From 5bc01f60e201d00de40f353c62388a6fc3f09648 Mon Sep 17 00:00:00 2001 From: typeagent-bot Date: Sat, 1 Aug 2026 04:44:11 +0000 Subject: [PATCH 10/22] style: apply prettier formatting and policy fixes --- ts/tools/actionBrowser/test/render.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ts/tools/actionBrowser/test/render.spec.ts b/ts/tools/actionBrowser/test/render.spec.ts index 8ff61ae022..04ba7b3375 100644 --- a/ts/tools/actionBrowser/test/render.spec.ts +++ b/ts/tools/actionBrowser/test/render.spec.ts @@ -64,7 +64,9 @@ describe("renderHtml", () => { const html = renderHtml(catalog); const scripts = [ - ...html.matchAll(/]*>([\s\S]*?)<\/script(?:\s+[^>]*)?>/gi), + ...html.matchAll( + /]*>([\s\S]*?)<\/script(?:\s+[^>]*)?>/gi, + ), ]; const executableScript = scripts.at(-1)?.[1]; From 1dca36cc910afb84149cab4b500e374656d1fe48 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 3 Aug 2026 00:04:42 +0000 Subject: [PATCH 11/22] fix: reduce complexity in configActionHandler, grammarActionHandler, and cli.ts --- .../system/action/collisionActionHandler.ts | 577 +++++++++--------- .../system/action/configActionHandler.ts | 101 ++- .../action/constructionActionHandler.ts | 95 ++- .../system/action/feedbackActionHandler.ts | 102 ++-- .../system/action/grammarActionHandler.ts | 35 +- .../action/systemOperationsActionHandler.ts | 59 +- ts/tools/actionBrowser/src/cli.ts | 90 +-- 7 files changed, 546 insertions(+), 513 deletions(-) diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts index 9d1948e95c..70e8d72655 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts @@ -18,279 +18,242 @@ function csv(values: string[] | undefined): string | undefined { return values?.join(","); } -export function executeCollisionAction( - action: TypeAgentAction, - context: ActionContext, - handlers: CommandHandlerTable, - commandExecutor: typeof executeCommandFromHandlers = executeCommandFromHandlers, -): Promise { - const execute = (commands: string[], params?: ParsedCommandParams) => - commandExecutor(handlers, commands, params, context); - const params: any = "parameters" in action ? action.parameters : undefined; +/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ +function opt(value: unknown, key: string): Record { + return value !== undefined ? { [key]: value } : {}; +} - switch (action.actionName) { - case "showCollisionEvents": - return execute(["events"], { - args: {}, - flags: { - limit: params?.limit ?? 10, - ...(params?.kind === undefined - ? {} - : { kind: params.kind }), - }, - }); - case "findSimilarActions": - return execute(["similar"], { - args: {}, - flags: { - threshold: params?.threshold ?? 0.85, - strategy: params?.strategy ?? "balanced", - "all-strategies": params?.allStrategies ?? false, - pairs: params?.pairs ?? false, - top: params?.top ?? 50, - ...(params?.jsonPath === undefined - ? {} - : { json: params.jsonPath }), - "no-cache": params?.noCache ?? false, - }, - }); - case "listCollisionStrategies": - return execute(["list-strategies"], { args: {}, flags: {} }); - case "probeCollisionPhrase": - return execute(["probe"], { - args: { phrase: params.phrase }, - flags: { - top: params.top ?? 5, - ...(params.expected === undefined - ? {} - : { expected: params.expected }), - delta: params.delta ?? 0.05, - "include-inactive": params.includeInactive ?? false, - }, - }); +type Executor = ( + commands: string[], + params?: ParsedCommandParams, +) => Promise; + +// --------------------------------------------------------------------------- +// Action-name groups used for dispatching in executeCollisionAction +// --------------------------------------------------------------------------- +const CORPUS_GEN_ACTIONS = new Set([ + "generateCollisionCorpus", + "probeCollisionCorpus", + "translateCollisionCorpus", + "reanalyzeCollisionCorpus", +]); + +const CORPUS_VIZ_ACTIONS = new Set([ + "visualizeCollisionCorpus", + "runCollisionCorpusPipeline", + "analyzeCollisionRecovery", + "visualizeCollisionRecovery", +]); + +const KEYWORDS_ACTIONS = new Set([ + "manageCollisionKeywords", + "backfillCollisionKeywords", + "buildCollisionNeighborhoods", +]); + +const OPTIMIZE_CORE_ACTIONS = new Set([ + "listCollisionOptimizationLevers", + "exploreCollisionOptimizations", + "validateCollisionOptimizations", + "mineCollisionOptimizationPatterns", +]); + +const OPTIMIZE_PIPELINE_ACTIONS = new Set([ + "runCollisionOptimizationPipeline", + "distillCollisionOptimizationPatterns", + "browseCollisionOptimizationRuns", +]); + +const PREFERENCES_ACTIONS = new Set([ + "listCollisionPreferences", + "setCollisionPreference", + "removeCollisionPreference", + "clearCollisionPreferences", +]); + +// --------------------------------------------------------------------------- +// Sub-handlers (one per logical action group) +// --------------------------------------------------------------------------- + +function executeCollisionCorpusGenAction( + actionName: string, + p: any, + execute: Executor, +): Promise { + switch (actionName) { case "generateCollisionCorpus": return execute(["corpus", "generate"], { args: {}, flags: { - ...(params?.schemas === undefined - ? {} - : { schemas: csv(params.schemas) }), - ...(params?.models === undefined - ? {} - : { models: csv(params.models) }), - ...(params?.styles === undefined - ? {} - : { styles: csv(params.styles) }), - concurrency: params?.concurrency ?? 8, - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(csv(p.schemas), "schemas"), + ...opt(csv(p.models), "models"), + ...opt(csv(p.styles), "styles"), + concurrency: p.concurrency ?? 8, + ...opt(p.outputPath, "out"), + ...opt(p.workdir, "workdir"), }, }); case "probeCollisionCorpus": return execute(["corpus", "probe"], { args: {}, flags: { - ...(params?.inputPath === undefined - ? {} - : { in: params.inputPath }), - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - top: params?.top ?? 5, - delta: params?.delta ?? 0.05, - concurrency: params?.concurrency ?? 8, - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(p.inputPath, "in"), + ...opt(p.outputPath, "out"), + top: p.top ?? 5, + delta: p.delta ?? 0.05, + concurrency: p.concurrency ?? 8, + ...opt(p.workdir, "workdir"), }, }); case "translateCollisionCorpus": return execute(["corpus", "translate"], { args: {}, flags: { - ...(params?.inputPath === undefined - ? {} - : { in: params.inputPath }), - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - concurrency: params?.concurrency ?? 4, - strategy: params?.strategy ?? "first-match", - ...(params?.maxPhrases === undefined - ? {} - : { "max-phrases": params.maxPhrases }), - ...(params?.modelLabel === undefined - ? {} - : { "model-label": params.modelLabel }), - "user-context-mode": params?.userContextMode ?? "none", - ...(params?.userContextJson === undefined - ? {} - : { "user-context-json": params.userContextJson }), - ...(params?.outputSuffix === undefined - ? {} - : { "output-suffix": params.outputSuffix }), - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(p.inputPath, "in"), + ...opt(p.outputPath, "out"), + concurrency: p.concurrency ?? 4, + strategy: p.strategy ?? "first-match", + ...opt(p.maxPhrases, "max-phrases"), + ...opt(p.modelLabel, "model-label"), + "user-context-mode": p.userContextMode ?? "none", + ...opt(p.userContextJson, "user-context-json"), + ...opt(p.outputSuffix, "output-suffix"), + ...opt(p.workdir, "workdir"), }, }); case "reanalyzeCollisionCorpus": return execute(["corpus", "reanalyze"], { args: {}, flags: { - ...(params?.inputPath === undefined - ? {} - : { in: params.inputPath }), - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - delta: params?.delta ?? 0.05, - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(p.inputPath, "in"), + ...opt(p.outputPath, "out"), + delta: p.delta ?? 0.05, + ...opt(p.workdir, "workdir"), }, }); + default: + throw new Error(`Unknown corpus gen action: ${actionName}`); + } +} + +function executeCollisionCorpusVizAction( + actionName: string, + p: any, + execute: Executor, +): Promise { + switch (actionName) { case "visualizeCollisionCorpus": return execute(["corpus", "visualize"], { args: {}, flags: { - ...(params?.inputPath === undefined - ? {} - : { in: params.inputPath }), - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - top: params?.top ?? 60, - "similarity-strategy": - params?.similarityStrategy ?? "balanced", + ...opt(p.inputPath, "in"), + ...opt(p.outputPath, "out"), + top: p.top ?? 60, + "similarity-strategy": p.similarityStrategy ?? "balanced", "similarity-threshold": String( - params?.similarityThreshold ?? 0.85, + p.similarityThreshold ?? 0.85, ), - "no-similarity": params?.noSimilarity ?? false, - ...(params?.translatorPath === undefined - ? {} - : { translator: params.translatorPath }), - "no-translator": params?.noTranslator ?? false, - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + "no-similarity": p.noSimilarity ?? false, + ...opt(p.translatorPath, "translator"), + "no-translator": p.noTranslator ?? false, + ...opt(p.workdir, "workdir"), }, }); case "runCollisionCorpusPipeline": return execute(["corpus", "run"], { args: {}, flags: { - from: params?.from ?? "generate", - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), - ...(params?.schemas === undefined - ? {} - : { schemas: csv(params.schemas) }), - ...(params?.models === undefined - ? {} - : { models: csv(params.models) }), - ...(params?.styles === undefined - ? {} - : { styles: csv(params.styles) }), - concurrency: params?.concurrency ?? 8, - delta: params?.delta ?? 0.05, - top: params?.top ?? 5, - "sankey-top": params?.sankeyTop ?? 60, + from: p.from ?? "generate", + ...opt(p.workdir, "workdir"), + ...opt(csv(p.schemas), "schemas"), + ...opt(csv(p.models), "models"), + ...opt(csv(p.styles), "styles"), + concurrency: p.concurrency ?? 8, + delta: p.delta ?? 0.05, + top: p.top ?? 5, + "sankey-top": p.sankeyTop ?? 60, }, }); case "analyzeCollisionRecovery": return execute(["corpus", "recovery"], { args: {}, flags: { - ...(params?.inputPath === undefined - ? {} - : { in: params.inputPath }), - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), - delta: params?.delta ?? 0.05, + ...opt(p.inputPath, "in"), + ...opt(p.workdir, "workdir"), + delta: p.delta ?? 0.05, }, }); case "visualizeCollisionRecovery": return execute(["corpus", "visualize-recovery"], { args: {}, flags: { - ...(params?.inputPath === undefined - ? {} - : { in: params.inputPath }), - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - delta: params?.delta ?? 0.05, - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(p.inputPath, "in"), + ...opt(p.outputPath, "out"), + delta: p.delta ?? 0.05, + ...opt(p.workdir, "workdir"), }, }); + default: + throw new Error(`Unknown corpus viz action: ${actionName}`); + } +} + +function executeCollisionKeywordsAction( + actionName: string, + p: any, + execute: Executor, +): Promise { + switch (actionName) { case "manageCollisionKeywords": { const operation = - params?.operation ?? - (params?.target === undefined ? "listOverrides" : "show"); + p.operation ?? (p.target === undefined ? "listOverrides" : "show"); if (operation === "listOverrides") { - return execute(["keywords"], { - args: {}, - flags: {}, - }); + return execute(["keywords"], { args: {}, flags: {} }); } - if (params?.target === undefined) { + if (p.target === undefined) { throw new Error( `A target is required to ${operation} collision keywords.`, ); } return execute(["keywords"], { args: { - tokens: [ - params.target, - operation, - ...(params.keywords ?? []), - ], + tokens: [p.target, operation, ...(p.keywords ?? [])], }, flags: {}, } as unknown as ParsedCommandParams); } case "backfillCollisionKeywords": return execute(["keywords", "backfill"], { - args: { - ...(params?.schemas === undefined - ? {} - : { schemas: params.schemas }), - }, + args: { ...opt(p.schemas, "schemas") }, flags: { - llm: params?.useLlm ?? false, - force: params?.force ?? false, + llm: p.useLlm ?? false, + force: p.force ?? false, }, } as unknown as ParsedCommandParams); case "buildCollisionNeighborhoods": return execute(["neighborhoods"], { args: {}, flags: { - ...(params?.corpusPath === undefined - ? {} - : { corpus: params.corpusPath }), - "min-misroute": params?.minMisroute ?? 2, - "include-same-schema": params?.includeSameSchema ?? true, - "samples-per-category": params?.samplesPerCategory ?? 5, - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - ...(params?.outputHtmlPath === undefined - ? {} - : { "out-html": params.outputHtmlPath }), - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(p.corpusPath, "corpus"), + "min-misroute": p.minMisroute ?? 2, + "include-same-schema": p.includeSameSchema ?? true, + "samples-per-category": p.samplesPerCategory ?? 5, + ...opt(p.outputPath, "out"), + ...opt(p.outputHtmlPath, "out-html"), + ...opt(p.workdir, "workdir"), }, }); + default: + throw new Error(`Unknown keywords action: ${actionName}`); + } +} + +function executeCollisionOptimizeCoreAction( + actionName: string, + p: any, + execute: Executor, +): Promise { + switch (actionName) { case "listCollisionOptimizationLevers": return execute(["optimize", "list-levers"], { args: {}, @@ -300,136 +263,186 @@ export function executeCollisionAction( return execute(["optimize", "explore"], { args: {}, flags: { - ...(params?.corpusPath === undefined - ? {} - : { corpus: params.corpusPath }), - ...(params?.baselinePath === undefined - ? {} - : { baseline: params.baselinePath }), - top: params?.top ?? 5, - "hypotheses-per-lever": params?.hypothesesPerLever ?? 3, - depth: params?.depth ?? 2, - ...(params?.levers === undefined - ? {} - : { lever: csv(params.levers) }), - severity: csv(params?.severities) ?? "blocker,leaky", - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), - "dry-run": params?.dryRun ?? false, - concurrency: params?.concurrency ?? 8, + ...opt(p.corpusPath, "corpus"), + ...opt(p.baselinePath, "baseline"), + top: p.top ?? 5, + "hypotheses-per-lever": p.hypothesesPerLever ?? 3, + depth: p.depth ?? 2, + ...opt(csv(p.levers), "lever"), + severity: csv(p.severities) ?? "blocker,leaky", + ...opt(p.workdir, "workdir"), + "dry-run": p.dryRun ?? false, + concurrency: p.concurrency ?? 8, }, }); case "validateCollisionOptimizations": return execute(["optimize", "validate"], { args: {}, flags: { - ...(params?.runId === undefined - ? {} - : { run: params.runId }), - ...(params?.neighborhoodId === undefined - ? {} - : { phrases: params.neighborhoodId }), - ...(params?.baselinePath === undefined - ? {} - : { baseline: params.baselinePath }), - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), - ...(params?.winners === undefined - ? {} - : { winners: csv(params.winners) }), - ...(params?.leaveOneOut === undefined - ? {} - : { "leave-one-out": csv(params.leaveOneOut) }), + ...opt(p.runId, "run"), + ...opt(p.neighborhoodId, "phrases"), + ...opt(p.baselinePath, "baseline"), + ...opt(p.workdir, "workdir"), + ...opt(csv(p.winners), "winners"), + ...opt(csv(p.leaveOneOut), "leave-one-out"), }, }); case "mineCollisionOptimizationPatterns": return execute(["optimize", "patterns"], { args: {}, flags: { - ...(params?.patternsFile === undefined - ? {} - : { "patterns-file": params.patternsFile }), - "min-attempts": params?.minAttempts ?? 5, - "surface-disagreement": String( - params?.surfaceDisagreement ?? 0.5, - ), - ...(params?.outputPath === undefined - ? {} - : { out: params.outputPath }), - ...(params?.outputHtmlPath === undefined - ? {} - : { "out-html": params.outputHtmlPath }), - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(p.patternsFile, "patterns-file"), + "min-attempts": p.minAttempts ?? 5, + "surface-disagreement": String(p.surfaceDisagreement ?? 0.5), + ...opt(p.outputPath, "out"), + ...opt(p.outputHtmlPath, "out-html"), + ...opt(p.workdir, "workdir"), }, }); + default: + throw new Error(`Unknown optimize core action: ${actionName}`); + } +} + +function executeCollisionOptimizePipelineAction( + actionName: string, + p: any, + execute: Executor, +): Promise { + switch (actionName) { case "runCollisionOptimizationPipeline": return execute(["optimize", "run"], { args: {}, flags: { - from: params?.from ?? "neighborhoods", - top: params?.top ?? 5, - depth: params?.depth ?? 2, - ...(params?.levers === undefined - ? {} - : { lever: csv(params.levers) }), - severity: csv(params?.severities) ?? "blocker,leaky", - "dry-run": params?.dryRun ?? false, - "skip-distill": params?.skipDistill ?? false, - "distill-min-attempts": params?.distillMinAttempts ?? 10, - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + from: p.from ?? "neighborhoods", + top: p.top ?? 5, + depth: p.depth ?? 2, + ...opt(csv(p.levers), "lever"), + severity: csv(p.severities) ?? "blocker,leaky", + "dry-run": p.dryRun ?? false, + "skip-distill": p.skipDistill ?? false, + "distill-min-attempts": p.distillMinAttempts ?? 10, + ...opt(p.workdir, "workdir"), }, }); case "distillCollisionOptimizationPatterns": return execute(["optimize", "distill"], { args: {}, flags: { - "min-attempts": params?.minAttempts ?? 10, - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + "min-attempts": p.minAttempts ?? 10, + ...opt(p.workdir, "workdir"), }, }); case "browseCollisionOptimizationRuns": return execute(["optimize", "browse"], { args: {}, flags: { - ...(params?.runId === undefined - ? {} - : { run: params.runId }), - all: params?.all ?? false, - ...(params?.workdir === undefined - ? {} - : { workdir: params.workdir }), + ...opt(p.runId, "run"), + all: p.all ?? false, + ...opt(p.workdir, "workdir"), }, }); + default: + throw new Error(`Unknown optimize pipeline action: ${actionName}`); + } +} + +function executeCollisionPreferencesAction( + actionName: string, + p: any, + execute: Executor, +): Promise { + switch (actionName) { case "listCollisionPreferences": - return execute(["preferences", "list"], { - args: {}, - flags: {}, - }); + return execute(["preferences", "list"], { args: {}, flags: {} }); case "setCollisionPreference": return execute(["preferences", "set"], { args: { - candidates: params.candidates.join(","), - chosen: params.chosen, + candidates: p.candidates.join(","), + chosen: p.chosen, }, flags: {}, }); case "removeCollisionPreference": return execute(["preferences", "remove"], { - args: { key: params.key }, + args: { key: p.key }, flags: {}, }); case "clearCollisionPreferences": - return execute(["preferences", "clear"], { + return execute(["preferences", "clear"], { args: {}, flags: {} }); + default: + throw new Error(`Unknown preferences action: ${actionName}`); + } +} + +// --------------------------------------------------------------------------- +// Main dispatcher +// --------------------------------------------------------------------------- + +export function executeCollisionAction( + action: TypeAgentAction, + context: ActionContext, + handlers: CommandHandlerTable, + commandExecutor: typeof executeCommandFromHandlers = executeCommandFromHandlers, +): Promise { + const execute: Executor = (commands, params) => + commandExecutor(handlers, commands, params, context); + const p: any = "parameters" in action ? action.parameters : {}; + + if (CORPUS_GEN_ACTIONS.has(action.actionName)) { + return executeCollisionCorpusGenAction(action.actionName, p, execute); + } + if (CORPUS_VIZ_ACTIONS.has(action.actionName)) { + return executeCollisionCorpusVizAction(action.actionName, p, execute); + } + if (KEYWORDS_ACTIONS.has(action.actionName)) { + return executeCollisionKeywordsAction(action.actionName, p, execute); + } + if (OPTIMIZE_CORE_ACTIONS.has(action.actionName)) { + return executeCollisionOptimizeCoreAction(action.actionName, p, execute); + } + if (OPTIMIZE_PIPELINE_ACTIONS.has(action.actionName)) { + return executeCollisionOptimizePipelineAction(action.actionName, p, execute); + } + if (PREFERENCES_ACTIONS.has(action.actionName)) { + return executeCollisionPreferencesAction(action.actionName, p, execute); + } + + switch (action.actionName) { + case "showCollisionEvents": + return execute(["events"], { args: {}, - flags: {}, + flags: { + limit: p.limit ?? 10, + ...opt(p.kind, "kind"), + }, + }); + case "findSimilarActions": + return execute(["similar"], { + args: {}, + flags: { + threshold: p.threshold ?? 0.85, + strategy: p.strategy ?? "balanced", + "all-strategies": p.allStrategies ?? false, + pairs: p.pairs ?? false, + top: p.top ?? 50, + ...opt(p.jsonPath, "json"), + "no-cache": p.noCache ?? false, + }, + }); + case "listCollisionStrategies": + return execute(["list-strategies"], { args: {}, flags: {} }); + case "probeCollisionPhrase": + return execute(["probe"], { + args: { phrase: p.phrase }, + flags: { + top: p.top ?? 5, + ...opt(p.expected, "expected"), + delta: p.delta ?? 0.05, + "include-inactive": p.includeInactive ?? false, + }, }); + default: + throw new Error(`Unknown collision action: ${action.actionName}`); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts index ab8cf022d5..9f01da7108 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts @@ -67,28 +67,22 @@ function parseConfigValue( return parsed; } -function getConfigCommandParams( - action: RunConfigCommandAction, - handlers: CommandHandlerTable, -): ParsedCommandParams | undefined { - const { command, arguments: args = [], flags } = action.parameters; - const handler = getCommandHandler(handlers, command.split(" ")); - if (handler.parameters === undefined || handler.parameters === false) { - const hasFlagValue = - flags !== undefined && - Object.values(flags).some((value) => value !== undefined); - if (args.length > 0 || hasFlagValue) { - throw new Error(`Config command '${command}' takes no parameters.`); - } - return undefined; - } - +function parseConfigArgs( + command: string, + args: string[], + argDefs: Record< + string, + { type?: string; multiple?: boolean; optional?: boolean } + >, +): Record { const parsedArgs: Record = {}; let argumentIndex = 0; - for (const [name, definition] of Object.entries( - handler.parameters.args ?? {}, - )) { - const type = definition.type ?? "string"; + for (const [name, definition] of Object.entries(argDefs)) { + const type = (definition.type ?? "string") as + | "string" + | "number" + | "boolean" + | "json"; if (definition.multiple) { const values = args.slice(argumentIndex); if (values.length === 0 && !definition.optional) { @@ -115,20 +109,29 @@ function getConfigCommandParams( if (argumentIndex !== args.length) { throw new Error(`Too many arguments for config command '${command}'.`); } + return parsedArgs; +} - const flagDefinitions = handler.parameters.flags ?? {}; - const suppliedFlags = flags ?? {}; +function parseConfigFlags( + command: string, + suppliedFlags: Record, + flagDefs: Record, +): Record { for (const [name, value] of Object.entries(suppliedFlags)) { - if (value !== undefined && flagDefinitions[name] === undefined) { + if (value !== undefined && flagDefs[name] === undefined) { throw new Error( `Config command '${command}' does not accept flag '${name}'.`, ); } } const parsedFlags: Record = {}; - for (const [name, definition] of Object.entries(flagDefinitions)) { - const value = suppliedFlags[name as keyof typeof suppliedFlags]; - const type = getFlagType(definition); + for (const [name, definition] of Object.entries(flagDefs)) { + const value = suppliedFlags[name]; + const type = getFlagType(definition as any) as + | "string" + | "number" + | "boolean" + | "json"; if (value === undefined) { if (definition.default !== undefined) { parsedFlags[name] = structuredClone(definition.default); @@ -139,20 +142,60 @@ function getConfigCommandParams( if (!Array.isArray(value)) { throw new Error(`Config flag '${name}' expects an array.`); } - parsedFlags[name] = value.map((item) => + parsedFlags[name] = value.map((item: any) => parseConfigValue(item, type, name), ); } else { if (Array.isArray(value)) { throw new Error(`Config flag '${name}' is not repeatable.`); } - parsedFlags[name] = parseConfigValue(value, type, name); + parsedFlags[name] = parseConfigValue( + value as string | boolean, + type, + name, + ); } } + return parsedFlags; +} + +function getConfigCommandParams( + action: RunConfigCommandAction, + handlers: CommandHandlerTable, +): ParsedCommandParams | undefined { + const { command, arguments: args = [], flags } = action.parameters; + const handler = getCommandHandler(handlers, command.split(" ")); + if (handler.parameters === undefined || handler.parameters === false) { + const hasFlagValue = + flags !== undefined && + Object.values(flags).some((value) => value !== undefined); + if (args.length > 0 || hasFlagValue) { + throw new Error(`Config command '${command}' takes no parameters.`); + } + return undefined; + } + + const parsedArgs = parseConfigArgs( + command, + args, + (handler.parameters.args ?? {}) as Record< + string, + { type?: string; multiple?: boolean; optional?: boolean } + >, + ); + const parsedFlags = parseConfigFlags( + command, + (flags ?? {}) as Record, + (handler.parameters.flags ?? {}) as Record< + string, + { multiple?: boolean; default?: unknown } + >, + ); return { args: handler.parameters.args === undefined ? undefined : parsedArgs, - flags: handler.parameters.flags === undefined ? undefined : parsedFlags, + flags: + handler.parameters.flags === undefined ? undefined : parsedFlags, } as ParsedCommandParams; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts index 9401d6e770..7c34b8bd97 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts @@ -14,6 +14,31 @@ import { import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConstructionAction } from "../schema/constructionActionSchema.js"; +/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ +function opt(value: unknown, key: string): Record { + return value !== undefined ? { [key]: value } : {}; +} + +const STORE_CMDS: Record = { + newConstructionStore: "new", + loadConstructionStore: "load", + saveConstructionStore: "save", +}; + +function executeConstructionStoreAction( + actionName: string, + p: any, + execute: ( + commands: string[], + params?: ParsedCommandParams, + ) => Promise, +): Promise { + return execute([STORE_CMDS[actionName]], { + args: { ...opt(p.file, "file") }, + flags: {}, + }); +} + export function executeConstructionAction( action: TypeAgentAction, context: ActionContext, @@ -23,30 +48,15 @@ export function executeConstructionAction( executeCommandFromHandlers(handlers, commands, params, context); const toggle = (commands: string[], enabled: boolean) => execute([...commands, enabled ? "on" : "off"]); + const p: any = action.parameters; + + if (action.actionName in STORE_CMDS) { + return executeConstructionStoreAction(action.actionName, p, execute); + } switch (action.actionName) { - case "newConstructionStore": - case "loadConstructionStore": - case "saveConstructionStore": - return execute( - [ - action.actionName === "newConstructionStore" - ? "new" - : action.actionName === "loadConstructionStore" - ? "load" - : "save", - ], - { - args: { - ...(action.parameters?.file === undefined - ? {} - : { file: action.parameters.file }), - }, - flags: {}, - }, - ); case "setConstructionAutoSave": - return toggle(["auto"], action.parameters.enabled); + return toggle(["auto"], p.enabled); case "disableConstructionStore": return execute(["off"]); case "showConstructionInfo": @@ -55,48 +65,35 @@ export function executeConstructionAction( return execute(["list"], { args: {}, flags: { - verbose: action.parameters?.verbose ?? false, - all: action.parameters?.allMatchStrings ?? false, - builtin: action.parameters?.builtIn ?? false, - ...(action.parameters?.match === undefined - ? {} - : { match: action.parameters.match }), - ...(action.parameters?.part === undefined - ? {} - : { part: action.parameters.part }), - ...(action.parameters?.ids === undefined - ? {} - : { id: action.parameters.ids }), + verbose: p.verbose ?? false, + all: p.allMatchStrings ?? false, + builtin: p.builtIn ?? false, + ...opt(p.match, "match"), + ...opt(p.part, "part"), + ...opt(p.ids, "id"), }, } as unknown as ParsedCommandParams); case "importConstructions": return execute(["import"], { - args: { - ...(action.parameters?.files === undefined - ? {} - : { file: action.parameters.files }), - }, - flags: { - extended: action.parameters?.extended ?? false, - }, + args: { ...opt(p.files, "file") }, + flags: { extended: p.extended ?? false }, } as unknown as ParsedCommandParams); case "pruneConstructions": return execute(["prune"]); case "deleteConstruction": return execute(["delete"], { - args: { - namespace: action.parameters.namespace, - id: action.parameters.id, - }, + args: { namespace: p.namespace, id: p.id }, flags: {}, }); case "setBuiltInConstructionCache": - return toggle(["builtin"], action.parameters.enabled); + return toggle(["builtin"], p.enabled); case "setConstructionMerge": - return toggle(["merge"], action.parameters.enabled); + return toggle(["merge"], p.enabled); case "setWildcardMatching": - return toggle(["wildcard"], action.parameters.enabled); + return toggle(["wildcard"], p.enabled); case "setEntityWildcardMatching": - return toggle(["wildcard", "entity"], action.parameters.enabled); + return toggle(["wildcard", "entity"], p.enabled); + default: + throw new Error(`Unknown construction action: ${action.actionName}`); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts index e0627f82e7..8852ff15a0 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts @@ -13,83 +13,59 @@ import { import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { FeedbackAction } from "../schema/feedbackActionSchema.js"; +/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ +function opt(value: unknown, key: string): Record { + return value !== undefined ? { [key]: value } : {}; +} + export function executeFeedbackAction( action: TypeAgentAction, context: ActionContext, handlers: CommandHandlerTable, ): Promise { + const execute = (commands: string[], params?: any) => + executeCommandFromHandlers(handlers, commands, params, context); + const p: any = action.parameters; + switch (action.actionName) { case "listFeedback": - return executeCommandFromHandlers( - handlers, - ["list"], - { - args: {}, - flags: { - limit: action.parameters?.limit ?? 20, - all: action.parameters?.includeAllEntries ?? false, - }, + return execute(["list"], { + args: {}, + flags: { + limit: p.limit ?? 20, + all: p.includeAllEntries ?? false, }, - context, - ); + }); case "summarizeFeedback": - return executeCommandFromHandlers( - handlers, - ["top"], - { - args: {}, - flags: { - limit: action.parameters?.categoryLimit ?? 10, - }, - }, - context, - ); + return execute(["top"], { + args: {}, + flags: { limit: p.categoryLimit ?? 10 }, + }); case "filterFeedback": - return executeCommandFromHandlers( - handlers, - ["filter"], - { - args: {}, - flags: { - ...(action.parameters?.rating === undefined - ? {} - : { rating: action.parameters.rating }), - ...(action.parameters?.category === undefined - ? {} - : { category: action.parameters.category }), - ...(action.parameters?.since === undefined - ? {} - : { since: action.parameters.since }), - ...(action.parameters?.until === undefined - ? {} - : { until: action.parameters.until }), - limit: action.parameters?.limit ?? 50, - all: action.parameters?.includeAllEntries ?? false, - }, + return execute(["filter"], { + args: {}, + flags: { + ...opt(p.rating, "rating"), + ...opt(p.category, "category"), + ...opt(p.since, "since"), + ...opt(p.until, "until"), + limit: p.limit ?? 50, + all: p.includeAllEntries ?? false, }, - context, - ); + }); case "exportFeedback": - return executeCommandFromHandlers( - handlers, - ["export"], - { - args: { file: action.parameters.file }, - flags: { - ...(action.parameters.format === undefined - ? {} - : { format: action.parameters.format }), - all: action.parameters.includeAllEntries ?? false, - }, + return execute(["export"], { + args: { file: p.file }, + flags: { + ...opt(p.format, "format"), + all: p.includeAllEntries ?? false, }, - context, - ); + }); case "countFeedback": - return executeCommandFromHandlers( - handlers, - ["count"], - undefined, - context, + return execute(["count"], undefined); + default: + throw new Error( + `Unknown feedback action: ${action.actionName}`, ); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts index adc904f9cd..d8710b548b 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts @@ -18,6 +18,27 @@ import { StoredGrammarRule } from "@typeagent/action-grammar"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { GrammarAction } from "../schema/grammarActionSchema.js"; +/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ +function opt(value: unknown, key: string): Record { + return value !== undefined ? { [key]: value } : {}; +} + +function executeScanGrammarCollisionsAction( + action: TypeAgentAction, + context: ActionContext, + systemHandlers: CommandHandlerTable, +): Promise { + return executeCommandFromHandlers( + systemHandlers, + ["grammar", "collisions"], + { + args: {}, + flags: { ...opt(action.parameters?.jsonPath, "json") }, + }, + context, + ); +} + export async function executeGrammarAction( action: TypeAgentAction, context: ActionContext, @@ -27,19 +48,7 @@ export async function executeGrammarAction( if (systemHandlers === undefined) { throw new Error("System command handlers are unavailable."); } - return executeCommandFromHandlers( - systemHandlers, - ["grammar", "collisions"], - { - args: {}, - flags: { - ...(action.parameters?.jsonPath === undefined - ? {} - : { json: action.parameters.jsonPath }), - }, - }, - context, - ); + return executeScanGrammarCollisionsAction(action, context, systemHandlers); } const chc = context.sessionContext.agentContext; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts index c97f393ae5..58385d61e3 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts @@ -14,6 +14,11 @@ import { import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { SystemOperationsAction } from "../schema/systemOperationsActionSchema.js"; +/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ +function opt(value: unknown, key: string): Record { + return value !== undefined ? { [key]: value } : {}; +} + export function executeSystemOperationsAction( action: TypeAgentAction, context: ActionContext, @@ -21,28 +26,22 @@ export function executeSystemOperationsAction( ): Promise { const execute = (commands: string[], params?: ParsedCommandParams) => executeCommandFromHandlers(systemHandlers, commands, params, context); + const p: any = action.parameters; switch (action.actionName) { case "executeTypedAction": { const actionParameters = - action.parameters.actionParametersJson === undefined + p.actionParametersJson === undefined ? undefined - : JSON.parse(action.parameters.actionParametersJson); + : JSON.parse(p.actionParametersJson); return execute(["action"], { args: { - schemaName: action.parameters.schemaName, - actionName: action.parameters.actionName, + schemaName: p.schemaName, + actionName: p.actionName, }, flags: { - ...(actionParameters === undefined - ? {} - : { parameters: actionParameters }), - ...(action.parameters.naturalLanguage === undefined - ? {} - : { - naturalLanguage: - action.parameters.naturalLanguage, - }), + ...opt(actionParameters, "parameters"), + ...opt(p.naturalLanguage, "naturalLanguage"), }, } as unknown as ParsedCommandParams); } @@ -55,38 +54,34 @@ export function executeSystemOperationsAction( case "showQuestionCards": return execute(["demo", "questionCards"], { args: {}, - flags: { paged: action.parameters?.paged ?? false }, + flags: { paged: p.paged ?? false }, }); case "displayContent": return execute(["display"], { - args: { text: action.parameters.content }, + args: { text: p.content }, flags: { - speak: action.parameters.speak ?? false, - type: action.parameters.type ?? "text", - inline: action.parameters.inline ?? false, + speak: p.speak ?? false, + type: p.type ?? "text", + inline: p.inline ?? false, }, } as unknown as ParsedCommandParams); case "exitTypeAgent": return execute(["exit"]); case "showCommandHelp": return execute(["help"], { - args: { - ...(action.parameters?.command === undefined - ? {} - : { command: action.parameters.command }), - }, - flags: { all: action.parameters?.all ?? false }, + args: { ...opt(p.command, "command") }, + flags: { all: p.all ?? false }, }); case "openFolder": return execute(["open"], { - args: { folder: action.parameters.folder }, + args: { folder: p.folder }, flags: {}, }); case "listRegisteredPorts": return execute(["ports"], { args: {}, flags: {} }); case "runCommandScript": return execute(["run"], { - args: { input: action.parameters.input }, + args: { input: p.input }, flags: {}, }); case "restartAgentServer": @@ -95,12 +90,12 @@ export function executeSystemOperationsAction( return execute(["shutdown"]); case "configureTrace": return execute(["trace"], { - args: { - ...(action.parameters?.namespaces === undefined - ? {} - : { namespaces: action.parameters.namespaces }), - }, - flags: { clear: action.parameters?.clear ?? false }, + args: { ...opt(p.namespaces, "namespaces") }, + flags: { clear: p.clear ?? false }, } as unknown as ParsedCommandParams); + default: + throw new Error( + `Unknown system operations action: ${action.actionName}`, + ); } } diff --git a/ts/tools/actionBrowser/src/cli.ts b/ts/tools/actionBrowser/src/cli.ts index 6820f8e1f9..ce452afc6f 100644 --- a/ts/tools/actionBrowser/src/cli.ts +++ b/ts/tools/actionBrowser/src/cli.ts @@ -37,6 +37,50 @@ function defaultOutPath(): string { return path.join(tsDir, "docs", "overview", "action-browser.html"); } +async function runCheckMode( + catalog: Awaited>, + allowMissing: boolean, +): Promise { + const issues = catalog.commandActionLinkIssues; + const missing = catalog.missingCommandActions; + process.stdout.write( + `Command action coverage: ${catalog.counts.linkedCommandEndpoints} / ` + + `${catalog.counts.commandEndpoints} endpoints ` + + `(${missing.length} missing, ${issues.length} invalid)\n`, + ); + for (const issue of issues) { + const command = + issue.host === "system" + ? `@${issue.path}` + : issue.path.length > 0 + ? `@${issue.host} ${issue.path}` + : `@${issue.host}`; + const action = issue.schema + ? `${issue.schema}.${issue.actionName}` + : issue.actionName; + process.stderr.write(`${command} -> ${action}: ${issue.message}\n`); + } + if (!allowMissing) { + for (const gap of missing) { + const command = + gap.host === "system" + ? `@${gap.path}` + : gap.path.length > 0 + ? `@${gap.host} ${gap.path}` + : `@${gap.host}`; + process.stderr.write(`${command}: no equivalent action\n`); + } + } + if (catalog.runtimeOnlySchemas.length > 0) { + process.stdout.write( + `Runtime-only schemas omitted: ${catalog.runtimeOnlySchemas.join(", ")}\n`, + ); + } + if (issues.length > 0 || (missing.length > 0 && !allowMissing)) { + process.exitCode = 1; + } +} + async function main(): Promise { const { values } = parseArgs({ options: { @@ -63,51 +107,7 @@ async function main(): Promise { const catalog = await collectCatalog({ strict: values.check }); if (values.check) { - const issues = catalog.commandActionLinkIssues; - const missing = catalog.missingCommandActions; - process.stdout.write( - `Command action coverage: ${catalog.counts.linkedCommandEndpoints} / ` + - `${catalog.counts.commandEndpoints} endpoints ` + - `(${missing.length} missing, ${issues.length} invalid)\n`, - ); - if (issues.length > 0) { - for (const issue of issues) { - const command = - issue.host === "system" - ? `@${issue.path}` - : issue.path.length > 0 - ? `@${issue.host} ${issue.path}` - : `@${issue.host}`; - const action = issue.schema - ? `${issue.schema}.${issue.actionName}` - : issue.actionName; - process.stderr.write( - `${command} -> ${action}: ${issue.message}\n`, - ); - } - } - if (!values["allow-missing"]) { - for (const gap of missing) { - const command = - gap.host === "system" - ? `@${gap.path}` - : gap.path.length > 0 - ? `@${gap.host} ${gap.path}` - : `@${gap.host}`; - process.stderr.write(`${command}: no equivalent action\n`); - } - } - if (catalog.runtimeOnlySchemas.length > 0) { - process.stdout.write( - `Runtime-only schemas omitted: ${catalog.runtimeOnlySchemas.join(", ")}\n`, - ); - } - if ( - issues.length > 0 || - (missing.length > 0 && !values["allow-missing"]) - ) { - process.exitCode = 1; - } + await runCheckMode(catalog, values["allow-missing"] ?? false); return; } From 507e6a353003142c67e37463175ec2f2816b8fbc Mon Sep 17 00:00:00 2001 From: typeagent-bot Date: Mon, 3 Aug 2026 18:06:53 +0000 Subject: [PATCH 12/22] style: apply prettier formatting and policy fixes --- .../system/action/collisionActionHandler.ts | 19 +++++++++++++++---- .../system/action/configActionHandler.ts | 3 +-- .../action/constructionActionHandler.ts | 4 +++- .../system/action/feedbackActionHandler.ts | 4 +--- .../system/action/grammarActionHandler.ts | 6 +++++- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts index 70e8d72655..3795f102c5 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts @@ -206,7 +206,8 @@ function executeCollisionKeywordsAction( switch (actionName) { case "manageCollisionKeywords": { const operation = - p.operation ?? (p.target === undefined ? "listOverrides" : "show"); + p.operation ?? + (p.target === undefined ? "listOverrides" : "show"); if (operation === "listOverrides") { return execute(["keywords"], { args: {}, flags: {} }); } @@ -293,7 +294,9 @@ function executeCollisionOptimizeCoreAction( flags: { ...opt(p.patternsFile, "patterns-file"), "min-attempts": p.minAttempts ?? 5, - "surface-disagreement": String(p.surfaceDisagreement ?? 0.5), + "surface-disagreement": String( + p.surfaceDisagreement ?? 0.5, + ), ...opt(p.outputPath, "out"), ...opt(p.outputHtmlPath, "out-html"), ...opt(p.workdir, "workdir"), @@ -399,10 +402,18 @@ export function executeCollisionAction( return executeCollisionKeywordsAction(action.actionName, p, execute); } if (OPTIMIZE_CORE_ACTIONS.has(action.actionName)) { - return executeCollisionOptimizeCoreAction(action.actionName, p, execute); + return executeCollisionOptimizeCoreAction( + action.actionName, + p, + execute, + ); } if (OPTIMIZE_PIPELINE_ACTIONS.has(action.actionName)) { - return executeCollisionOptimizePipelineAction(action.actionName, p, execute); + return executeCollisionOptimizePipelineAction( + action.actionName, + p, + execute, + ); } if (PREFERENCES_ACTIONS.has(action.actionName)) { return executeCollisionPreferencesAction(action.actionName, p, execute); diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts index 9f01da7108..970d6ed726 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts @@ -194,8 +194,7 @@ function getConfigCommandParams( return { args: handler.parameters.args === undefined ? undefined : parsedArgs, - flags: - handler.parameters.flags === undefined ? undefined : parsedFlags, + flags: handler.parameters.flags === undefined ? undefined : parsedFlags, } as ParsedCommandParams; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts index 7c34b8bd97..25aa56d6a7 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts @@ -94,6 +94,8 @@ export function executeConstructionAction( case "setEntityWildcardMatching": return toggle(["wildcard", "entity"], p.enabled); default: - throw new Error(`Unknown construction action: ${action.actionName}`); + throw new Error( + `Unknown construction action: ${action.actionName}`, + ); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts index 8852ff15a0..aca8447479 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts @@ -64,8 +64,6 @@ export function executeFeedbackAction( case "countFeedback": return execute(["count"], undefined); default: - throw new Error( - `Unknown feedback action: ${action.actionName}`, - ); + throw new Error(`Unknown feedback action: ${action.actionName}`); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts index d8710b548b..a744f5fb38 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts @@ -48,7 +48,11 @@ export async function executeGrammarAction( if (systemHandlers === undefined) { throw new Error("System command handlers are unavailable."); } - return executeScanGrammarCollisionsAction(action, context, systemHandlers); + return executeScanGrammarCollisionsAction( + action, + context, + systemHandlers, + ); } const chc = context.sessionContext.agentContext; From dae9051ae373313a8f9a15d8ca5df25b2f12e88b Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 18:18:05 -0700 Subject: [PATCH 13/22] Fix pnpm-lock.yaml merge resolution The merge text-merged pnpm-lock.yaml, keeping the PR branch's stale importer entries alongside main's updated package.json files. That left the lockfile out of sync (e.g. esbuild specifier ^0.28.1 vs ^0.28.2 in package.json), which breaks 'pnpm install --frozen-lockfile' in CI. Take main's lockfile as the base and re-add only this PR's dependency additions. Verified with 'pnpm install --frozen-lockfile'. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- ts/pnpm-lock.yaml | 2497 ++++++++++++++++++++++++++++++--------------- 1 file changed, 1662 insertions(+), 835 deletions(-) diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index a74af8123b..3ce9be8b9b 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -90,8 +90,8 @@ importers: specifier: workspace:* version: link:../../../packages/agentSdk better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 devDependencies: '@types/better-sqlite3': specifier: 7.6.13 @@ -177,7 +177,7 @@ importers: version: 8.18.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -186,7 +186,7 @@ importers: version: 6.0.1 ts-loader: specifier: ^9.5.1 - version: 9.5.2(typescript@5.4.5)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.24)) + version: 9.5.2(typescript@5.4.5)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.26)) typescript: specifier: ~5.4.5 version: 5.4.5 @@ -230,8 +230,8 @@ importers: specifier: workspace:* version: link:../../packages/utils/typechatUtils better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 chalk: specifier: ^5.4.1 version: 5.6.2 @@ -546,8 +546,8 @@ importers: specifier: workspace:* version: link:../../packages/knowledgeProcessor better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 debug: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) @@ -572,7 +572,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -813,7 +813,7 @@ importers: version: 12.0.2(webpack@5.105.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -828,7 +828,7 @@ importers: version: 5.4.5 webpack: specifier: ^5.104.1 - version: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + version: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) @@ -883,7 +883,7 @@ importers: dependencies: '@azure/ai-projects': specifier: ^2.2.0 - version: 2.2.0(ws@8.21.1)(zod@3.25.76) + version: 2.2.0(ws@8.21.3)(zod@3.25.76) '@azure/identity': specifier: ^4.10.0 version: 4.10.0 @@ -957,7 +957,7 @@ importers: version: 12.0.2(webpack@5.105.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -972,7 +972,7 @@ importers: version: 5.4.5 webpack: specifier: ^5.104.1 - version: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + version: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) @@ -1006,7 +1006,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1040,7 +1040,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1096,7 +1096,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1133,7 +1133,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1222,7 +1222,7 @@ importers: version: 7.0.15 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1255,8 +1255,8 @@ importers: specifier: ^2.4.1 version: 2.5.2 esbuild: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^0.28.2 + version: 0.28.2 glob: specifier: ^11.0.0 version: 11.1.0 @@ -1320,13 +1320,13 @@ importers: version: 5.4.5 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@26.1.2)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0) + version: 6.4.3(@types/node@26.2.0)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0) packages/actionGrammar: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) '@typeagent/action-schema': specifier: workspace:* version: link:../actionSchema @@ -1363,7 +1363,7 @@ importers: version: 5.6.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1413,7 +1413,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1451,23 +1451,41 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 packages/agentRpc: dependencies: + '@opentelemetry/api': + specifier: 1.9.0 + version: 1.9.0 '@typeagent/agent-sdk': specifier: workspace:* version: link:../agentSdk '@typeagent/common-utils': specifier: workspace:* version: link:../utils/commonUtils + '@typeagent/telemetry': + specifier: workspace:* + version: link:../telemetry debug: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) devDependencies: + '@opentelemetry/context-async-hooks': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) '@types/debug': specifier: ^4.1.12 version: 4.1.12 @@ -1476,7 +1494,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1507,7 +1525,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1561,7 +1579,7 @@ importers: version: 1.43.1(supports-color@8.1.1) openai: specifier: ^4.73.0 - version: 4.103.0(encoding@0.1.13)(ws@8.21.1)(zod@4.3.6) + version: 4.103.0(encoding@0.1.13)(ws@8.21.3)(zod@4.3.6) zod: specifier: ^4.1.13 version: 4.3.6 @@ -1594,8 +1612,8 @@ importers: specifier: 2026.1.14 version: 2026.1.14(zod@4.4.3) better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 graphology: specifier: ^0.25.4 version: 0.25.4(graphology-types@0.24.8) @@ -1655,7 +1673,7 @@ importers: version: 4.4.3(supports-color@8.1.1) isomorphic-ws: specifier: ^5.0.0 - version: 5.0.0(ws@8.21.1) + version: 5.0.0(ws@8.21.3) devDependencies: '@jest/globals': specifier: ^29.7.0 @@ -1674,7 +1692,7 @@ importers: version: 8.18.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1685,8 +1703,8 @@ importers: specifier: ~5.4.5 version: 5.4.5 ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 packages/agentServer/protocol: dependencies: @@ -1696,6 +1714,9 @@ importers: '@typeagent/agent-sdk': specifier: workspace:* version: link:../../agentSdk + '@typeagent/copilot-macros': + specifier: workspace:* + version: link:../../copilot-macros '@typeagent/dispatcher-rpc': specifier: workspace:* version: link:../../dispatcher/rpc @@ -1745,12 +1766,18 @@ importers: '@typeagent/conversation-memory': specifier: workspace:* version: link:../../memory/conversation + '@typeagent/copilot-macros': + specifier: workspace:* + version: link:../../copilot-macros '@typeagent/dispatcher-rpc': specifier: workspace:* version: link:../../dispatcher/rpc '@typeagent/dispatcher-types': specifier: workspace:* version: link:../../dispatcher/types + '@typeagent/telemetry': + specifier: workspace:* + version: link:../../telemetry '@typeagent/typechat-utils': specifier: workspace:* version: link:../../utils/typechatUtils @@ -1761,8 +1788,8 @@ importers: specifier: workspace:* version: link:../../dispatcher/dispatcher better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 debug: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) @@ -1776,8 +1803,8 @@ importers: specifier: ^16.3.1 version: 16.5.0 ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@jest/globals': specifier: ^29.7.0 @@ -1796,7 +1823,7 @@ importers: version: 8.18.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1836,6 +1863,9 @@ importers: '@typeagent/common-utils': specifier: workspace:* version: link:../../../utils/commonUtils + '@typeagent/config': + specifier: workspace:* + version: link:../../../config chalk: specifier: ^5.4.1 version: 5.6.2 @@ -1884,23 +1914,7 @@ importers: version: 2.4.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) - prettier: - specifier: ^3.5.3 - version: 3.5.3 - rimraf: - specifier: ^6.0.1 - version: 6.0.1 - typescript: - specifier: ~5.4.5 - version: 5.4.5 - - packages/agents/androidMobile: - dependencies: - '@typeagent/agent-sdk': - specifier: workspace:* - version: link:../../agentSdk - devDependencies: + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1998,8 +2012,8 @@ importers: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 express: specifier: ^4.22.0 version: 4.22.1 @@ -2061,8 +2075,8 @@ importers: specifier: ~5.4.5 version: 5.4.5 ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 xss: specifier: ^1.0.15 version: 1.0.15 @@ -2082,6 +2096,9 @@ importers: '@typeagent/action-schema-compiler': specifier: workspace:* version: link:../../actionSchemaCompiler + '@typeagent/browser-extension': + specifier: workspace:* + version: link:../browserExtension '@types/debug': specifier: ^4.1.12 version: 4.1.12 @@ -2123,7 +2140,7 @@ importers: version: 29.3.3(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest@29.7.0(@types/node@22.15.18)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)))(typescript@5.4.5) vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@22.15.18)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.8.3) + version: 6.4.3(@types/node@22.15.18)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.8.3) packages/agents/browserControlRpc: dependencies: @@ -2131,8 +2148,8 @@ importers: specifier: workspace:* version: link:../../agentRpc dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 devDependencies: prettier: specifier: ^3.5.3 @@ -2192,8 +2209,8 @@ importers: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 html-to-text: specifier: ^9.0.5 version: 9.0.5 @@ -2287,7 +2304,7 @@ importers: version: 5.4.5 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0) + version: 6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0) packages/agents/calendar: dependencies: @@ -2330,7 +2347,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -2373,7 +2390,7 @@ importers: version: 2.4.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -2399,8 +2416,8 @@ importers: specifier: workspace:* version: link:../../utils/webSocketUtils better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 chalk: specifier: ^5.4.1 version: 5.6.2 @@ -2408,8 +2425,8 @@ importers: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@typeagent/action-grammar-compiler': specifier: workspace:* @@ -2434,7 +2451,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -2484,8 +2501,8 @@ importers: specifier: ^0.1.1 version: 0.1.1(typescript@5.4.5)(zod@3.25.76) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@jest/globals': specifier: ^29.7.0 @@ -2525,7 +2542,7 @@ importers: version: 2.4.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -2544,6 +2561,9 @@ importers: '@typeagent/aiclient': specifier: workspace:* version: link:../../aiclient + '@typeagent/config': + specifier: workspace:* + version: link:../../config devDependencies: '@typeagent/action-grammar-compiler': specifier: workspace:* @@ -2565,7 +2585,7 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) '@typeagent/agent-runtime': specifier: workspace:* version: link:../../typeagent @@ -2630,7 +2650,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -2744,7 +2764,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -2758,6 +2778,9 @@ importers: specifier: workspace:* version: link:../../agentSdk devDependencies: + '@typeagent/action-grammar': + specifier: workspace:* + version: link:../../actionGrammar '@typeagent/action-grammar-compiler': specifier: workspace:* version: link:../../actionGrammarCompiler @@ -2772,7 +2795,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -2825,8 +2848,8 @@ importers: specifier: ^4.3.4 version: 4.4.1(supports-color@8.1.1) dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 express: specifier: ^4.22.0 version: 4.22.1 @@ -2846,8 +2869,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 mermaid: - specifier: ^11.15.0 - version: 11.15.0 + specifier: ^11.16.1 + version: 11.16.1 prosemirror-inputrules: specifier: ^1.2.0 version: 1.5.0 @@ -2867,8 +2890,8 @@ importers: specifier: ^4.1.2 version: 4.1.2 ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 y-prosemirror: specifier: ^1.2.3 version: 1.3.5(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) @@ -2911,7 +2934,7 @@ importers: version: 2.4.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -2926,7 +2949,7 @@ importers: version: 5.4.5 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@26.1.2)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0) + version: 6.4.3(@types/node@26.2.0)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0) packages/agents/montage: dependencies: @@ -3005,7 +3028,7 @@ importers: version: 12.0.2(webpack@5.105.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.5.3 @@ -3020,7 +3043,7 @@ importers: version: 5.4.5 webpack: specifier: ^5.104.1 - version: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + version: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) @@ -3092,8 +3115,8 @@ importers: specifier: ~5.4.5 version: 5.4.5 ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 packages/agents/osNotifications: dependencies: @@ -3124,7 +3147,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3216,7 +3239,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -3277,7 +3300,7 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) '@typeagent/agent-flows': specifier: workspace:* version: link:../../agent-flows @@ -3288,6 +3311,9 @@ importers: specifier: ^4.3.4 version: 4.4.3(supports-color@8.1.1) devDependencies: + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 '@typeagent/action-grammar': specifier: workspace:* version: link:../../actionGrammar @@ -3300,9 +3326,15 @@ importers: '@types/debug': specifier: ^4.1.12 version: 4.1.12 + '@types/jest': + specifier: ^29.5.7 + version: 29.5.14 concurrently: specifier: ^9.1.2 version: 9.1.2 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3345,7 +3377,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3385,7 +3417,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3466,8 +3498,8 @@ importers: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@typeagent/action-schema-compiler': specifier: workspace:* @@ -3504,7 +3536,7 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) '@typeagent/agent-flows': specifier: workspace:* version: link:../../agent-flows @@ -3595,7 +3627,7 @@ importers: version: 12.0.2(webpack@5.105.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3610,7 +3642,7 @@ importers: version: 5.4.5 webpack: specifier: ^5.104.1 - version: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + version: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) @@ -3622,7 +3654,7 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) '@typeagent/agent-sdk': specifier: workspace:* version: link:../../agentSdk @@ -3662,7 +3694,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3741,8 +3773,8 @@ importers: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@typeagent/action-grammar-compiler': specifier: workspace:* @@ -3795,7 +3827,7 @@ importers: version: 5.4.5 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@26.1.2)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0) + version: 6.4.3(@types/node@26.2.0)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0) packages/agents/weather: dependencies: @@ -3817,7 +3849,7 @@ importers: version: 9.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3888,7 +3920,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -3963,8 +3995,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@types/debug': specifier: ^4.1.12 @@ -3980,7 +4012,7 @@ importers: version: 8.18.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3995,7 +4027,7 @@ importers: dependencies: '@azure/ai-projects': specifier: ^2.2.0 - version: 2.2.0(ws@8.21.1)(zod@3.25.76) + version: 2.2.0(ws@8.21.3)(zod@3.25.76) '@azure/identity': specifier: ^4.10.0 version: 4.10.0 @@ -4022,7 +4054,7 @@ importers: version: 4.4.1(supports-color@8.1.1) openai: specifier: ^6.16.0 - version: 6.41.0(ws@8.21.1)(zod@3.25.76) + version: 6.41.0(ws@8.21.3)(zod@3.25.76) typechat: specifier: ^0.1.1 version: 0.1.1(typescript@5.4.5)(zod@3.25.76) @@ -4044,7 +4076,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -4054,19 +4086,49 @@ importers: packages/benchmarks: dependencies: + '@typeagent/action-schema': + specifier: workspace:* + version: link:../actionSchema '@typeagent/agent-sdk': specifier: workspace:* version: link:../agentSdk + '@typeagent/aiclient': + specifier: workspace:* + version: link:../aiclient agent-dispatcher: specifier: workspace:* version: link:../dispatcher/dispatcher + commander: + specifier: ^12.1.0 + version: 12.1.0 default-agent-provider: specifier: workspace:* version: link:../defaultAgentProvider + gpt-tokenizer: + specifier: ^2.9.0 + version: 2.9.0 + js-yaml: + specifier: ^4.3.1 + version: 4.3.1 + zod: + specifier: ^4.1.13 + version: 4.1.13 devDependencies: + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 + '@types/jest': + specifier: ^29.5.7 + version: 29.5.14 + '@types/js-yaml': + specifier: ^4.0.9 + version: 4.0.9 '@types/node': specifier: ^22.0.0 version: 22.20.1 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -4127,7 +4189,7 @@ importers: version: 2.0.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -4167,7 +4229,7 @@ importers: version: 5.6.3(webpack@5.105.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -4182,7 +4244,7 @@ importers: version: 5.4.5 webpack: specifier: ^5.104.1 - version: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + version: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) @@ -4205,8 +4267,8 @@ importers: specifier: ^6.0.2 version: 6.0.5 dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 markdown-it: specifier: ^14.2.0 version: 14.2.0 @@ -4219,7 +4281,7 @@ importers: version: 14.1.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0(supports-color@8.1.1) @@ -4357,8 +4419,8 @@ importers: specifier: ^16.3.1 version: 16.5.0 ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@types/body-parser': specifier: ^1.19.5 @@ -4391,8 +4453,8 @@ importers: specifier: ^3.2.1 version: 3.4.0(supports-color@8.1.1) esbuild: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^0.28.2 + version: 0.28.2 mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -4435,7 +4497,7 @@ importers: dependencies: '@modelcontextprotocol/sdk': specifier: 1.26.0 - version: 1.26.0(zod@4.3.6) + version: 1.26.0(zod@4.4.3) '@typeagent/agent-server-client': specifier: workspace:* version: link:../agentServer/client @@ -4487,7 +4549,7 @@ importers: version: 9.0.5 isomorphic-ws: specifier: ^5.0.0 - version: 5.0.0(ws@8.21.1) + version: 5.0.0(ws@8.21.3) zod: specifier: ^4.1.13 version: 4.1.13 @@ -4503,7 +4565,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.5.3 @@ -4512,7 +4574,7 @@ importers: version: 5.0.10 ts-jest: specifier: ^29.1.2 - version: 29.3.3(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)))(typescript@5.4.5) + version: 29.3.3(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)))(typescript@5.4.5) typescript: specifier: ~5.4.5 version: 5.4.5 @@ -4547,8 +4609,8 @@ importers: specifier: ^16.3.1 version: 16.5.0 js-yaml: - specifier: ^4.3.0 - version: 4.3.0 + specifier: ^4.3.1 + version: 4.3.1 zod: specifier: ^3.23.8 version: 3.25.76 @@ -4564,7 +4626,28 @@ importers: version: 4.0.9 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + typescript: + specifier: ~5.4.5 + version: 5.4.5 + + packages/copilot-macros: + devDependencies: + '@types/jest': + specifier: ^29.5.7 + version: 29.5.14 + '@types/node': + specifier: ^20.10.0 + version: 20.19.40 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)) + prettier: + specifier: ^3.5.3 + version: 3.5.3 rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -4583,6 +4666,9 @@ importers: '@typeagent/agent-server-client': specifier: workspace:* version: link:../agentServer/client + '@typeagent/copilot-macros': + specifier: workspace:* + version: link:../copilot-macros '@typeagent/dispatcher-types': specifier: workspace:* version: link:../dispatcher/types @@ -4593,15 +4679,24 @@ importers: specifier: ^3.25.0 version: 3.25.76 devDependencies: + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 '@types/html-to-text': specifier: ^9.0.4 version: 9.0.4 + '@types/jest': + specifier: ^29.5.7 + version: 29.5.14 '@types/node': specifier: ^20.10.0 version: 20.19.40 esbuild: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^0.28.2 + version: 0.28.2 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)) postject: specifier: 1.0.0-alpha.6 version: 1.0.0-alpha.6 @@ -4614,9 +4709,9 @@ importers: packages/defaultAgentProvider: dependencies: - '@modelcontextprotocol/sdk': - specifier: 1.26.0 - version: 1.26.0(supports-color@8.1.1)(zod@4.1.13) + '@modelcontextprotocol/client': + specifier: ^2.0.0 + version: 2.0.0 '@modelcontextprotocol/server-filesystem': specifier: 2026.1.14 version: 2026.1.14(zod@4.1.13) @@ -4659,6 +4754,9 @@ importers: '@typeagent/config': specifier: workspace:* version: link:../config + '@typeagent/copilot-macros': + specifier: workspace:* + version: link:../copilot-macros '@typeagent/desktop-automation': specifier: workspace:* version: link:../agents/desktop @@ -4786,8 +4884,8 @@ importers: specifier: workspace:* version: link:../../examples/workflow/adapter ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 zod: specifier: ^4.1.13 version: 4.1.13 @@ -4815,7 +4913,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -4849,6 +4947,9 @@ importers: '@modelcontextprotocol/sdk': specifier: 1.26.0 version: 1.26.0(supports-color@8.1.1)(zod@4.1.13) + '@opentelemetry/api': + specifier: 1.9.0 + version: 1.9.0 '@typeagent/action-grammar': specifier: workspace:* version: link:../../actionGrammar @@ -4972,7 +5073,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -4997,6 +5098,9 @@ importers: '@typeagent/common-utils': specifier: workspace:* version: link:../../utils/commonUtils + '@typeagent/telemetry': + specifier: workspace:* + version: link:../../telemetry agent-dispatcher: specifier: workspace:* version: link:../dispatcher @@ -5004,6 +5108,12 @@ importers: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) devDependencies: + '@opentelemetry/api': + specifier: 1.9.0 + version: 1.9.0 + '@typeagent/dispatcher-rpc': + specifier: workspace:* + version: link:../rpc '@typeagent/dispatcher-types': specifier: workspace:* version: link:../types @@ -5015,7 +5125,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -5109,7 +5219,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^5.0.5 version: 5.0.10 @@ -5143,7 +5253,7 @@ importers: version: 0.11.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^5.0.5 version: 5.0.10 @@ -5152,7 +5262,7 @@ importers: version: 5.4.5 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@26.1.2)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0) + version: 6.4.3(@types/node@26.2.0)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0) packages/interactiveApp: dependencies: @@ -5211,7 +5321,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -5309,7 +5419,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -5349,7 +5459,7 @@ importers: version: 12.0.2(webpack@5.105.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -5364,7 +5474,7 @@ importers: version: 5.4.5 webpack: specifier: ^5.104.1 - version: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + version: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) @@ -5376,7 +5486,7 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) '@typeagent/aiclient': specifier: workspace:* version: link:../aiclient @@ -5384,8 +5494,8 @@ importers: specifier: workspace:* version: link:../utils/commonUtils better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 debug: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) @@ -5413,10 +5523,10 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.3.6))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) '@anthropic-ai/sdk': specifier: ^0.93.0 - version: 0.93.0(zod@4.3.6) + version: 0.93.0(zod@4.4.3) '@typeagent/aiclient': specifier: workspace:* version: link:../../aiclient @@ -5499,7 +5609,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -5540,8 +5650,8 @@ importers: specifier: workspace:* version: link:../../utils/typechatUtils better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 debug: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) @@ -5569,7 +5679,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -5598,8 +5708,8 @@ importers: specifier: workspace:* version: link:../../knowPro better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 debug: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) @@ -5621,7 +5731,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.5.3 @@ -5662,8 +5772,8 @@ importers: specifier: workspace:* version: link:../../telemetry better-sqlite3: - specifier: 12.6.2 - version: 12.6.2 + specifier: 12.8.0 + version: 12.8.0 cheerio: specifier: ^1.0.0 version: 1.1.0 @@ -5671,8 +5781,8 @@ importers: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 get-folder-size: specifier: ^5.0.0 version: 5.0.0 @@ -5715,7 +5825,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -5789,7 +5899,7 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ^0.3.150 - version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6) + version: 0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3) devDependencies: '@types/node': specifier: ^22.0.0 @@ -5811,7 +5921,7 @@ importers: version: 1.5.13 '@electron-toolkit/preload': specifier: ^3.0.2 - version: 3.0.2(electron@40.8.5(supports-color@8.1.1)) + version: 3.0.2(electron@41.10.3(supports-color@8.1.1)) '@typeagent/agent-rpc': specifier: workspace:* version: link:../agentRpc @@ -5851,6 +5961,9 @@ importers: '@typeagent/dispatcher-types': specifier: workspace:* version: link:../dispatcher/types + '@typeagent/telemetry': + specifier: workspace:* + version: link:../telemetry '@typeagent/typechat-utils': specifier: workspace:* version: link:../utils/typechatUtils @@ -5870,8 +5983,8 @@ importers: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 dotenv: specifier: ^16.3.1 version: 16.5.0 @@ -5882,8 +5995,8 @@ importers: specifier: ^5.9.6 version: 5.10.0 js-yaml: - specifier: ^4.3.0 - version: 4.3.0 + specifier: ^4.3.1 + version: 4.3.1 markdown-it: specifier: ^14.2.0 version: 14.2.0 @@ -5894,8 +6007,8 @@ importers: specifier: ^0.1.1 version: 0.1.1(typescript@5.4.5)(zod@3.25.76) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@electron-toolkit/tsconfig': specifier: ^1.0.1 @@ -5940,8 +6053,8 @@ importers: specifier: workspace:* version: link:../dispatcher/nodeProviders electron: - specifier: 40.8.5 - version: 40.8.5(supports-color@8.1.1) + specifier: 41.10.3 + version: 41.10.3(supports-color@8.1.1) electron-builder: specifier: 26.8.1 version: 26.8.1(electron-builder-squirrel-windows@26.8.1) @@ -5950,7 +6063,7 @@ importers: version: 26.8.1(dmg-builder@26.8.1)(supports-color@8.1.1) electron-vite: specifier: ^4.0.1 - version: 4.0.1(vite@6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) + version: 4.0.1(vite@6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0)) jest: specifier: ^29.7.0 version: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) @@ -5971,7 +6084,7 @@ importers: version: 5.4.5 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0) + version: 6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0) packages/studio-service: dependencies: @@ -5991,8 +6104,8 @@ importers: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@types/debug': specifier: ^4.1.12 @@ -6021,9 +6134,51 @@ importers: packages/telemetry: dependencies: + '@opentelemetry/api': + specifier: 1.9.0 + version: 1.9.0 + '@opentelemetry/api-logs': + specifier: 0.221.0 + version: 0.221.0 + '@opentelemetry/context-async-hooks': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-proto': + specifier: 0.221.0 + version: 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-proto': + specifier: 0.221.0 + version: 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-proto': + specifier: 0.221.0 + version: 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': + specifier: 0.221.0 + version: 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': + specifier: 2.10.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': + specifier: 1.43.0 + version: 1.43.0 '@typeagent/common-utils': specifier: workspace:* version: link:../utils/commonUtils + '@typeagent/config': + specifier: workspace:* + version: link:../config chalk: specifier: ^5.4.1 version: 5.6.2 @@ -6051,7 +6206,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6085,7 +6240,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6156,7 +6311,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6220,7 +6375,7 @@ importers: version: link:../grammarTools/core jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6252,8 +6407,8 @@ importers: specifier: workspace:* version: link:../defaultAgentProvider ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@types/debug': specifier: ^4.1.0 @@ -6271,8 +6426,8 @@ importers: specifier: ^3.2.1 version: 3.4.0(supports-color@8.1.1) esbuild: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^0.28.2 + version: 0.28.2 mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -6299,11 +6454,11 @@ importers: specifier: ^29.5.7 version: 29.5.14 esbuild: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^0.28.2 + version: 0.28.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6331,7 +6486,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6380,7 +6535,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6406,8 +6561,8 @@ importers: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@jest/globals': specifier: ^29.7.0 @@ -6423,7 +6578,7 @@ importers: version: 8.18.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -6453,10 +6608,10 @@ importers: version: 1.0.0 isomorphic-ws: specifier: ^5.0.0 - version: 5.0.0(ws@8.21.1) + version: 5.0.0(ws@8.21.3) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@types/debug': specifier: ^4.1.12 @@ -6511,8 +6666,8 @@ importers: specifier: ^9.1.2 version: 9.1.2 esbuild: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^0.28.2 + version: 0.28.2 mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -6565,11 +6720,11 @@ importers: specifier: ^4.4.0 version: 4.4.3(supports-color@8.1.1) dompurify: - specifier: ^3.4.12 - version: 3.4.12 + specifier: ^3.4.13 + version: 3.4.13 isomorphic-ws: specifier: ^5.0.0 - version: 5.0.0(ws@8.21.1) + version: 5.0.0(ws@8.21.3) markdown-it: specifier: ^14.2.0 version: 14.2.0 @@ -6577,8 +6732,8 @@ importers: specifier: 1.43.1 version: 1.43.1(supports-color@8.1.1) ws: - specifier: ^8.21.1 - version: 8.21.1 + specifier: ^8.21.3 + version: 8.21.3 devDependencies: '@types/debug': specifier: ^4.1.0 @@ -6605,8 +6760,8 @@ importers: specifier: ^2.4.1 version: 2.4.1 esbuild: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^0.28.2 + version: 0.28.2 mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -6644,8 +6799,8 @@ importers: specifier: ^4.4.0 version: 4.4.1(supports-color@8.1.1) js-yaml: - specifier: ^4.3.0 - version: 4.3.0 + specifier: ^4.3.1 + version: 4.3.1 lodash-es: specifier: ^4.18.1 version: 4.18.1 @@ -6695,7 +6850,7 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + version: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -7195,8 +7350,8 @@ packages: resolution: {integrity: sha512-EotmBz42apYGjqiIV9rDUdptaMptpTn4TdGf3JfjLvFvinSe9BJ6ywU92K9ky+t/b0ghbeTSe9RfqlgLh8f2jA==} engines: {node: '>=0.8.0'} - '@azure/msal-common@16.11.2': - resolution: {integrity: sha512-yDhtBOGDCdK9ipQ9g3+wmlMEPnZx2pXaDicDd9jYyR1L+7lEbvEohTDmF5qejZDutZY3m9pWPxeYxzNC701A2w==} + '@azure/msal-common@16.12.0': + resolution: {integrity: sha512-hgLgfRdbG2AmhXPygebf1KYJEvse86+ZZLWufdiTKaGRYEUqOzHdlf6AS1IiuUCHWbynkgbHc451jSNkbfhWlg==} engines: {node: '>=0.8.0'} '@azure/msal-common@16.6.0': @@ -7215,16 +7370,13 @@ packages: resolution: {integrity: sha512-bJcqe86u6gdqU7L5wAG3OpmkROGnTwm9bSgTIvyJj3eNDwQO1QsRhSQ4s5HlP65I3n/hy1bUwBgNDgIJ5bSG2Q==} engines: {node: '>=16'} - '@azure/msal-node-extensions@5.3.3': - resolution: {integrity: sha512-WNF0XJyZLWOhRo4Pta2ubWn6gWE7gEEMYD7olQepiisAn+txb4/QRxXikNmd4oeYfk5wQ67QFSK/OQ8m6hYlXA==} + '@azure/msal-node-extensions@5.3.5': + resolution: {integrity: sha512-NzTHKi5AWYeut4Wh6k5eSoTczwnRita0P0bgMqBdvZsNa8AKhGCPVK+UWBVD72vjIxdSk81FBH7sTAvKVuEjSw==} engines: {node: '>=20'} '@azure/msal-node-runtime@0.18.2': resolution: {integrity: sha512-v45fyBQp80BrjZAeGJXl+qggHcbylQiFBihr0ijO2eniDCW9tz5TZBKYsqzH06VuiRaVG/Sa0Hcn4pjhJqFSTw==} - '@azure/msal-node-runtime@0.20.5': - resolution: {integrity: sha512-DqY28Lpx67AsMbT3FYal3MnDZx62Pblnhp1qA+HGtgEsm3jK8COkJVCrhVsprn80PKQfAOdKRuxgVYyvmv2rOg==} - '@azure/msal-node-runtime@0.20.6': resolution: {integrity: sha512-89Al7l5c8sOEA954d35WZOg1sCa2WKfgf7KyTbN9vIkKsoZrXdJ5+CPjy8+tQqWcsJTAMbQD4OWr7V09/xN8KA==} @@ -7260,8 +7412,8 @@ packages: resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.7': - resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.29.7': @@ -7306,8 +7458,8 @@ packages: resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.7': - resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} engines: {node: '>=6.0.0'} hasBin: true @@ -7420,12 +7572,12 @@ packages: resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.7': - resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': @@ -7562,8 +7714,8 @@ packages: '@codemirror/view@6.37.2': resolution: {integrity: sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==} - '@codemirror/view@6.43.7': - resolution: {integrity: sha512-FZsExxkoxnAN+d9TgqXLg5g4A1oQwzX9WlkOT5i2PKkcW7xx3Bmu0vs90g6fo9Mpdsb/l96dnAraQ8932aO4/g==} + '@codemirror/view@6.43.8': + resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -7633,6 +7785,10 @@ packages: resolution: {integrity: sha512-hIMJbt1guqr3/N2zCN45k9hw9o78qcdsO0xietLe+Bfa+JL0YafHTgkWkM1oT3Ht5sGMJaDcJZiYomSMU6CtTA==} engines: {node: '>=20'} + '@electron-internal/extract-zip@1.0.5': + resolution: {integrity: sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA==} + engines: {node: '>=22.12.0'} + '@electron-toolkit/preload@3.0.2': resolution: {integrity: sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==} peerDependencies: @@ -7652,14 +7808,14 @@ packages: resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} hasBin: true - '@electron/get@2.0.3': - resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} - engines: {node: '>=12'} - '@electron/get@3.1.0': resolution: {integrity: sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==} engines: {node: '>=14'} + '@electron/get@5.1.0': + resolution: {integrity: sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==} + engines: {node: '>=22.12.0'} + '@electron/notarize@2.5.0': resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} engines: {node: '>= 10.0.0'} @@ -7721,6 +7877,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} @@ -7739,6 +7901,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} @@ -7757,6 +7925,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} @@ -7775,6 +7949,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} @@ -7793,6 +7973,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} @@ -7811,6 +7997,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} @@ -7829,6 +8021,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} @@ -7847,6 +8045,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} @@ -7865,6 +8069,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} @@ -7883,6 +8093,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} @@ -7901,6 +8117,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} @@ -7919,6 +8141,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} @@ -7937,6 +8165,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} @@ -7955,6 +8189,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} @@ -7973,6 +8213,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} @@ -7991,6 +8237,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} @@ -8009,6 +8261,12 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} @@ -8027,6 +8285,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} @@ -8045,6 +8309,12 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} @@ -8063,6 +8333,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} @@ -8081,6 +8357,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} @@ -8099,6 +8381,12 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} @@ -8117,6 +8405,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} @@ -8135,6 +8429,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} @@ -8153,6 +8453,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} @@ -8171,6 +8477,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.10.1': resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -9087,8 +9399,8 @@ packages: '@marijn/find-cluster-break@1.0.3': resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==} - '@mermaid-js/parser@1.1.1': - resolution: {integrity: sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==} + '@mermaid-js/parser@1.2.0': + resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} '@microsoft/microsoft-graph-client@3.0.7': resolution: {integrity: sha512-/AazAV/F+HK4LIywF9C+NYHcJo038zEnWkteilcxC1FM/uK/4NVGDKGrxx7nNq1ybspAroRKT4I1FHfxQzxkUw==} @@ -9188,6 +9500,14 @@ packages: '@milkdown/utils@7.13.1': resolution: {integrity: sha512-4ct/ovL0h/0kuLFligLdZgt3qtWbNZEHnIKO321qvkaGLx1HmzbMpiL6V8tq7iDqNKeoqAzFb/2vnUeYGv1Ndw==} + '@modelcontextprotocol/client@2.0.0': + resolution: {integrity: sha512-8f1OghQ2rjzIOfqgUCP+8GiUWqRs89njoWLNqAe8kWmDePv3s1fZXseej+QXemssEuuOvLLmLO/kqM3IQHtISw==} + engines: {node: '>=20'} + + '@modelcontextprotocol/core@2.0.0': + resolution: {integrity: sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==} + engines: {node: '>=20'} + '@modelcontextprotocol/sdk@1.26.0': resolution: {integrity: sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==} engines: {node: '>=18'} @@ -9278,6 +9598,13 @@ packages: resolution: {integrity: sha512-ypTJ/DXzsJbTU3o7qXFlWmZGgEbh42JWQl7v5/i+DJz/HURELcSnq9ler9e1ukqma70JzmCQcIseiE/Xs6sczw==} engines: {node: '>= 10'} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + '@napi-rs/wasm-runtime@1.1.6': resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} peerDependencies: @@ -9307,8 +9634,8 @@ packages: resolution: {integrity: sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow==} engines: {node: '>=0.3.0'} - '@oclif/core@4.13.2': - resolution: {integrity: sha512-YWQs0JvESCliWopKtCZqPLgEB1e3oqR+KYecMReseYWbo7E73Rz2tFwQDFQtAp48VLMiAsiTPKKQaZAo+ghzLw==} + '@oclif/core@4.13.3': + resolution: {integrity: sha512-wBp2igI2KVwq2ZmpnfmGtOROo7aXZIr3OEtAS16g1wHFBqyEuswL+9K50NJWJvlpAmxd+4dVj/ycawXESU3wQQ==} engines: {node: '>=18.0.0'} '@oclif/core@4.5.2': @@ -9331,8 +9658,8 @@ packages: resolution: {integrity: sha512-5KdldxEizbV3RsHOddN4oMxrX/HL6z79S94tbxEHVZ/dJKDWzfyCpgC9axNYqwmBF2pFZkozl/l7t3hCGOdalw==} engines: {node: '>=18.0.0'} - '@oclif/plugin-help@6.2.55': - resolution: {integrity: sha512-IamFqLPoD8KTZbGSAu24EFe2kNibMrL/WA8+4EvnbdkYqZGUcizVqeXUIxzns3SES99wgqOtsK3DtLB3V3kIJQ==} + '@oclif/plugin-help@6.2.58': + resolution: {integrity: sha512-DAYMXZrTWRMLTbpX+rT+ibAmKrZ6IVNGn+fgAGjMoeNlqlSY94eJHocgmqChMwsdWp3H3x+jFmPJiYQt/ifr3Q==} engines: {node: '>=18.0.0'} '@oclif/plugin-not-found@3.2.65': @@ -9374,18 +9701,104 @@ packages: '@open-wc/testing@4.0.0': resolution: {integrity: sha512-KI70O0CJEpBWs3jrTju4BFCy7V/d4tFfYWkg8pMzncsDhD7TYNHLw5cy+s1FHXIgVFetnMDhPpwlKIPvtTQW7w==} + '@opentelemetry/api-logs@0.221.0': + resolution: {integrity: sha512-OlanaW1vv7ufTqQ3/fPLI4arGt5ZoM+P8abOMki6uEYnpRazepSWDwDnnw+la7kE26SHVC18//SMccrDvLKOXQ==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@opentelemetry/core@2.8.0': - resolution: {integrity: sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==} + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/context-async-hooks@2.10.0': + resolution: {integrity: sha512-bvyMcgLEkozzSzpEEEo1OMoeQ97bxj6Qs2uN3mPrSdDvObMI1myffD/BPqcLlzZO9//d1SqQA/WPw7Cz2AiqhA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/semantic-conventions@1.34.0': - resolution: {integrity: sha512-aKcOkyrorBGlajjRdVoJWHTxfxO1vCNHLJVlSDaRHDIdjU+pX8IYQPvPDkYiujKLbRnWU+1TBwEt0QRgSm4SGA==} + '@opentelemetry/core@2.10.0': + resolution: {integrity: sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-logs-otlp-proto@0.221.0': + resolution: {integrity: sha512-AH6EY+47gXFaWYgG3hfeOneGiE9xIZGtDBk+9g0sM8NZWzsQhhmqPbQQXJzS7pyCh5jRRr2nYNXVrkCmoojRvQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-http@0.221.0': + resolution: {integrity: sha512-sRfCKbOzgy8xZQV2as0RzIZlnCmCseCKZGLfRcrpo2CBngJDr+rPtX0zkG0+oUCV5kfQPUoW3W3C96Ag3Y/Clg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-proto@0.221.0': + resolution: {integrity: sha512-YMF4LveY2I3yhw61rn6nmC9FE8U24IZHPeKU1Duc5+sbwjMd8FwZAwba318ImdThCg/HuVQvhm2y6bfgNPnfYg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-proto@0.221.0': + resolution: {integrity: sha512-Z9i2T7vgZbWe9rSLYxXVIbeW+XyzUq4rZanW3ZyVNwVDqCsh0EJKUgBWWQ0CZfeuUA+RQPzKgJQHMuWAUnKqXw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-exporter-base@0.221.0': + resolution: {integrity: sha512-UFPIq80OH3Ns/oPFHRj14d4DTOxUo+MUFU8hUiCq5jTqFhdeJnfVSANHT+xp92409cA+oxzvlZCe6NM1wvCuBA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.221.0': + resolution: {integrity: sha512-lg6lkOU08Az23jVcn/0Els9HP+V8PnR4Km6p0KgpTggS0n/WuhnmY64rSh83Of9iR9nD+dpWr6adlcX8KzAwjg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/resources@2.10.0': + resolution: {integrity: sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.221.0': + resolution: {integrity: sha512-FaDcazjyMp7TZZZAsqbo4IkovP0UegoCu0EBkiNt+qCqvUf7FPAsfcrZ3+ZEkKgXZ/jHafop+JoGPDk3A0SmLg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@2.10.0': + resolution: {integrity: sha512-t6r1VSvXNtSDnPXU1FbZeetJb7yyovHmgu0wRSoftxtE0g2rSNhQZQUy69sRUCL+iioJpX8SN/S6wq6ZtvLySQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.10.0': + resolution: {integrity: sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-node@2.10.0': + resolution: {integrity: sha512-GZK/G6oZyBLGlH1pUgeDch7D91KoHd2uotUGIkWCPi9GI5T9X0p4L7nNAMDR1BQjkRYoDqo+ddfVx9t5Uhys+Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-trace@2.10.0': + resolution: {integrity: sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} '@oxc-parser/binding-android-arm-eabi@0.137.0': @@ -9748,8 +10161,8 @@ packages: cpu: [arm] os: [android] - '@rollup/rollup-android-arm-eabi@4.62.3': - resolution: {integrity: sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==} + '@rollup/rollup-android-arm-eabi@4.62.4': + resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==} cpu: [arm] os: [android] @@ -9758,8 +10171,8 @@ packages: cpu: [arm64] os: [android] - '@rollup/rollup-android-arm64@4.62.3': - resolution: {integrity: sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==} + '@rollup/rollup-android-arm64@4.62.4': + resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==} cpu: [arm64] os: [android] @@ -9768,8 +10181,8 @@ packages: cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-arm64@4.62.3': - resolution: {integrity: sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==} + '@rollup/rollup-darwin-arm64@4.62.4': + resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==} cpu: [arm64] os: [darwin] @@ -9778,8 +10191,8 @@ packages: cpu: [x64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.3': - resolution: {integrity: sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==} + '@rollup/rollup-darwin-x64@4.62.4': + resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==} cpu: [x64] os: [darwin] @@ -9788,8 +10201,8 @@ packages: cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-arm64@4.62.3': - resolution: {integrity: sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==} + '@rollup/rollup-freebsd-arm64@4.62.4': + resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==} cpu: [arm64] os: [freebsd] @@ -9798,8 +10211,8 @@ packages: cpu: [x64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.62.3': - resolution: {integrity: sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==} + '@rollup/rollup-freebsd-x64@4.62.4': + resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==} cpu: [x64] os: [freebsd] @@ -9809,8 +10222,8 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-gnueabihf@4.62.3': - resolution: {integrity: sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==} + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} cpu: [arm] os: [linux] libc: [glibc] @@ -9821,8 +10234,8 @@ packages: os: [linux] libc: [musl] - '@rollup/rollup-linux-arm-musleabihf@4.62.3': - resolution: {integrity: sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==} + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} cpu: [arm] os: [linux] libc: [musl] @@ -9833,8 +10246,8 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-gnu@4.62.3': - resolution: {integrity: sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==} + '@rollup/rollup-linux-arm64-gnu@4.62.4': + resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} cpu: [arm64] os: [linux] libc: [glibc] @@ -9845,8 +10258,8 @@ packages: os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-musl@4.62.3': - resolution: {integrity: sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==} + '@rollup/rollup-linux-arm64-musl@4.62.4': + resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} cpu: [arm64] os: [linux] libc: [musl] @@ -9857,8 +10270,8 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-gnu@4.62.3': - resolution: {integrity: sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==} + '@rollup/rollup-linux-loong64-gnu@4.62.4': + resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} cpu: [loong64] os: [linux] libc: [glibc] @@ -9869,8 +10282,8 @@ packages: os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-musl@4.62.3': - resolution: {integrity: sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==} + '@rollup/rollup-linux-loong64-musl@4.62.4': + resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} cpu: [loong64] os: [linux] libc: [musl] @@ -9881,8 +10294,8 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-gnu@4.62.3': - resolution: {integrity: sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==} + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} cpu: [ppc64] os: [linux] libc: [glibc] @@ -9893,8 +10306,8 @@ packages: os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-musl@4.62.3': - resolution: {integrity: sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==} + '@rollup/rollup-linux-ppc64-musl@4.62.4': + resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} cpu: [ppc64] os: [linux] libc: [musl] @@ -9905,8 +10318,8 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.62.3': - resolution: {integrity: sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==} + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} cpu: [riscv64] os: [linux] libc: [glibc] @@ -9917,8 +10330,8 @@ packages: os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-musl@4.62.3': - resolution: {integrity: sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==} + '@rollup/rollup-linux-riscv64-musl@4.62.4': + resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} cpu: [riscv64] os: [linux] libc: [musl] @@ -9929,8 +10342,8 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-linux-s390x-gnu@4.62.3': - resolution: {integrity: sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==} + '@rollup/rollup-linux-s390x-gnu@4.62.4': + resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} cpu: [s390x] os: [linux] libc: [glibc] @@ -9941,8 +10354,8 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.3': - resolution: {integrity: sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==} + '@rollup/rollup-linux-x64-gnu@4.62.4': + resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} cpu: [x64] os: [linux] libc: [glibc] @@ -9953,8 +10366,8 @@ packages: os: [linux] libc: [musl] - '@rollup/rollup-linux-x64-musl@4.62.3': - resolution: {integrity: sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==} + '@rollup/rollup-linux-x64-musl@4.62.4': + resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} cpu: [x64] os: [linux] libc: [musl] @@ -9964,8 +10377,8 @@ packages: cpu: [x64] os: [openbsd] - '@rollup/rollup-openbsd-x64@4.62.3': - resolution: {integrity: sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==} + '@rollup/rollup-openbsd-x64@4.62.4': + resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} cpu: [x64] os: [openbsd] @@ -9974,8 +10387,8 @@ packages: cpu: [arm64] os: [openharmony] - '@rollup/rollup-openharmony-arm64@4.62.3': - resolution: {integrity: sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==} + '@rollup/rollup-openharmony-arm64@4.62.4': + resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==} cpu: [arm64] os: [openharmony] @@ -9984,8 +10397,8 @@ packages: cpu: [arm64] os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.62.3': - resolution: {integrity: sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==} + '@rollup/rollup-win32-arm64-msvc@4.62.4': + resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==} cpu: [arm64] os: [win32] @@ -9994,8 +10407,8 @@ packages: cpu: [ia32] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.62.3': - resolution: {integrity: sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==} + '@rollup/rollup-win32-ia32-msvc@4.62.4': + resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==} cpu: [ia32] os: [win32] @@ -10004,8 +10417,8 @@ packages: cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.3': - resolution: {integrity: sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==} + '@rollup/rollup-win32-x64-gnu@4.62.4': + resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==} cpu: [x64] os: [win32] @@ -10014,8 +10427,8 @@ packages: cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.3': - resolution: {integrity: sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==} + '@rollup/rollup-win32-x64-msvc@4.62.4': + resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==} cpu: [x64] os: [win32] @@ -10112,8 +10525,8 @@ packages: resolution: {integrity: sha512-1Vcut4LEL9HZsdpI0vFiRYIsaoPwZLjAxnVQDUMQK8beMS+EYPLDQCXtbzfxmM5GzSgjfe2Q9M7WaXwIMQllyQ==} engines: {node: '>=18.0.0'} - '@smithy/core@3.31.0': - resolution: {integrity: sha512-sylYk2l9d7CmRv8ts8p0SDQUr3VO+HMeS1nrjL6+UtbO8ktJHTOeQ1McX+aAyvGGccp5aZX9eNtdcXrSwzoZaw==} + '@smithy/core@3.31.1': + resolution: {integrity: sha512-CyogUINxvi7C7LDsh8Syo6hVJOT9ckz4rG8dRZfTJ8r91HkMY59PnNooaj7WcHyxEkxPfBAmbgztZU+xTo76lg==} engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.2.11': @@ -10168,6 +10581,10 @@ packages: resolution: {integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==} engines: {node: '>=18.0.0'} + '@smithy/is-array-buffer@4.4.16': + resolution: {integrity: sha512-Uu5RVG+BjnS74dzSlQbK50ONlE3DD9YXdZwlBbZRCjvEp5KrBu/FPwO3SyDBYf6l12Q0DxSFdjeBiIh+7gNcmg==} + engines: {node: '>=18.0.0'} + '@smithy/md5-js@4.2.11': resolution: {integrity: sha512-350X4kGIrty0Snx2OWv7rPM6p6vM7RzryvFs6B/56Cux3w3sChOb3bymo5oidXJlPcP9fIRxGUCk7GqpiSOtng==} engines: {node: '>=18.0.0'} @@ -10284,12 +10701,8 @@ packages: resolution: {integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==} engines: {node: '>=18.0.0'} - '@smithy/util-hex-encoding@4.4.15': - resolution: {integrity: sha512-SBb6oMnuys6inwF82r5w3nfDaLwk/DTlEg2Pgk7GOUym6ZoTchEy7hBs5v3EHefqBrbBR+DPmSsSYNTJTv8QFw==} - engines: {node: '>=18.0.0'} - - '@smithy/util-hex-encoding@4.4.8': - resolution: {integrity: sha512-7U8V8aMAx5U7EFghoHfj0mch+AUSFEm/+u6ah5Gidp29vWzMtoOGUwD83Krt0VYNyZd1j67k1sH/UZLai/WLNw==} + '@smithy/util-hex-encoding@4.4.16': + resolution: {integrity: sha512-x9/taZ/r/nEL6SBfdV+M18VpJU16yzehn2q1XHNmXWEp3g5U4NBl2oMBVw7YKdmH2HiKQ/ZqDW5JjBDNzgLKrg==} engines: {node: '>=18.0.0'} '@smithy/util-middleware@4.2.11': @@ -10599,8 +11012,8 @@ packages: '@types/express-serve-static-core@4.19.8': resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} - '@types/express-serve-static-core@5.1.2': - resolution: {integrity: sha512-d3KvEXBSo/lOAMc2u6fkyDHBvetBHeqD7wm/AcXfLpSOQwlmG9D/aQ0SFswVjv05p7ullQS7Mjohj6/VdbZuTg==} + '@types/express-serve-static-core@5.1.3': + resolution: {integrity: sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==} '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} @@ -10746,8 +11159,8 @@ packages: '@types/lodash@4.17.17': resolution: {integrity: sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==} - '@types/lodash@4.17.24': - resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} + '@types/lodash@4.17.25': + resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==} '@types/mailparser@3.4.6': resolution: {integrity: sha512-wVV3cnIKzxTffaPH8iRnddX1zahbYB1ZEoAxyhoBo3TBCBuK6nZ8M8JYO/RhsCuuBVOw/DEN/t/ENbruwlxn6Q==} @@ -10807,8 +11220,8 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} - '@types/node@26.1.2': - resolution: {integrity: sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==} + '@types/node@26.2.0': + resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -10972,8 +11385,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.65.0': - resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==} + '@typescript-eslint/project-service@8.66.0': + resolution: {integrity: sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' @@ -10988,8 +11401,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/tsconfig-utils@8.65.0': - resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==} + '@typescript-eslint/tsconfig-utils@8.66.0': + resolution: {integrity: sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' @@ -11005,8 +11418,8 @@ packages: resolution: {integrity: sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.65.0': - resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==} + '@typescript-eslint/types@8.66.0': + resolution: {integrity: sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@8.62.1': @@ -11015,8 +11428,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/typescript-estree@8.65.0': - resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==} + '@typescript-eslint/typescript-estree@8.66.0': + resolution: {integrity: sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' @@ -11032,8 +11445,8 @@ packages: resolution: {integrity: sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.65.0': - resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} + '@typescript-eslint/visitor-keys@8.66.0': + resolution: {integrity: sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typespec/ts-http-runtime@0.2.2': @@ -11044,8 +11457,8 @@ packages: resolution: {integrity: sha512-91fp6CAAJSRtH5ja95T1FHSKa8aPW9/Zw6cta81jlZTUw/+Vq8jM/AfF/14h2b71wwR84JUTW/3Y8QPhDAawFA==} engines: {node: '>=20.0.0'} - '@typespec/ts-http-runtime@0.3.7': - resolution: {integrity: sha512-JVUD8X2tfDMWjcjLs4yVxxVrS8yR5vnh386GAXT9Qj79nBxxXSaHFQZg5FweLmT8HlPQ3kii6noUB+Z9RN7DvQ==} + '@typespec/ts-http-runtime@0.3.8': + resolution: {integrity: sha512-bLMpVcWZNzq6lYOybwFwOAR1IXKcHnhUNqYeHjl1bET/qE3jFPFH+p8Wrh3rU4xwdnifPxmKNESBYnvnmc75aA==} engines: {node: '>=22.0.0'} '@upsetjs/venn.js@2.0.0': @@ -11119,26 +11532,26 @@ packages: '@vue/compiler-core@3.5.16': resolution: {integrity: sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==} - '@vue/compiler-core@3.5.40': - resolution: {integrity: sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==} + '@vue/compiler-core@3.5.41': + resolution: {integrity: sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==} '@vue/compiler-dom@3.5.16': resolution: {integrity: sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==} - '@vue/compiler-dom@3.5.40': - resolution: {integrity: sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==} + '@vue/compiler-dom@3.5.41': + resolution: {integrity: sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==} '@vue/compiler-sfc@3.5.16': resolution: {integrity: sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==} - '@vue/compiler-sfc@3.5.40': - resolution: {integrity: sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==} + '@vue/compiler-sfc@3.5.41': + resolution: {integrity: sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==} '@vue/compiler-ssr@3.5.16': resolution: {integrity: sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==} - '@vue/compiler-ssr@3.5.40': - resolution: {integrity: sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==} + '@vue/compiler-ssr@3.5.41': + resolution: {integrity: sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==} '@vue/reactivity@3.5.16': resolution: {integrity: sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==} @@ -11157,8 +11570,8 @@ packages: '@vue/shared@3.5.16': resolution: {integrity: sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==} - '@vue/shared@3.5.40': - resolution: {integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==} + '@vue/shared@3.5.41': + resolution: {integrity: sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==} '@web/browser-logs@0.4.1': resolution: {integrity: sha512-ypmMG+72ERm+LvP+loj9A64MTXvWMXHUOu773cPO4L1SV/VWg6xA9Pv7vkvkXQX+ItJtCJt+KQ+U6ui2HhSFUw==} @@ -11287,10 +11700,12 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@xmldom/xmldom@0.9.10': resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==} engines: {node: '>=14.6'} + deprecated: this version has critical issues, please update to the latest version '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -11696,9 +12111,9 @@ packages: bare-buffer: optional: true - bare-fs@4.7.4: - resolution: {integrity: sha512-y1kC+ffIx/tPLdTE693uNjHfzTfr+ravR5tvWlMXe25nELbkqV400S71qHDwbkAQ1FVEZobB1NFRzFbCCcyBCQ==} - engines: {bare: '>=1.16.0'} + bare-fs@4.8.0: + resolution: {integrity: sha512-fM+MhCvdQhZ7NV6S95a07gPSqjIYKn6mFaXfx266wN3ajZGl/+1AzH+ubkXQ0fFZvOe2nk9VHkzdYkQE5zMV3Q==} + engines: {bare: '>=1.28.0'} peerDependencies: bare-buffer: '*' peerDependenciesMeta: @@ -11746,8 +12161,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.11.5: - resolution: {integrity: sha512-xJo6a6YZnwZfnyGmQKWMbVOcii7XRibjOskRh+WJ9UHQoX16xrQrcIgAMQOzfvs8XiLMx6ih/fsLPF73iY2D1A==} + baseline-browser-mapping@2.11.13: + resolution: {integrity: sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -11761,8 +12176,8 @@ packages: bent@7.3.12: resolution: {integrity: sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==} - better-sqlite3@12.6.2: - resolution: {integrity: sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==} + better-sqlite3@12.8.0: + resolution: {integrity: sha512-RxD2Vd96sQDjQr20kdP+F+dK/1OUNiVOl200vKBZY8u0vTwysfolF6Hq+3ZK2+h8My9YvZhHsF+RSGZW2VYrPQ==} engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} bidi-js@1.0.3: @@ -11818,14 +12233,14 @@ packages: bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - brace-expansion@1.1.16: - resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==} + brace-expansion@1.1.18: + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} - brace-expansion@2.1.3: - resolution: {integrity: sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A==} + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} - brace-expansion@5.0.8: - resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} engines: {node: 20 || >=22} braces@3.0.3: @@ -11835,8 +12250,8 @@ packages: browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - browserslist@4.28.7: - resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} + browserslist@4.28.8: + resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -11956,8 +12371,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001806: - resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} + caniuse-lite@1.0.30001809: + resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==} caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -12720,6 +13135,9 @@ packages: decode-named-character-reference@1.1.0: resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -12967,8 +13385,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.4.12: - resolution: {integrity: sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==} + dompurify@3.4.13: + resolution: {integrity: sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==} domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -13030,8 +13448,8 @@ packages: electron-publish@26.8.1: resolution: {integrity: sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==} - electron-to-chromium@1.5.397: - resolution: {integrity: sha512-khGTy9U9x02KEtsKM8vx5A62BsRmcOsIgDpWr1ImE32Ax8GxHGPHZf+Eu9H8zOOyHJnB0jTbseyTHbq2XCT8yw==} + electron-to-chromium@1.5.403: + resolution: {integrity: sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==} electron-updater@6.6.2: resolution: {integrity: sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw==} @@ -13051,9 +13469,9 @@ packages: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} engines: {node: '>=8.0.0'} - electron@40.8.5: - resolution: {integrity: sha512-pgTY/VPQKaiU4sTjfU96iyxCXrFm4htVPCMRT4b7q9ijNTRgtLmLvcmzp2G4e7xDrq9p7OLHSmu1rBKFf6Y1/A==} - engines: {node: '>= 12.20.55'} + electron@41.10.3: + resolution: {integrity: sha512-MJuSODPw8siv/I8JjhctW/cS/XNldwI4gLRyyWZx6QkoZJUDgbEvitp7IVOnGrHENTQb6Udo+zMpKhFnhlIhdg==} + engines: {node: '>= 22.12.0'} hasBin: true emittery@0.13.1: @@ -13101,8 +13519,8 @@ packages: resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} - enhanced-resolve@5.24.3: - resolution: {integrity: sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==} + enhanced-resolve@5.24.5: + resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} engines: {node: '>=10.13.0'} entities@2.2.0: @@ -13124,6 +13542,10 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + envinfo@7.11.0: resolution: {integrity: sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==} engines: {node: '>=4'} @@ -13204,6 +13626,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -13421,8 +13848,8 @@ packages: fast-levenshtein@3.0.0: resolution: {integrity: sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==} - fast-uri@3.1.4: - resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} fast-xml-builder@1.2.0: resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} @@ -13838,6 +14265,9 @@ packages: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} engines: {node: '>=10.19.0'} + gpt-tokenizer@2.9.0: + resolution: {integrity: sha512-YSpexBL/k4bfliAzMrRqn3M6+it02LutVyhVpDeMKrC/O9+pCe/5s8U2hYKa2vFLD5/vHhsKc8sOn/qGqII8Kg==} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -13952,8 +14382,8 @@ packages: highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hono@4.12.29: - resolution: {integrity: sha512-1hNiRjawYrLq/4m3DQQjPGFg0VZkk4RjQJDff/excI6Dm9BiL75qxGrd7/c6YOxPdq6AscP3LiXhQ6fKFC1Waw==} + hono@4.13.0: + resolution: {integrity: sha512-jhunvfHWxd7J5EFfSgH4xsYJzSe/lfqbUCxiyyeaQasUsXeEHXtzVid+7EOGByc5JnFa23SSFL3Y2RV/z1T+eQ==} engines: {node: '>=16.9.0'} hosted-git-info@4.1.0: @@ -14221,6 +14651,10 @@ packages: resolution: {integrity: sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==} engines: {node: '>= 12'} + ip-address@10.5.0: + resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} + engines: {node: '>= 12'} + ip-regex@4.3.0: resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} engines: {node: '>=8'} @@ -14746,18 +15180,21 @@ packages: jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + jose@6.2.8: + resolution: {integrity: sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==} + js-stringify@1.0.2: resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.15.0: - resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==} + js-yaml@3.15.1: + resolution: {integrity: sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==} hasBin: true - js-yaml@4.3.0: - resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true jsbi@2.0.5: @@ -15353,8 +15790,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - mermaid@11.15.0: - resolution: {integrity: sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==} + mermaid@11.16.1: + resolution: {integrity: sha512-TQsq6u22fAn3rek5VOubrhKPo1g5hwC3FXUN9hiyupTckcYiGuuKGkNQrKYwGJkXUxZdojwRG46gsSCFZMDp4g==} methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} @@ -15580,8 +16017,8 @@ packages: engines: {node: '>= 14.0.0'} hasBin: true - mocha@11.7.6: - resolution: {integrity: sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==} + mocha@11.8.0: + resolution: {integrity: sha512-VyCeUdGN3A9lmCTTgG4yuvY9ixxaDk+xt2R/7/+1AP6EqNG+G9OKkzBwhVtVYoNX8YsxNSgAl8mOv3IAeOpFbw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true @@ -15652,13 +16089,18 @@ packages: nanocolors@0.2.13: resolution: {integrity: sha512-0n3mSAQLPpGLV9ORXT5+C/D4mwew7Ebws69Hx4E2sgz2ZA5+32Q80B9tL8PbL7XHnRDiAxH/pnrUJ9a4fkTNTA==} - nanoid@3.3.16: - resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + nanoid@3.3.17: + resolution: {integrity: sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.5: - resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} + nanoid@5.1.16: + resolution: {integrity: sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==} engines: {node: ^18 || >=20} hasBin: true @@ -15760,8 +16202,8 @@ packages: node-pty@1.1.0: resolution: {integrity: sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==} - node-releases@2.0.51: - resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} + node-releases@2.0.53: + resolution: {integrity: sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==} engines: {node: '>=18'} node-rsa@1.1.1: @@ -16261,6 +16703,10 @@ packages: resolution: {integrity: sha512-8RyVklq0owXUTa4xlpzu4l9AaVKIdQvAcOHZWaMh98HgySsUtxRVf/chRe3dsSLqb6i40BzGRzEUddRaI+9TSw==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + postject@1.0.0-alpha.6: resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} engines: {node: '>=14.0.0'} @@ -16856,8 +17302,8 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rollup@4.62.3: - resolution: {integrity: sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==} + rollup@4.62.4: + resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -17038,8 +17484,8 @@ packages: resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} engines: {node: '>=20.0.0'} - serialize-javascript@7.0.7: - resolution: {integrity: sha512-YAy8Od6KV+uuwUuU50np8fGB/Aues6Y0nAhA9y/hId74PlKUcme4pXcBD46NWKr1Q4osN/iseZ17YqO1XfmI8g==} + serialize-javascript@7.1.0: + resolution: {integrity: sha512-RNEqWOyhhUQYN9V1GfHwu9AR/g+NTciH6Z5u3/no6X3/w+04J2lVDL+svFQVXgXrEGBMG2puMVN3gq2SNGuTGw==} engines: {node: '>=20.0.0'} serve-index@1.9.2: @@ -17576,8 +18022,8 @@ packages: engines: {node: '>=10'} hasBin: true - terser@5.49.0: - resolution: {integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==} + terser@5.49.2: + resolution: {integrity: sha512-rGbJiKeQ4WDe3EXlDAIaQcwftVfv2Q8o1awFNfvXolJYKkb1AuZY1RTOmqx4LJXZENbWZA7eIsYGHuEzHsi1nQ==} engines: {node: '>=10'} hasBin: true @@ -18074,8 +18520,8 @@ packages: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + update-browserslist-db@1.3.0: + resolution: {integrity: sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -18500,8 +18946,8 @@ packages: utf-8-validate: optional: true - ws@8.21.1: - resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -18791,36 +19237,6 @@ snapshots: '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.162 '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.162 - '@anthropic-ai/claude-agent-sdk@0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.3.6))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6)': - dependencies: - '@anthropic-ai/sdk': 0.93.0(zod@4.3.6) - '@modelcontextprotocol/sdk': 1.26.0(zod@4.4.3) - zod: 4.3.6 - optionalDependencies: - '@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.162 - '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.162 - - '@anthropic-ai/claude-agent-sdk@0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.3.6)': - dependencies: - '@anthropic-ai/sdk': 0.93.0(zod@4.4.3) - '@modelcontextprotocol/sdk': 1.26.0(zod@4.4.3) - zod: 4.3.6 - optionalDependencies: - '@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.162 - '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.162 - '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.162 - '@anthropic-ai/claude-agent-sdk@0.3.162(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(zod@4.4.3)': dependencies: '@anthropic-ai/sdk': 0.93.0(zod@4.4.3) @@ -19355,7 +19771,7 @@ snapshots: '@azure/core-auth': 1.11.0 '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.4.0 - '@typespec/ts-http-runtime': 0.3.7 + '@typespec/ts-http-runtime': 0.3.8 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -19384,7 +19800,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@azure/ai-projects@2.2.0(ws@8.21.1)(zod@3.25.76)': + '@azure/ai-projects@2.2.0(ws@8.21.3)(zod@3.25.76)': dependencies: '@azure-rest/core-client': 2.4.0 '@azure/abort-controller': 2.1.2 @@ -19398,7 +19814,7 @@ snapshots: '@azure/identity': 4.13.1 '@azure/logger': 1.3.0 '@azure/storage-blob': 12.27.0 - openai: 6.41.0(ws@8.21.1)(zod@3.25.76) + openai: 6.41.0(ws@8.21.3)(zod@3.25.76) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -19544,7 +19960,7 @@ snapshots: '@azure/core-tracing': 1.4.0 '@azure/core-util': 1.14.0 '@azure/logger': 1.4.0 - '@typespec/ts-http-runtime': 0.3.7 + '@typespec/ts-http-runtime': 0.3.8 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -19581,7 +19997,7 @@ snapshots: '@azure/core-util@1.14.0': dependencies: '@azure/abort-controller': 2.2.0 - '@typespec/ts-http-runtime': 0.3.7 + '@typespec/ts-http-runtime': 0.3.8 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -19613,7 +20029,7 @@ snapshots: '@azure/core-auth': 1.10.1 '@azure/identity': 4.10.0 '@azure/msal-node': 5.2.0 - '@azure/msal-node-extensions': 5.3.3 + '@azure/msal-node-extensions': 5.3.5 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -19740,7 +20156,7 @@ snapshots: '@azure/logger@1.4.0': dependencies: - '@typespec/ts-http-runtime': 0.3.7 + '@typespec/ts-http-runtime': 0.3.8 tslib: 2.6.2 transitivePeerDependencies: - supports-color @@ -19767,7 +20183,7 @@ snapshots: '@azure/msal-common@15.6.0': {} - '@azure/msal-common@16.11.2': {} + '@azure/msal-common@16.12.0': {} '@azure/msal-common@16.6.0': {} @@ -19785,16 +20201,14 @@ snapshots: '@azure/msal-node-runtime': 0.20.6 keytar: 7.9.0 - '@azure/msal-node-extensions@5.3.3': + '@azure/msal-node-extensions@5.3.5': dependencies: - '@azure/msal-common': 16.11.2 - '@azure/msal-node-runtime': 0.20.5 + '@azure/msal-common': 16.12.0 + '@azure/msal-node-runtime': 0.20.6 keytar: 7.9.0 '@azure/msal-node-runtime@0.18.2': {} - '@azure/msal-node-runtime@0.20.5': {} - '@azure/msal-node-runtime@0.20.6': {} '@azure/msal-node@3.5.3': @@ -19858,14 +20272,14 @@ snapshots: '@babel/core@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helpers': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3(supports-color@8.1.1) @@ -19875,10 +20289,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.7': + '@babel/generator@7.29.8': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 @@ -19887,7 +20301,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.7 '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.7 + browserslist: 4.28.8 lru-cache: 5.1.1 semver: 6.3.1 @@ -19895,8 +20309,8 @@ snapshots: '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -19905,7 +20319,7 @@ snapshots: '@babel/core': 7.29.7 '@babel/helper-module-imports': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -19922,11 +20336,11 @@ snapshots: '@babel/helpers@7.29.7': dependencies: '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 - '@babel/parser@7.29.7': + '@babel/parser@7.29.8': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': dependencies: @@ -20027,22 +20441,22 @@ snapshots: '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 - '@babel/traverse@7.29.7': + '@babel/traverse@7.29.8': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/types@7.29.7': + '@babel/types@7.29.8': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 @@ -20322,7 +20736,7 @@ snapshots: '@codemirror/lint@6.9.7': dependencies: '@codemirror/state': 6.5.2 - '@codemirror/view': 6.43.7 + '@codemirror/view': 6.43.8 crelt: 1.0.7 '@codemirror/search@6.5.11': @@ -20353,7 +20767,7 @@ snapshots: style-mod: 4.1.2 w3c-keyname: 2.2.8 - '@codemirror/view@6.43.7': + '@codemirror/view@6.43.8': dependencies: '@codemirror/state': 6.7.1 crelt: 1.0.7 @@ -20415,8 +20829,8 @@ snapshots: '@elastic/transport@9.3.5(supports-color@8.1.1)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.1) debug: 4.4.1(supports-color@8.1.1) hpagent: 1.2.0 ms: 2.1.3 @@ -20426,9 +20840,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron-toolkit/preload@3.0.2(electron@40.8.5(supports-color@8.1.1))': + '@electron-internal/extract-zip@1.0.5': {} + + '@electron-toolkit/preload@3.0.2(electron@41.10.3(supports-color@8.1.1))': dependencies: - electron: 40.8.5(supports-color@8.1.1) + electron: 41.10.3(supports-color@8.1.1) '@electron-toolkit/tsconfig@1.0.1(@types/node@22.20.1)': dependencies: @@ -20446,9 +20862,9 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@2.0.3(supports-color@8.1.1)': + '@electron/get@3.1.0': dependencies: - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 @@ -20460,17 +20876,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/get@3.1.0': + '@electron/get@5.1.0(supports-color@8.1.1)': dependencies: - debug: 4.4.3(supports-color@8.1.1) - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 + debug: 4.4.1(supports-color@8.1.1) + env-paths: 3.0.0 + graceful-fs: 4.2.11 progress: 2.0.3 - semver: 6.3.1 + semver: 7.8.5 sumchecker: 3.0.1(supports-color@8.1.1) optionalDependencies: - global-agent: 3.0.0 + undici: 7.29.0 transitivePeerDependencies: - supports-color @@ -20489,7 +20904,7 @@ snapshots: fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 - plist: 3.1.1 + plist: 3.1.0 transitivePeerDependencies: - supports-color @@ -20512,7 +20927,7 @@ snapshots: dir-compare: 4.2.0 fs-extra: 11.4.0 minimatch: 9.0.9 - plist: 3.1.1 + plist: 3.1.0 transitivePeerDependencies: - supports-color @@ -20567,6 +20982,9 @@ snapshots: '@esbuild/aix-ppc64@0.28.1': optional: true + '@esbuild/aix-ppc64@0.28.2': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true @@ -20576,6 +20994,9 @@ snapshots: '@esbuild/android-arm64@0.28.1': optional: true + '@esbuild/android-arm64@0.28.2': + optional: true + '@esbuild/android-arm@0.25.12': optional: true @@ -20585,6 +21006,9 @@ snapshots: '@esbuild/android-arm@0.28.1': optional: true + '@esbuild/android-arm@0.28.2': + optional: true + '@esbuild/android-x64@0.25.12': optional: true @@ -20594,6 +21018,9 @@ snapshots: '@esbuild/android-x64@0.28.1': optional: true + '@esbuild/android-x64@0.28.2': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true @@ -20603,6 +21030,9 @@ snapshots: '@esbuild/darwin-arm64@0.28.1': optional: true + '@esbuild/darwin-arm64@0.28.2': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true @@ -20612,6 +21042,9 @@ snapshots: '@esbuild/darwin-x64@0.28.1': optional: true + '@esbuild/darwin-x64@0.28.2': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true @@ -20621,6 +21054,9 @@ snapshots: '@esbuild/freebsd-arm64@0.28.1': optional: true + '@esbuild/freebsd-arm64@0.28.2': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true @@ -20630,6 +21066,9 @@ snapshots: '@esbuild/freebsd-x64@0.28.1': optional: true + '@esbuild/freebsd-x64@0.28.2': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true @@ -20639,6 +21078,9 @@ snapshots: '@esbuild/linux-arm64@0.28.1': optional: true + '@esbuild/linux-arm64@0.28.2': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true @@ -20648,6 +21090,9 @@ snapshots: '@esbuild/linux-arm@0.28.1': optional: true + '@esbuild/linux-arm@0.28.2': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true @@ -20657,6 +21102,9 @@ snapshots: '@esbuild/linux-ia32@0.28.1': optional: true + '@esbuild/linux-ia32@0.28.2': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true @@ -20666,6 +21114,9 @@ snapshots: '@esbuild/linux-loong64@0.28.1': optional: true + '@esbuild/linux-loong64@0.28.2': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true @@ -20675,6 +21126,9 @@ snapshots: '@esbuild/linux-mips64el@0.28.1': optional: true + '@esbuild/linux-mips64el@0.28.2': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true @@ -20684,6 +21138,9 @@ snapshots: '@esbuild/linux-ppc64@0.28.1': optional: true + '@esbuild/linux-ppc64@0.28.2': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true @@ -20693,6 +21150,9 @@ snapshots: '@esbuild/linux-riscv64@0.28.1': optional: true + '@esbuild/linux-riscv64@0.28.2': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true @@ -20702,6 +21162,9 @@ snapshots: '@esbuild/linux-s390x@0.28.1': optional: true + '@esbuild/linux-s390x@0.28.2': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true @@ -20711,6 +21174,9 @@ snapshots: '@esbuild/linux-x64@0.28.1': optional: true + '@esbuild/linux-x64@0.28.2': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true @@ -20720,6 +21186,9 @@ snapshots: '@esbuild/netbsd-arm64@0.28.1': optional: true + '@esbuild/netbsd-arm64@0.28.2': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true @@ -20729,6 +21198,9 @@ snapshots: '@esbuild/netbsd-x64@0.28.1': optional: true + '@esbuild/netbsd-x64@0.28.2': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true @@ -20738,6 +21210,9 @@ snapshots: '@esbuild/openbsd-arm64@0.28.1': optional: true + '@esbuild/openbsd-arm64@0.28.2': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true @@ -20747,6 +21222,9 @@ snapshots: '@esbuild/openbsd-x64@0.28.1': optional: true + '@esbuild/openbsd-x64@0.28.2': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true @@ -20756,6 +21234,9 @@ snapshots: '@esbuild/openharmony-arm64@0.28.1': optional: true + '@esbuild/openharmony-arm64@0.28.2': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true @@ -20765,6 +21246,9 @@ snapshots: '@esbuild/sunos-x64@0.28.1': optional: true + '@esbuild/sunos-x64@0.28.2': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true @@ -20774,6 +21258,9 @@ snapshots: '@esbuild/win32-arm64@0.28.1': optional: true + '@esbuild/win32-arm64@0.28.2': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true @@ -20783,6 +21270,9 @@ snapshots: '@esbuild/win32-ia32@0.28.1': optional: true + '@esbuild/win32-ia32@0.28.2': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true @@ -20792,6 +21282,9 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true + '@esbuild/win32-x64@0.28.2': + optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@10.6.0(jiti@2.7.0)(supports-color@8.1.1))': dependencies: eslint: 10.6.0(jiti@2.7.0)(supports-color@8.1.1) @@ -20856,10 +21349,10 @@ snapshots: '@fluid-tools/version-tools@0.57.0(@types/node@22.15.18)(supports-color@8.1.1)': dependencies: - '@oclif/core': 4.13.2 + '@oclif/core': 4.13.3 '@oclif/plugin-autocomplete': 3.2.24(supports-color@8.1.1) '@oclif/plugin-commands': 4.1.21 - '@oclif/plugin-help': 6.2.55 + '@oclif/plugin-help': 6.2.58 '@oclif/plugin-not-found': 3.2.65(@types/node@22.15.18) semver: 7.8.4 table: 6.9.0 @@ -20872,10 +21365,10 @@ snapshots: '@fluid-tools/version-tools@0.57.0(@types/node@22.20.1)': dependencies: - '@oclif/core': 4.13.2 + '@oclif/core': 4.13.3 '@oclif/plugin-autocomplete': 3.2.24(supports-color@8.1.1) '@oclif/plugin-commands': 4.1.21 - '@oclif/plugin-help': 6.2.55 + '@oclif/plugin-help': 6.2.58 '@oclif/plugin-not-found': 3.2.65(@types/node@22.20.1) semver: 7.8.4 table: 6.9.0 @@ -21001,9 +21494,9 @@ snapshots: '@hapi/bourne@3.0.0': {} - '@hono/node-server@1.19.17(hono@4.12.29)': + '@hono/node-server@1.19.17(hono@4.13.0)': dependencies: - hono: 4.12.29 + hono: 4.13.0 '@huggingface/jinja@0.5.9': optional: true @@ -21474,7 +21967,7 @@ snapshots: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 - js-yaml: 3.15.0 + js-yaml: 3.15.1 resolve-from: 5.0.0 '@istanbuljs/schema@0.1.3': {} @@ -21484,12 +21977,47 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.19.40)(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': 26.2.0 + 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@26.2.0)(ts-node@10.9.2(@types/node@20.19.40)(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 @@ -21497,14 +22025,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 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@26.1.2)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21532,14 +22060,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 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@26.1.2)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21567,14 +22095,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 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@26.1.2)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21595,21 +22123,21 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5))': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@26.2.0)(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': 26.1.2 + '@types/node': 26.2.0 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@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21634,7 +22162,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -21674,7 +22202,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 26.1.2 + '@types/node': 26.2.0 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -22082,13 +22610,13 @@ snapshots: dependencies: fast-glob: 3.3.3 jju: 1.4.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 '@marijn/find-cluster-break@1.0.2': {} '@marijn/find-cluster-break@1.0.3': {} - '@mermaid-js/parser@1.1.1': + '@mermaid-js/parser@1.2.0': dependencies: '@chevrotain/types': 11.1.2 @@ -22119,10 +22647,10 @@ snapshots: '@types/lodash.debounce': 4.0.9 '@types/lodash.throttle': 4.1.9 clsx: 2.1.1 - dompurify: 3.4.12 + dompurify: 3.4.13 lodash.debounce: 4.0.8 lodash.throttle: 4.1.1 - nanoid: 5.1.5 + nanoid: 5.1.16 tslib: 2.8.1 unist-util-visit: 5.1.0 vue: 3.5.16(typescript@5.4.5) @@ -22157,7 +22685,7 @@ snapshots: codemirror: 6.0.1 katex: 0.16.22 lodash-es: 4.18.1 - nanoid: 5.1.5 + nanoid: 5.1.16 prosemirror-virtual-cursor: 0.4.2(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0) remark-math: 6.0.0 tslib: 2.8.1 @@ -22413,14 +22941,28 @@ snapshots: '@milkdown/exception': 7.13.1 '@milkdown/prose': 7.13.1 '@milkdown/transformer': 7.13.1 - nanoid: 5.1.5 + nanoid: 5.1.16 tslib: 2.8.1 transitivePeerDependencies: - supports-color + '@modelcontextprotocol/client@2.0.0': + dependencies: + '@modelcontextprotocol/core': 2.0.0 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + jose: 6.2.8 + pkce-challenge: 5.0.1 + zod: 4.4.3 + + '@modelcontextprotocol/core@2.0.0': + dependencies: + zod: 4.4.3 + '@modelcontextprotocol/sdk@1.26.0(supports-color@8.1.1)(zod@4.1.13)': dependencies: - '@hono/node-server': 1.19.17(hono@4.12.29) + '@hono/node-server': 1.19.17(hono@4.13.0) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -22430,7 +22972,7 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1(supports-color@8.1.1) express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.29 + hono: 4.13.0 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -22442,7 +22984,7 @@ snapshots: '@modelcontextprotocol/sdk@1.26.0(zod@3.25.76)': dependencies: - '@hono/node-server': 1.19.17(hono@4.12.29) + '@hono/node-server': 1.19.17(hono@4.13.0) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -22452,7 +22994,7 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1(supports-color@8.1.1) express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.29 + hono: 4.13.0 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -22464,7 +23006,7 @@ snapshots: '@modelcontextprotocol/sdk@1.26.0(zod@4.3.6)': dependencies: - '@hono/node-server': 1.19.17(hono@4.12.29) + '@hono/node-server': 1.19.17(hono@4.13.0) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -22474,7 +23016,7 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1(supports-color@8.1.1) express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.29 + hono: 4.13.0 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -22486,7 +23028,7 @@ snapshots: '@modelcontextprotocol/sdk@1.26.0(zod@4.4.3)': dependencies: - '@hono/node-server': 1.19.17(hono@4.12.29) + '@hono/node-server': 1.19.17(hono@4.13.0) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -22496,7 +23038,7 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1(supports-color@8.1.1) express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.29 + hono: 4.13.0 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -22580,6 +23122,9 @@ snapshots: '@napi-rs/canvas-win32-x64-msvc': 0.1.72 optional: true + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)': dependencies: '@emnapi/core': 1.11.0 @@ -22612,7 +23157,7 @@ snapshots: '@nornagon/put@0.0.8': {} - '@oclif/core@4.13.2': + '@oclif/core@4.13.3': dependencies: ansi-escapes: 4.3.2 ansis: 3.17.0 @@ -22677,7 +23222,7 @@ snapshots: '@oclif/plugin-autocomplete@3.2.24(supports-color@8.1.1)': dependencies: - '@oclif/core': 4.13.2 + '@oclif/core': 4.13.3 ansis: 3.17.0 debug: 4.4.3(supports-color@8.1.1) ejs: 3.1.10 @@ -22686,7 +23231,7 @@ snapshots: '@oclif/plugin-commands@4.1.21': dependencies: - '@oclif/core': 4.13.2 + '@oclif/core': 4.13.3 '@oclif/table': 0.4.6 lodash: 4.18.1 object-treeify: 4.0.1 @@ -22699,14 +23244,14 @@ snapshots: dependencies: '@oclif/core': 4.5.2 - '@oclif/plugin-help@6.2.55': + '@oclif/plugin-help@6.2.58': dependencies: - '@oclif/core': 4.13.2 + '@oclif/core': 4.13.3 '@oclif/plugin-not-found@3.2.65(@types/node@22.15.18)': dependencies: '@inquirer/prompts': 7.8.3(@types/node@22.15.18) - '@oclif/core': 4.13.2 + '@oclif/core': 4.13.3 ansis: 3.17.0 fast-levenshtein: 3.0.0 transitivePeerDependencies: @@ -22715,7 +23260,7 @@ snapshots: '@oclif/plugin-not-found@3.2.65(@types/node@22.20.1)': dependencies: '@inquirer/prompts': 7.8.3(@types/node@22.20.1) - '@oclif/core': 4.13.2 + '@oclif/core': 4.13.3 ansis: 3.17.0 fast-levenshtein: 3.0.0 transitivePeerDependencies: @@ -22789,14 +23334,117 @@ snapshots: - supports-color - utf-8-validate + '@opentelemetry/api-logs@0.221.0': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api@1.9.0': {} - '@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/api@1.9.1': {} + + '@opentelemetry/context-async-hooks@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/exporter-logs-otlp-proto@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/otlp-exporter-base': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.221.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-metrics-otlp-http@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.10.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-metrics-otlp-proto@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/exporter-metrics-otlp-http': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.221.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-trace-otlp-proto@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/otlp-exporter-base': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.10.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/otlp-exporter-base@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.221.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/otlp-transformer@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.221.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.10.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.221.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-trace-node@2.10.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.34.0 + '@opentelemetry/context-async-hooks': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.10.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions@1.34.0': {} + '@opentelemetry/sdk-trace@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/semantic-conventions@1.43.0': {} '@oxc-parser/binding-android-arm-eabi@0.137.0': optional: true @@ -23105,172 +23753,172 @@ snapshots: '@remusao/trie@1.5.0': {} - '@rollup/plugin-node-resolve@15.3.1(rollup@4.62.3)': + '@rollup/plugin-node-resolve@15.3.1(rollup@4.62.4)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.62.3) + '@rollup/pluginutils': 5.3.0(rollup@4.62.4) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.12 optionalDependencies: - rollup: 4.62.3 + rollup: 4.62.4 - '@rollup/pluginutils@5.3.0(rollup@4.62.3)': + '@rollup/pluginutils@5.3.0(rollup@4.62.4)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.5 optionalDependencies: - rollup: 4.62.3 + rollup: 4.62.4 '@rollup/rollup-android-arm-eabi@4.62.2': optional: true - '@rollup/rollup-android-arm-eabi@4.62.3': + '@rollup/rollup-android-arm-eabi@4.62.4': optional: true '@rollup/rollup-android-arm64@4.62.2': optional: true - '@rollup/rollup-android-arm64@4.62.3': + '@rollup/rollup-android-arm64@4.62.4': optional: true '@rollup/rollup-darwin-arm64@4.62.2': optional: true - '@rollup/rollup-darwin-arm64@4.62.3': + '@rollup/rollup-darwin-arm64@4.62.4': optional: true '@rollup/rollup-darwin-x64@4.62.2': optional: true - '@rollup/rollup-darwin-x64@4.62.3': + '@rollup/rollup-darwin-x64@4.62.4': optional: true '@rollup/rollup-freebsd-arm64@4.62.2': optional: true - '@rollup/rollup-freebsd-arm64@4.62.3': + '@rollup/rollup-freebsd-arm64@4.62.4': optional: true '@rollup/rollup-freebsd-x64@4.62.2': optional: true - '@rollup/rollup-freebsd-x64@4.62.3': + '@rollup/rollup-freebsd-x64@4.62.4': optional: true '@rollup/rollup-linux-arm-gnueabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.62.3': + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': optional: true '@rollup/rollup-linux-arm-musleabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.3': + '@rollup/rollup-linux-arm-musleabihf@4.62.4': optional: true '@rollup/rollup-linux-arm64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.3': + '@rollup/rollup-linux-arm64-gnu@4.62.4': optional: true '@rollup/rollup-linux-arm64-musl@4.62.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.62.3': + '@rollup/rollup-linux-arm64-musl@4.62.4': optional: true '@rollup/rollup-linux-loong64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.3': + '@rollup/rollup-linux-loong64-gnu@4.62.4': optional: true '@rollup/rollup-linux-loong64-musl@4.62.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.3': + '@rollup/rollup-linux-loong64-musl@4.62.4': optional: true '@rollup/rollup-linux-ppc64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.3': + '@rollup/rollup-linux-ppc64-gnu@4.62.4': optional: true '@rollup/rollup-linux-ppc64-musl@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.3': + '@rollup/rollup-linux-ppc64-musl@4.62.4': optional: true '@rollup/rollup-linux-riscv64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.3': + '@rollup/rollup-linux-riscv64-gnu@4.62.4': optional: true '@rollup/rollup-linux-riscv64-musl@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.3': + '@rollup/rollup-linux-riscv64-musl@4.62.4': optional: true '@rollup/rollup-linux-s390x-gnu@4.62.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.3': + '@rollup/rollup-linux-s390x-gnu@4.62.4': optional: true '@rollup/rollup-linux-x64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.3': + '@rollup/rollup-linux-x64-gnu@4.62.4': optional: true '@rollup/rollup-linux-x64-musl@4.62.2': optional: true - '@rollup/rollup-linux-x64-musl@4.62.3': + '@rollup/rollup-linux-x64-musl@4.62.4': optional: true '@rollup/rollup-openbsd-x64@4.62.2': optional: true - '@rollup/rollup-openbsd-x64@4.62.3': + '@rollup/rollup-openbsd-x64@4.62.4': optional: true '@rollup/rollup-openharmony-arm64@4.62.2': optional: true - '@rollup/rollup-openharmony-arm64@4.62.3': + '@rollup/rollup-openharmony-arm64@4.62.4': optional: true '@rollup/rollup-win32-arm64-msvc@4.62.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.3': + '@rollup/rollup-win32-arm64-msvc@4.62.4': optional: true '@rollup/rollup-win32-ia32-msvc@4.62.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.3': + '@rollup/rollup-win32-ia32-msvc@4.62.4': optional: true '@rollup/rollup-win32-x64-gnu@4.62.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.62.3': + '@rollup/rollup-win32-x64-gnu@4.62.4': optional: true '@rollup/rollup-win32-x64-msvc@4.62.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.3': + '@rollup/rollup-win32-x64-msvc@4.62.4': optional: true '@secretlint/config-creator@9.3.2': @@ -23409,7 +24057,7 @@ snapshots: '@smithy/uuid': 1.1.2 tslib: 2.8.1 - '@smithy/core@3.31.0': + '@smithy/core@3.31.1': dependencies: '@smithy/types': 4.16.1 tslib: 2.8.1 @@ -23426,7 +24074,7 @@ snapshots: dependencies: '@aws-crypto/crc32': 5.2.0 '@smithy/types': 4.13.0 - '@smithy/util-hex-encoding': 4.4.15 + '@smithy/util-hex-encoding': 4.4.16 tslib: 2.8.1 '@smithy/eventstream-serde-browser@4.2.11': @@ -23493,6 +24141,11 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/is-array-buffer@4.4.16': + dependencies: + '@smithy/core': 3.31.1 + tslib: 2.8.1 + '@smithy/md5-js@4.2.11': dependencies: '@smithy/types': 4.13.0 @@ -23586,10 +24239,10 @@ snapshots: '@smithy/signature-v4@5.3.11': dependencies: - '@smithy/is-array-buffer': 4.2.2 + '@smithy/is-array-buffer': 4.4.16 '@smithy/protocol-http': 5.3.11 '@smithy/types': 4.13.0 - '@smithy/util-hex-encoding': 4.4.8 + '@smithy/util-hex-encoding': 4.4.16 '@smithy/util-middleware': 4.2.11 '@smithy/util-uri-escape': 4.2.2 '@smithy/util-utf8': 4.2.2 @@ -23640,7 +24293,7 @@ snapshots: '@smithy/util-buffer-from@4.2.2': dependencies: - '@smithy/is-array-buffer': 4.2.2 + '@smithy/is-array-buffer': 4.4.16 tslib: 2.8.1 '@smithy/util-config-provider@4.2.2': @@ -23674,14 +24327,9 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-hex-encoding@4.4.15': + '@smithy/util-hex-encoding@4.4.16': dependencies: - '@smithy/core': 3.31.0 - tslib: 2.8.1 - - '@smithy/util-hex-encoding@4.4.8': - dependencies: - '@smithy/core': 3.31.0 + '@smithy/core': 3.31.1 tslib: 2.8.1 '@smithy/util-middleware@4.2.11': @@ -23749,7 +24397,7 @@ snapshots: '@textlint/types': 14.7.1 chalk: 4.1.2 debug: 4.4.1(supports-color@8.1.1) - js-yaml: 3.15.0 + js-yaml: 3.15.1 lodash: 4.18.1 pluralize: 2.0.0 string-width: 4.2.3 @@ -23799,7 +24447,7 @@ snapshots: '@types/accepts@1.3.7': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/async@3.2.24': {} @@ -23807,52 +24455,52 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/better-sqlite3@7.6.11': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/better-sqlite3@7.6.13': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/bonjour@3.5.13': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/cacheable-request@6.0.3': dependencies: '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 24.13.3 + '@types/node': 22.20.1 '@types/responselike': 1.0.3 '@types/chai-dom@1.11.3': @@ -23883,7 +24531,7 @@ snapshots: '@types/co-body@6.1.3': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/qs': 6.15.1 '@types/command-line-args@5.2.3': {} @@ -23893,11 +24541,11 @@ snapshots: '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 4.19.8 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/connect@3.4.38': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/content-disposition@0.5.9': {} @@ -23908,11 +24556,11 @@ snapshots: '@types/connect': 3.4.38 '@types/express': 5.0.6 '@types/keygrip': 1.0.6 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/cors@2.8.18': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/cytoscape-dagre@2.3.3': dependencies: @@ -24069,21 +24717,21 @@ snapshots: '@types/express-serve-static-core@4.17.41': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/qs': 6.15.0 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 '@types/express-serve-static-core@4.19.8': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/qs': 6.15.1 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 - '@types/express-serve-static-core@5.1.2': + '@types/express-serve-static-core@5.1.3': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/qs': 6.15.1 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -24105,7 +24753,7 @@ snapshots: '@types/express@5.0.6': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.1.2 + '@types/express-serve-static-core': 5.1.3 '@types/serve-static': 2.2.0 '@types/fast-levenshtein@0.0.4': {} @@ -24129,7 +24777,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/fs-extra@9.0.13': dependencies: @@ -24168,7 +24816,7 @@ snapshots: '@types/http-proxy@1.17.17': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/istanbul-lib-coverage@2.0.6': {} @@ -24216,7 +24864,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/jsonpath@0.2.4': {} @@ -24226,7 +24874,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 24.13.3 + '@types/node': 22.20.1 '@types/koa-compose@3.2.9': dependencies: @@ -24241,7 +24889,7 @@ snapshots: '@types/http-errors': 2.0.5 '@types/keygrip': 1.0.6 '@types/koa-compose': 3.2.9 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/linkify-it@5.0.0': {} @@ -24251,19 +24899,19 @@ snapshots: '@types/lodash.debounce@4.0.9': dependencies: - '@types/lodash': 4.17.24 + '@types/lodash': 4.17.25 '@types/lodash.throttle@4.1.9': dependencies: - '@types/lodash': 4.17.24 + '@types/lodash': 4.17.25 '@types/lodash@4.17.17': {} - '@types/lodash@4.17.24': {} + '@types/lodash@4.17.25': {} '@types/mailparser@3.4.6': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 iconv-lite: 0.6.3 '@types/markdown-it@14.1.2': @@ -24326,7 +24974,7 @@ snapshots: dependencies: undici-types: 7.18.2 - '@types/node@26.1.2': + '@types/node@26.2.0': dependencies: undici-types: 8.3.0 @@ -24365,7 +25013,7 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 24.13.3 + '@types/node': 22.20.1 '@types/retry@0.12.2': {} @@ -24376,16 +25024,16 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/send@1.2.1': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/serve-index@1.9.4': dependencies: @@ -24394,19 +25042,19 @@ snapshots: '@types/serve-static@1.15.10': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/send': 0.17.6 '@types/serve-static@1.15.5': dependencies: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/sinon-chai@3.2.12': dependencies: @@ -24423,7 +25071,7 @@ snapshots: '@types/sockjs@0.3.36': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/spotify-api@0.0.25': {} @@ -24456,15 +25104,15 @@ snapshots: '@types/ws@7.4.7': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/ws@8.18.1': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/xml2js@0.4.14': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/yargs-parser@21.0.3': {} @@ -24474,7 +25122,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 24.13.3 + '@types/node': 26.2.0 optional: true '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': @@ -24542,10 +25190,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.65.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.66.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@5.9.3) + '@typescript-eslint/types': 8.66.0 debug: 4.4.3(supports-color@8.1.1) typescript: 5.9.3 transitivePeerDependencies: @@ -24560,7 +25208,7 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.66.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 @@ -24590,7 +25238,7 @@ snapshots: '@typescript-eslint/types@8.62.1': {} - '@typescript-eslint/types@8.65.0': {} + '@typescript-eslint/types@8.66.0': {} '@typescript-eslint/typescript-estree@8.62.1(typescript@5.9.3)': dependencies: @@ -24607,12 +25255,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.66.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.65.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/project-service': 8.66.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@5.9.3) + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/visitor-keys': 8.66.0 debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.6 semver: 7.8.5 @@ -24649,9 +25297,9 @@ snapshots: '@typescript-eslint/types': 8.62.1 eslint-visitor-keys: 5.0.1 - '@typescript-eslint/visitor-keys@8.65.0': + '@typescript-eslint/visitor-keys@8.66.0': dependencies: - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/types': 8.66.0 eslint-visitor-keys: 5.0.1 '@typespec/ts-http-runtime@0.2.2': @@ -24670,7 +25318,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typespec/ts-http-runtime@0.3.7': + '@typespec/ts-http-runtime@0.3.8': dependencies: http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -24693,7 +25341,7 @@ snapshots: enhanced-resolve: 5.19.0 glob: 10.5.0 minimatch: 9.0.9 - mocha: 11.7.6 + mocha: 11.8.0 supports-color: 10.2.2 yargs: 17.7.2 transitivePeerDependencies: @@ -24786,16 +25434,16 @@ snapshots: '@vue/compiler-core@3.5.16': dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/shared': 3.5.16 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-core@3.5.40': + '@vue/compiler-core@3.5.41': dependencies: - '@babel/parser': 7.29.7 - '@vue/shared': 3.5.40 + '@babel/parser': 7.29.8 + '@vue/shared': 3.5.41 entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 @@ -24805,33 +25453,33 @@ snapshots: '@vue/compiler-core': 3.5.16 '@vue/shared': 3.5.16 - '@vue/compiler-dom@3.5.40': + '@vue/compiler-dom@3.5.41': dependencies: - '@vue/compiler-core': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/compiler-core': 3.5.41 + '@vue/shared': 3.5.41 '@vue/compiler-sfc@3.5.16': dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/compiler-core': 3.5.16 '@vue/compiler-dom': 3.5.16 '@vue/compiler-ssr': 3.5.16 '@vue/shared': 3.5.16 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.24 + postcss: 8.5.26 source-map-js: 1.2.1 - '@vue/compiler-sfc@3.5.40': + '@vue/compiler-sfc@3.5.41': dependencies: - '@babel/parser': 7.29.7 - '@vue/compiler-core': 3.5.40 - '@vue/compiler-dom': 3.5.40 - '@vue/compiler-ssr': 3.5.40 - '@vue/shared': 3.5.40 + '@babel/parser': 7.29.8 + '@vue/compiler-core': 3.5.41 + '@vue/compiler-dom': 3.5.41 + '@vue/compiler-ssr': 3.5.41 + '@vue/shared': 3.5.41 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.24 + postcss: 8.5.26 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.16': @@ -24839,10 +25487,10 @@ snapshots: '@vue/compiler-dom': 3.5.16 '@vue/shared': 3.5.16 - '@vue/compiler-ssr@3.5.40': + '@vue/compiler-ssr@3.5.41': dependencies: - '@vue/compiler-dom': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/compiler-dom': 3.5.41 + '@vue/shared': 3.5.41 '@vue/reactivity@3.5.16': dependencies: @@ -24868,7 +25516,7 @@ snapshots: '@vue/shared@3.5.16': {} - '@vue/shared@3.5.40': {} + '@vue/shared@3.5.41': {} '@web/browser-logs@0.4.1': dependencies: @@ -24903,11 +25551,11 @@ snapshots: '@web/dev-server-rollup@0.6.4': dependencies: - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.62.3) + '@rollup/plugin-node-resolve': 15.3.1(rollup@4.62.4) '@web/dev-server-core': 0.7.5 nanocolors: 0.2.13 parse5: 6.0.1 - rollup: 4.62.3 + rollup: 4.62.4 whatwg-url: 14.2.0 transitivePeerDependencies: - bufferutil @@ -24988,7 +25636,7 @@ snapshots: istanbul-reports: 3.2.0 log-update: 4.0.0 nanocolors: 0.2.13 - nanoid: 3.3.16 + nanoid: 3.3.18 open: 8.4.2 picomatch: 2.3.2 source-map: 0.7.6 @@ -25131,24 +25779,25 @@ snapshots: '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.105.0)': dependencies: - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.105.0)': dependencies: - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.6)(webpack@5.105.0)': dependencies: - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) optionalDependencies: webpack-dev-server: 5.2.6(debug@4.4.1(supports-color@8.1.1))(supports-color@8.1.1)(tslib@2.8.1)(webpack-cli@5.1.4)(webpack@5.105.0) '@xmldom/xmldom@0.8.13': {} - '@xmldom/xmldom@0.9.10': {} + '@xmldom/xmldom@0.9.10': + optional: true '@xtuc/ieee754@1.2.0': {} @@ -25249,14 +25898,14 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.4 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.4 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -25349,7 +25998,7 @@ snapshots: hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 jiti: 2.7.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 json5: 2.2.3 lazy-val: 1.0.5 minimatch: 10.2.6 @@ -25536,7 +26185,7 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 @@ -25567,7 +26216,7 @@ snapshots: babel-walk@3.0.0-canary-5: dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 badgen@3.3.2: {} @@ -25589,7 +26238,7 @@ snapshots: - react-native-b4a optional: true - bare-fs@4.7.4: + bare-fs@4.8.0: dependencies: bare-events: 2.9.1 bare-path: 3.0.0 @@ -25635,7 +26284,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.11.5: {} + baseline-browser-mapping@2.11.13: {} basic-ftp@5.3.0: {} @@ -25647,7 +26296,7 @@ snapshots: caseless: 0.12.0 is-stream: 2.0.1 - better-sqlite3@12.6.2: + better-sqlite3@12.8.0: dependencies: bindings: 1.5.0 prebuild-install: 7.1.3 @@ -25725,16 +26374,16 @@ snapshots: bowser@2.11.0: {} - brace-expansion@1.1.16: + brace-expansion@1.1.18: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.1.3: + brace-expansion@2.1.4: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.8: + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.3 @@ -25744,13 +26393,13 @@ snapshots: browser-stdout@1.3.1: {} - browserslist@4.28.7: + browserslist@4.28.8: dependencies: - baseline-browser-mapping: 2.11.5 - caniuse-lite: 1.0.30001806 - electron-to-chromium: 1.5.397 - node-releases: 2.0.51 - update-browserslist-db: 1.2.3(browserslist@4.28.7) + baseline-browser-mapping: 2.11.13 + caniuse-lite: 1.0.30001809 + electron-to-chromium: 1.5.403 + node-releases: 2.0.53 + update-browserslist-db: 1.3.0(browserslist@4.28.8) bs-logger@0.2.6: dependencies: @@ -25811,7 +26460,7 @@ snapshots: fs-extra: 10.1.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 - js-yaml: 4.3.0 + js-yaml: 4.3.1 sanitize-filename: 1.6.4 source-map-support: 0.5.21 stat-mode: 1.0.0 @@ -25893,7 +26542,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001806: {} + caniuse-lite@1.0.30001809: {} caseless@0.12.0: {} @@ -26001,7 +26650,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -26261,8 +26910,8 @@ snapshots: constantinople@4.0.1: dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 content-disposition@0.5.4: dependencies: @@ -26301,7 +26950,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 7.0.5 - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) copyfiles@2.4.1: dependencies: @@ -26339,7 +26988,7 @@ snapshots: cosmiconfig@8.3.6(typescript@5.4.5): dependencies: import-fresh: 3.3.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: @@ -26349,7 +26998,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 parse-json: 5.2.0 optionalDependencies: typescript: 5.4.5 @@ -26358,7 +27007,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 parse-json: 5.2.0 optionalDependencies: typescript: 5.9.3 @@ -26379,6 +27028,21 @@ snapshots: dependencies: buffer: 5.7.1 + create-jest@29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(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.40)(ts-node@10.9.2(@types/node@20.19.40)(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 @@ -26424,13 +27088,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + create-jest@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(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@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -26439,13 +27103,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + create-jest@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(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@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -26817,6 +27481,10 @@ snapshots: dependencies: character-entities: 2.0.2 + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -26933,11 +27601,11 @@ snapshots: dependencies: node-source-walk: 7.0.2 - detective-postcss@8.0.4(postcss@8.5.24): + detective-postcss@8.0.4(postcss@8.5.26): dependencies: is-url-superb: 4.0.0 - postcss: 8.5.24 - postcss-values-parser: 6.0.2(postcss@8.5.24) + postcss: 8.5.26 + postcss-values-parser: 6.0.2(postcss@8.5.26) detective-sass@6.0.2: dependencies: @@ -26953,7 +27621,7 @@ snapshots: detective-typescript@14.1.2(typescript@5.9.3): dependencies: - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.66.0(typescript@5.9.3) ast-module-types: 6.0.2 node-source-walk: 7.0.2 typescript: 5.9.3 @@ -26963,7 +27631,7 @@ snapshots: detective-vue2@2.3.0(typescript@5.9.3): dependencies: '@dependents/detective-less': 5.0.3 - '@vue/compiler-sfc': 3.5.40 + '@vue/compiler-sfc': 3.5.41 detective-es6: 5.0.2 detective-sass: 6.0.2 detective-scss: 5.0.2 @@ -27004,7 +27672,7 @@ snapshots: builder-util: 26.8.1 fs-extra: 10.1.0 iconv-lite: 0.6.3 - js-yaml: 4.3.0 + js-yaml: 4.3.1 optionalDependencies: dmg-license: 1.0.11 transitivePeerDependencies: @@ -27059,7 +27727,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.4.12: + dompurify@3.4.13: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -27154,13 +27822,13 @@ snapshots: transitivePeerDependencies: - supports-color - electron-to-chromium@1.5.397: {} + electron-to-chromium@1.5.403: {} electron-updater@6.6.2(supports-color@8.1.1): dependencies: builder-util-runtime: 9.3.1(supports-color@8.1.1) fs-extra: 10.1.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 lazy-val: 1.0.5 lodash.escaperegexp: 4.1.2 lodash.isequal: 4.5.0 @@ -27169,7 +27837,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron-vite@4.0.1(vite@6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)): + electron-vite@4.0.1(vite@6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0)): dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.7) @@ -27177,7 +27845,7 @@ snapshots: esbuild: 0.25.12 magic-string: 0.30.17 picocolors: 1.1.1 - vite: 6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0) + vite: 6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: - supports-color @@ -27193,11 +27861,11 @@ snapshots: transitivePeerDependencies: - supports-color - electron@40.8.5(supports-color@8.1.1): + electron@41.10.3(supports-color@8.1.1): dependencies: - '@electron/get': 2.0.3(supports-color@8.1.1) + '@electron-internal/extract-zip': 1.0.5 + '@electron/get': 5.1.0(supports-color@8.1.1) '@types/node': 24.13.3 - extract-zip: 2.0.1 transitivePeerDependencies: - supports-color @@ -27241,7 +27909,7 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 - enhanced-resolve@5.24.3: + enhanced-resolve@5.24.5: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 @@ -27256,6 +27924,8 @@ snapshots: env-paths@2.2.1: {} + env-paths@3.0.0: {} + envinfo@7.11.0: {} environment@1.1.0: {} @@ -27454,6 +28124,35 @@ snapshots: '@esbuild/win32-ia32': 0.28.1 '@esbuild/win32-x64': 0.28.1 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -27826,7 +28525,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -27865,7 +28564,7 @@ snapshots: dependencies: fastest-levenshtein: 1.0.16 - fast-uri@3.1.4: {} + fast-uri@3.1.5: {} fast-xml-builder@1.2.0: dependencies: @@ -27927,7 +28626,7 @@ snapshots: dependencies: app-module-path: 2.2.0 commander: 12.1.0 - enhanced-resolve: 5.24.3 + enhanced-resolve: 5.24.5 module-definition: 6.0.2 module-lookup-amd: 9.1.3 resolve: 1.22.12 @@ -28391,6 +29090,8 @@ snapshots: p-cancelable: 2.1.1 responselike: 2.0.1 + gpt-tokenizer@2.9.0: {} + graceful-fs@4.2.11: {} graphlib@2.1.8: @@ -28510,7 +29211,7 @@ snapshots: highlight.js@10.7.3: {} - hono@4.12.29: {} + hono@4.13.0: {} hosted-git-info@4.1.0: dependencies: @@ -28571,7 +29272,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) htmlparser2@10.0.0: dependencies: @@ -28800,7 +29501,7 @@ snapshots: type-fest: 4.41.0 widest-line: 5.0.0 wrap-ansi: 9.0.2 - ws: 8.21.1 + ws: 8.21.3 yoga-wasm-web: 0.3.3 optionalDependencies: '@types/react': 18.3.18 @@ -28831,6 +29532,8 @@ snapshots: ip-address@10.3.1: {} + ip-address@10.5.0: {} + ip-regex@4.3.0: {} ipaddr.js@1.9.1: {} @@ -29072,9 +29775,9 @@ snapshots: isobject@3.0.1: {} - isomorphic-ws@5.0.0(ws@8.21.1): + isomorphic-ws@5.0.0(ws@8.21.3): dependencies: - ws: 8.21.1 + ws: 8.21.3 isomorphic.js@0.2.5: {} @@ -29085,7 +29788,7 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -29095,7 +29798,7 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: '@babel/core': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 7.8.5 @@ -29165,7 +29868,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.0 @@ -29185,6 +29888,25 @@ snapshots: - babel-plugin-macros - supports-color + jest-cli@29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.40)(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.40)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.3 + 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)) @@ -29242,16 +29964,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + jest-cli@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.2.0)(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@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + create-jest: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.3 @@ -29261,16 +29983,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + jest-cli@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.2.0)(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@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + create-jest: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.3 @@ -29280,6 +30002,37 @@ snapshots: - supports-color - ts-node + jest-config@29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)): + dependencies: + '@babel/core': 7.29.7 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.7) + 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.40 + ts-node: 10.9.2(@types/node@20.19.40)(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.29.7 @@ -29373,7 +30126,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29399,12 +30152,43 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.20.1 - ts-node: 10.9.2(@types/node@26.1.2)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@26.2.0)(typescript@5.4.5) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)): + dependencies: + '@babel/core': 7.29.7 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.7) + 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': 26.2.0 + ts-node: 10.9.2(@types/node@20.19.40)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29429,13 +30213,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 ts-node: 10.9.2(@types/node@22.15.18)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29460,13 +30244,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 ts-node: 10.9.2(@types/node@22.19.19)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@22.20.1)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29491,13 +30275,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 ts-node: 10.9.2(@types/node@22.20.1)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -29522,8 +30306,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 26.1.2 - ts-node: 10.9.2(@types/node@26.1.2)(typescript@5.4.5) + '@types/node': 26.2.0 + ts-node: 10.9.2(@types/node@26.2.0)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -29567,7 +30351,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -29616,7 +30400,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -29651,7 +30435,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -29679,7 +30463,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -29700,10 +30484,10 @@ snapshots: jest-snapshot@29.7.0: dependencies: '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.7) '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.29.7) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 @@ -29744,7 +30528,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.1.2 + '@types/node': 26.2.0 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -29753,7 +30537,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.20.1 + '@types/node': 26.2.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -29764,6 +30548,18 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jest@29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.19.40)(ts-node@10.9.2(@types/node@20.19.40)(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)) @@ -29800,24 +30596,24 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + jest@29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest-cli: 29.7.0(@types/node@22.20.1)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)): + jest@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest-cli: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -29832,16 +30628,18 @@ snapshots: jose@6.2.3: {} + jose@6.2.8: {} + js-stringify@1.0.2: {} js-tokens@4.0.0: {} - js-yaml@3.15.0: + js-yaml@3.15.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - js-yaml@4.3.0: + js-yaml@4.3.1: dependencies: argparse: 2.0.1 @@ -29891,7 +30689,7 @@ snapshots: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.21.1 + ws: 8.21.3 xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -30524,7 +31322,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 - decode-named-character-reference: 1.1.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 micromark: 4.0.2(supports-color@8.1.1) @@ -30670,11 +31468,11 @@ snapshots: merge2@1.4.1: {} - mermaid@11.15.0: + mermaid@11.16.1: dependencies: '@braintree/sanitize-url': 7.1.2 '@iconify/utils': 3.1.3 - '@mermaid-js/parser': 1.1.1 + '@mermaid-js/parser': 1.2.0 '@types/d3': 7.4.3 '@upsetjs/venn.js': 2.0.0 cytoscape: 3.34.0 @@ -30684,7 +31482,7 @@ snapshots: d3-sankey: 0.12.3 dagre-d3-es: 7.0.14 dayjs: 1.11.20 - dompurify: 3.4.12 + dompurify: 3.4.13 es-toolkit: 1.46.1 katex: 0.16.47 khroma: 2.1.0 @@ -30945,31 +31743,31 @@ snapshots: minimatch@10.2.4: dependencies: - brace-expansion: 5.0.8 + brace-expansion: 5.0.9 minimatch@10.2.5: dependencies: - brace-expansion: 5.0.8 + brace-expansion: 5.0.9 minimatch@10.2.6: dependencies: - brace-expansion: 5.0.8 + brace-expansion: 5.0.9 minimatch@3.1.5: dependencies: - brace-expansion: 1.1.16 + brace-expansion: 1.1.18 minimatch@5.1.9: dependencies: - brace-expansion: 2.1.3 + brace-expansion: 2.1.4 minimatch@8.0.7: dependencies: - brace-expansion: 2.1.3 + brace-expansion: 2.1.4 minimatch@9.0.9: dependencies: - brace-expansion: 2.1.3 + brace-expansion: 2.1.4 minimist@1.2.8: {} @@ -31015,7 +31813,7 @@ snapshots: find-up: 5.0.0 glob: 8.1.0 he: 1.2.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 log-symbols: 4.1.0 minimatch: 5.1.9 ms: 2.1.3 @@ -31027,7 +31825,7 @@ snapshots: yargs-parser: 20.2.9 yargs-unparser: 2.0.0 - mocha@11.7.6: + mocha@11.8.0: dependencies: browser-stdout: 1.3.1 chokidar: 4.0.3 @@ -31038,12 +31836,12 @@ snapshots: glob: 10.5.0 he: 1.2.0 is-path-inside: 3.0.3 - js-yaml: 4.3.0 + js-yaml: 4.3.1 log-symbols: 4.1.0 minimatch: 9.0.9 ms: 2.1.3 picocolors: 1.1.1 - serialize-javascript: 7.0.7 + serialize-javascript: 7.1.0 strip-json-comments: 3.1.1 supports-color: 8.1.1 workerpool: 9.3.4 @@ -31104,9 +31902,11 @@ snapshots: nanocolors@0.2.13: {} - nanoid@3.3.16: {} + nanoid@3.3.17: {} - nanoid@5.1.5: {} + nanoid@3.3.18: {} + + nanoid@5.1.16: {} napi-build-utils@2.0.0: {} @@ -31148,7 +31948,7 @@ snapshots: node-abi@4.33.0: dependencies: - semver: 7.8.5 + semver: 7.7.4 node-addon-api@1.7.2: optional: true @@ -31159,7 +31959,7 @@ snapshots: node-api-version@0.2.1: dependencies: - semver: 7.8.5 + semver: 7.7.4 node-domexception@1.0.0: {} @@ -31188,7 +31988,7 @@ snapshots: graceful-fs: 4.2.11 nopt: 9.0.0 proc-log: 6.1.0 - semver: 7.8.5 + semver: 7.7.4 tar: 7.5.22 tinyglobby: 0.2.17 undici: 6.28.0 @@ -31200,7 +32000,7 @@ snapshots: dependencies: node-addon-api: 7.1.1 - node-releases@2.0.51: {} + node-releases@2.0.53: {} node-rsa@1.1.1: dependencies: @@ -31218,7 +32018,7 @@ snapshots: node-source-walk@7.0.2: dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 nodemailer@8.0.4: {} @@ -31346,7 +32146,7 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openai@4.103.0(encoding@0.1.13)(ws@8.21.1)(zod@4.3.6): + openai@4.103.0(encoding@0.1.13)(ws@8.21.3)(zod@4.3.6): dependencies: '@types/node': 18.19.130 '@types/node-fetch': 2.6.12 @@ -31356,14 +32156,14 @@ snapshots: formdata-node: 4.4.1 node-fetch: 2.7.0(encoding@0.1.13) optionalDependencies: - ws: 8.21.1 + ws: 8.21.3 zod: 4.3.6 transitivePeerDependencies: - encoding - openai@6.41.0(ws@8.21.1)(zod@3.25.76): + openai@6.41.0(ws@8.21.3)(zod@3.25.76): optionalDependencies: - ws: 8.21.1 + ws: 8.21.3 zod: 3.25.76 optionator@0.9.4: @@ -31723,6 +32523,7 @@ snapshots: '@xmldom/xmldom': 0.9.10 base64-js: 1.5.1 xmlbuilder: 15.1.1 + optional: true pluralize@2.0.0: {} @@ -31744,16 +32545,22 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-values-parser@6.0.2(postcss@8.5.24): + postcss-values-parser@6.0.2(postcss@8.5.26): dependencies: color-name: 1.1.4 is-url-superb: 4.0.0 - postcss: 8.5.24 + postcss: 8.5.26 quote-unquote: 1.0.0 postcss@8.5.24: dependencies: - nanoid: 3.3.16 + nanoid: 3.3.17 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -31783,7 +32590,7 @@ snapshots: detective-amd: 6.1.0 detective-cjs: 6.1.1 detective-es6: 5.0.2 - detective-postcss: 8.0.4(postcss@8.5.24) + detective-postcss: 8.0.4(postcss@8.5.26) detective-sass: 6.0.2 detective-scss: 5.0.2 detective-stylus: 5.0.1 @@ -31791,7 +32598,7 @@ snapshots: detective-vue2: 2.3.0(typescript@5.9.3) module-definition: 6.0.2 node-source-walk: 7.0.2 - postcss: 8.5.24 + postcss: 8.5.26 typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -31947,7 +32754,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.1 - '@types/node': 26.1.2 + '@types/node': 26.2.0 long: 5.3.2 optional: true @@ -32068,7 +32875,7 @@ snapshots: debug: 4.4.3(supports-color@8.1.1) devtools-protocol: 0.0.1367902 typed-query-selector: 2.12.2 - ws: 8.21.1 + ws: 8.21.3 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -32085,7 +32892,7 @@ snapshots: devtools-protocol: 0.0.1566079 typed-query-selector: 2.12.2 webdriver-bidi-protocol: 0.4.1 - ws: 8.21.1 + ws: 8.21.3 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -32310,7 +33117,7 @@ snapshots: rc-config-loader@4.1.3: dependencies: debug: 4.4.1(supports-color@8.1.1) - js-yaml: 4.3.0 + js-yaml: 4.3.1 json5: 2.2.3 require-from-string: 2.0.2 transitivePeerDependencies: @@ -32650,35 +33457,36 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.62.2 fsevents: 2.3.3 - rollup@4.62.3: + rollup@4.62.4: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.3 - '@rollup/rollup-android-arm64': 4.62.3 - '@rollup/rollup-darwin-arm64': 4.62.3 - '@rollup/rollup-darwin-x64': 4.62.3 - '@rollup/rollup-freebsd-arm64': 4.62.3 - '@rollup/rollup-freebsd-x64': 4.62.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.3 - '@rollup/rollup-linux-arm-musleabihf': 4.62.3 - '@rollup/rollup-linux-arm64-gnu': 4.62.3 - '@rollup/rollup-linux-arm64-musl': 4.62.3 - '@rollup/rollup-linux-loong64-gnu': 4.62.3 - '@rollup/rollup-linux-loong64-musl': 4.62.3 - '@rollup/rollup-linux-ppc64-gnu': 4.62.3 - '@rollup/rollup-linux-ppc64-musl': 4.62.3 - '@rollup/rollup-linux-riscv64-gnu': 4.62.3 - '@rollup/rollup-linux-riscv64-musl': 4.62.3 - '@rollup/rollup-linux-s390x-gnu': 4.62.3 - '@rollup/rollup-linux-x64-gnu': 4.62.3 - '@rollup/rollup-linux-x64-musl': 4.62.3 - '@rollup/rollup-openbsd-x64': 4.62.3 - '@rollup/rollup-openharmony-arm64': 4.62.3 - '@rollup/rollup-win32-arm64-msvc': 4.62.3 - '@rollup/rollup-win32-ia32-msvc': 4.62.3 - '@rollup/rollup-win32-x64-gnu': 4.62.3 - '@rollup/rollup-win32-x64-msvc': 4.62.3 + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.62.4 + '@rollup/rollup-android-arm64': 4.62.4 + '@rollup/rollup-darwin-arm64': 4.62.4 + '@rollup/rollup-darwin-x64': 4.62.4 + '@rollup/rollup-freebsd-arm64': 4.62.4 + '@rollup/rollup-freebsd-x64': 4.62.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.4 + '@rollup/rollup-linux-arm-musleabihf': 4.62.4 + '@rollup/rollup-linux-arm64-gnu': 4.62.4 + '@rollup/rollup-linux-arm64-musl': 4.62.4 + '@rollup/rollup-linux-loong64-gnu': 4.62.4 + '@rollup/rollup-linux-loong64-musl': 4.62.4 + '@rollup/rollup-linux-ppc64-gnu': 4.62.4 + '@rollup/rollup-linux-ppc64-musl': 4.62.4 + '@rollup/rollup-linux-riscv64-gnu': 4.62.4 + '@rollup/rollup-linux-riscv64-musl': 4.62.4 + '@rollup/rollup-linux-s390x-gnu': 4.62.4 + '@rollup/rollup-linux-x64-gnu': 4.62.4 + '@rollup/rollup-linux-x64-musl': 4.62.4 + '@rollup/rollup-openbsd-x64': 4.62.4 + '@rollup/rollup-openharmony-arm64': 4.62.4 + '@rollup/rollup-win32-arm64-msvc': 4.62.4 + '@rollup/rollup-win32-ia32-msvc': 4.62.4 + '@rollup/rollup-win32-x64-gnu': 4.62.4 + '@rollup/rollup-win32-x64-msvc': 4.62.4 fsevents: 2.3.3 rope-sequence@1.3.4: {} @@ -32750,7 +33558,7 @@ snapshots: sass-lookup@6.1.2: dependencies: commander: 12.1.0 - enhanced-resolve: 5.24.3 + enhanced-resolve: 5.24.5 sax@1.3.0: {} @@ -32909,7 +33717,7 @@ snapshots: serialize-javascript@7.0.5: {} - serialize-javascript@7.0.7: {} + serialize-javascript@7.1.0: {} serve-index@1.9.2: dependencies: @@ -33187,7 +33995,7 @@ snapshots: socks@2.8.7: dependencies: - ip-address: 10.3.1 + ip-address: 10.5.0 smart-buffer: 4.2.0 sort-object-keys@1.1.3: {} @@ -33521,7 +34329,7 @@ snapshots: pump: 3.0.4 tar-stream: 3.2.0 optionalDependencies: - bare-fs: 4.7.4 + bare-fs: 4.8.0 bare-path: 3.1.1 transitivePeerDependencies: - bare-abort-controller @@ -33547,7 +34355,7 @@ snapshots: tar-stream@3.2.0: dependencies: b4a: 1.8.1 - bare-fs: 4.7.4 + bare-fs: 4.8.0 fast-fifo: 1.3.2 streamx: 2.28.0 transitivePeerDependencies: @@ -33585,27 +34393,27 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser-webpack-plugin@5.6.1(esbuild@0.28.1)(postcss@8.5.24)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.24)): + terser-webpack-plugin@5.6.1(esbuild@0.28.1)(postcss@8.5.26)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.26)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 - terser: 5.49.0 - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24) + terser: 5.49.2 + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26) optionalDependencies: esbuild: 0.28.1 - postcss: 8.5.24 + postcss: 8.5.26 - terser-webpack-plugin@5.6.1(esbuild@0.28.1)(postcss@8.5.24)(webpack@5.105.0): + terser-webpack-plugin@5.6.1(esbuild@0.28.1)(postcss@8.5.26)(webpack@5.105.0): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 - terser: 5.49.0 - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + terser: 5.49.2 + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) optionalDependencies: esbuild: 0.28.1 - postcss: 8.5.24 + postcss: 8.5.26 terser@5.27.0: dependencies: @@ -33614,7 +34422,7 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - terser@5.49.0: + terser@5.49.2: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.18.0 @@ -33813,12 +34621,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.29.7) esbuild: 0.28.1 - ts-jest@29.3.3(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest@29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)))(typescript@5.4.5): + ts-jest@29.3.3(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest@29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)))(typescript@5.4.5): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@26.1.2)(ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5)) + jest: 29.7.0(@types/node@26.2.0)(ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -33855,7 +34663,7 @@ snapshots: esbuild: 0.28.1 jest-util: 29.7.0 - ts-loader@9.5.2(typescript@5.4.5)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.24)): + ts-loader@9.5.2(typescript@5.4.5)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.26)): dependencies: chalk: 4.1.2 enhanced-resolve: 5.15.0 @@ -33863,7 +34671,7 @@ snapshots: semver: 7.5.4 source-map: 0.7.4 typescript: 5.4.5 - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26) ts-loader@9.5.2(typescript@5.4.5)(webpack@5.105.0): dependencies: @@ -33873,7 +34681,26 @@ snapshots: semver: 7.5.4 source-map: 0.7.4 typescript: 5.4.5 - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) + + ts-node@10.9.2(@types/node@20.19.40)(typescript@5.4.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.12 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.19.40 + acorn: 8.18.0 + acorn-walk: 8.3.5 + 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 + optional: true ts-node@10.9.2(@types/node@22.15.18)(typescript@5.4.5): dependencies: @@ -33931,14 +34758,14 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - ts-node@10.9.2(@types/node@26.1.2)(typescript@5.4.5): + ts-node@10.9.2(@types/node@26.2.0)(typescript@5.4.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 26.1.2 + '@types/node': 26.2.0 acorn: 8.18.0 acorn-walk: 8.3.5 arg: 4.1.3 @@ -34212,9 +35039,9 @@ snapshots: untildify@4.0.0: {} - update-browserslist-db@1.2.3(browserslist@4.28.7): + update-browserslist-db@1.3.0(browserslist@4.28.8): dependencies: - browserslist: 4.28.7 + browserslist: 4.28.8 escalade: 3.2.0 picocolors: 1.1.1 @@ -34291,7 +35118,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite@6.4.3(@types/node@22.15.18)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.8.3): + vite@6.4.3(@types/node@22.15.18)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.8.3): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.5) @@ -34304,11 +35131,11 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 less: 4.3.0 - terser: 5.49.0 + terser: 5.49.2 tsx: 4.21.0 yaml: 2.8.3 - vite@6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0): + vite@6.4.3(@types/node@22.20.1)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.5) @@ -34321,11 +35148,11 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 less: 4.3.0 - terser: 5.49.0 + terser: 5.49.2 tsx: 4.21.0 yaml: 2.9.0 - vite@6.4.3(@types/node@26.1.2)(jiti@2.7.0)(less@4.3.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0): + vite@6.4.3(@types/node@26.2.0)(jiti@2.7.0)(less@4.3.0)(terser@5.49.2)(tsx@4.21.0)(yaml@2.9.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.5) @@ -34334,11 +35161,11 @@ snapshots: rollup: 4.62.2 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 fsevents: 2.3.3 jiti: 2.7.0 less: 4.3.0 - terser: 5.49.0 + terser: 5.49.2 tsx: 4.21.0 yaml: 2.9.0 @@ -34431,7 +35258,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-merge: 5.10.0 optionalDependencies: webpack-dev-server: 5.2.6(debug@4.4.1(supports-color@8.1.1))(supports-color@8.1.1)(tslib@2.8.1)(webpack-cli@5.1.4)(webpack@5.105.0) @@ -34445,7 +35272,7 @@ snapshots: range-parser: 1.3.0 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) transitivePeerDependencies: - tslib @@ -34478,9 +35305,9 @@ snapshots: sockjs: 0.3.24 spdy: 4.0.2(supports-color@8.1.1) webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.0) - ws: 8.21.1 + ws: 8.21.3 optionalDependencies: - webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.6)(webpack@5.105.0) transitivePeerDependencies: - bufferutil @@ -34497,7 +35324,7 @@ snapshots: webpack-sources@3.5.1: {} - webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.24): + webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.26): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.9 @@ -34507,9 +35334,9 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.18.0 acorn-import-phases: 1.0.4(acorn@8.18.0) - browserslist: 4.28.7 + browserslist: 4.28.8 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.24.3 + enhanced-resolve: 5.24.5 es-module-lexer: 2.3.1 eslint-scope: 5.1.1 events: 3.3.0 @@ -34521,7 +35348,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 - terser-webpack-plugin: 5.6.1(esbuild@0.28.1)(postcss@8.5.24)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.24)) + terser-webpack-plugin: 5.6.1(esbuild@0.28.1)(postcss@8.5.26)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.26)) watchpack: 2.5.2 webpack-sources: 3.5.1 transitivePeerDependencies: @@ -34538,7 +35365,7 @@ snapshots: - postcss - uglify-js - webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.24)(webpack-cli@5.1.4): + webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.26)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.9 @@ -34548,9 +35375,9 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.18.0 acorn-import-phases: 1.0.4(acorn@8.18.0) - browserslist: 4.28.7 + browserslist: 4.28.8 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.24.3 + enhanced-resolve: 5.24.5 es-module-lexer: 2.3.1 eslint-scope: 5.1.1 events: 3.3.0 @@ -34562,7 +35389,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 - terser-webpack-plugin: 5.6.1(esbuild@0.28.1)(postcss@8.5.24)(webpack@5.105.0) + terser-webpack-plugin: 5.6.1(esbuild@0.28.1)(postcss@8.5.26)(webpack@5.105.0) watchpack: 2.5.2 webpack-sources: 3.5.1 optionalDependencies: @@ -34704,8 +35531,8 @@ snapshots: with@7.0.2: dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 assert-never: 1.4.0 babel-walk: 3.0.0-canary-5 @@ -34752,7 +35579,7 @@ snapshots: ws@7.5.13: {} - ws@8.21.1: {} + ws@8.21.3: {} wsl-utils@0.1.0: dependencies: @@ -34786,7 +35613,7 @@ snapshots: '@oozcitak/dom': 2.0.2 '@oozcitak/infra': 2.0.2 '@oozcitak/util': 10.0.0 - js-yaml: 4.3.0 + js-yaml: 4.3.1 xmlbuilder@11.0.1: {} From 2648d43352b15d70e5e2347ec137ba9636708ad4 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 18:39:55 -0700 Subject: [PATCH 14/22] Fix build break and correctness issues in command/action parity Build (agent-dispatcher failed to compile): - Extract the duplicated opt() helper into actionParams.ts and make it generic so spread results match the command flag value types. - Add actionParams(), which reads parameters off an action union. Members without parameters and members whose parameters is optional both yield {}, fixing the type error and the TypeError thrown when the translator omits parameters (e.g. 'show help', 'list constructions'). - Cast in the exhaustive default branches so actionName resolves on never. Correctness: - dispatcher.diagnostics is no longer injected, so the open-ended dispatchRequest action is not added to every translation prompt. - toggleAgent repeats --off per agent name; the parser takes one token per flag occurrence, so '--off a b' disabled a and enabled b. - powershell: strip fallbackToReasoning on the command path, which has no reasoning retry and so displayed nothing on failure. - powershell: invalid flowParametersJson now fails instead of silently running the flow with defaults. - powershell: use the session store, not the module-global one. - browser: surface action errors as ActionResult errors instead of console.error, which never reached the user. - browser: '@browser learn ' needs implicitQuotes to accept a multi-word goal. - greeting: drop the internal mock flag from the LLM-facing schema and guard the empty possibleGreetings case that threw in randomInt. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/agent/browserActionHandler.mts | 15 ++++---- .../greeting/src/greetingActionSchema.ts | 2 - .../greeting/src/greetingCommandHandler.ts | 37 +++++++++---------- .../greeting/test/greetingAction.spec.ts | 32 ++++++++++------ .../agents/powershell/src/actionHandler.mts | 24 +++++++++--- .../src/context/dispatcher/dispatcherAgent.ts | 7 +++- .../src/context/system/action/actionParams.ts | 16 ++++++++ .../system/action/collisionActionHandler.ts | 6 +-- .../system/action/configActionHandler.ts | 16 +++++--- .../action/constructionActionHandler.ts | 10 ++--- .../system/action/feedbackActionHandler.ts | 12 +++--- .../system/action/grammarActionHandler.ts | 13 +++---- .../action/systemOperationsActionHandler.ts | 10 ++--- 13 files changed, 112 insertions(+), 88 deletions(-) create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts diff --git a/ts/packages/agents/browser/src/agent/browserActionHandler.mts b/ts/packages/agents/browser/src/agent/browserActionHandler.mts index 2e4739be39..45811f51f1 100644 --- a/ts/packages/agents/browser/src/agent/browserActionHandler.mts +++ b/ts/packages/agents/browser/src/agent/browserActionHandler.mts @@ -2398,14 +2398,14 @@ Select actions to create as WebFlows:`; schemaName, ); } catch (ex: any) { - if (ex instanceof Error) { - console.error(ex); - } else { - console.error(JSON.stringify(ex)); - } + const message = + ex instanceof Error ? ex.message : JSON.stringify(ex); + return createActionResultFromError( + `Browser action '${action.actionName}' failed: ${message}`, + ); } } else { - console.error("No browser control available."); + return createActionResultFromError("No browser control available."); } return undefined; } @@ -3305,8 +3305,7 @@ class LearnHandler implements CommandHandler { goal: { description: "The goal to accomplish (what the action should do)", - type: "string" as const, - required: true, + implicitQuotes: true, }, }, }; diff --git a/ts/packages/agents/greeting/src/greetingActionSchema.ts b/ts/packages/agents/greeting/src/greetingActionSchema.ts index ce4b28b47f..c37b8b51d5 100644 --- a/ts/packages/agents/greeting/src/greetingActionSchema.ts +++ b/ts/packages/agents/greeting/src/greetingActionSchema.ts @@ -13,8 +13,6 @@ export type GreetingAction = PersonalizedGreetingAction; export interface PersonalizedGreetingAction { actionName: "personalizedGreetingAction"; parameters: { - // Set true only when the caller requests the deterministic mock greeting. - mock?: boolean; // the original request/greeting from the user originalRequest: string; // a set possible generic greeting responses to the user diff --git a/ts/packages/agents/greeting/src/greetingCommandHandler.ts b/ts/packages/agents/greeting/src/greetingCommandHandler.ts index 439d463830..f8b136954f 100644 --- a/ts/packages/agents/greeting/src/greetingCommandHandler.ts +++ b/ts/packages/agents/greeting/src/greetingCommandHandler.ts @@ -119,6 +119,12 @@ export interface GenericGreeting { `; +/** + * Deterministic greeting used by `@greeting --mock`. Kept out of the action + * schema so the translator can't select it in place of a real greeting. + */ +export const MOCK_GREETING = "Hello. How can I help you today?"; + /** * Implements the @greeting command. */ @@ -146,18 +152,9 @@ export class GreetingCommandHandler implements CommandHandler { params: ParsedCommandParams, ): Promise { if (params.flags.mock) { - const result = (await executeGreetingAction( - { - schemaName: "greeting", - actionName: "personalizedGreetingAction", - parameters: { - mock: true, - originalRequest: "@greeting --mock", - possibleGreetings: [], - }, - }, - context, - )) as ActionResultSuccess; + const result = createActionResult( + MOCK_GREETING, + ) as ActionResultSuccess; return { ...result, tokenUsage: { @@ -326,10 +323,6 @@ async function handlePersonalizedGreetingAction( greetingAction: PersonalizedGreetingAction, context: ActionContext, ): Promise { - if (greetingAction.parameters.mock === true) { - return createActionResult("Hello. How can I help you today?"); - } - let result = createActionResult("Hi!", true, undefined); if (greetingAction.parameters !== undefined) { const count = greetingAction.parameters.possibleGreetings.length; @@ -351,10 +344,14 @@ async function handlePersonalizedGreetingAction( // } // } else if (index == 0) { - result = createActionResult( - greetingAction.parameters.possibleGreetings[randomInt(0, count)] - .generatedGreeting, - ); + // randomInt throws when max === min, so an empty list keeps the "Hi!" + // fallback above. + if (count > 0) { + result = createActionResult( + greetingAction.parameters.possibleGreetings[randomInt(0, count)] + .generatedGreeting, + ); + } // } else { // result = createActionResult( // greetingAction.parameters.possibleGreetings[randomInt(0, count)] diff --git a/ts/packages/agents/greeting/test/greetingAction.spec.ts b/ts/packages/agents/greeting/test/greetingAction.spec.ts index 0e9b9d9257..486c4f39a6 100644 --- a/ts/packages/agents/greeting/test/greetingAction.spec.ts +++ b/ts/packages/agents/greeting/test/greetingAction.spec.ts @@ -12,19 +12,20 @@ import type { const here = path.dirname(fileURLToPath(import.meta.url)); const packageRoot = path.resolve(here, "..", ".."); -const { instantiate } = await import( +const { instantiate, MOCK_GREETING } = await import( pathToFileURL(path.join(packageRoot, "dist", "greetingCommandHandler.js")) .href ); -function mockAction() { +function greetingAction(greetings: string[]) { return { schemaName: "greeting", actionName: "personalizedGreetingAction", parameters: { - mock: true, originalRequest: "hello", - possibleGreetings: [], + possibleGreetings: greetings.map((generatedGreeting) => ({ + generatedGreeting, + })), }, } as any; } @@ -34,11 +35,21 @@ describe("greeting action parity", () => { const agent = instantiate(); assert.equal(typeof agent.executeAction, "function"); - const result = await agent.executeAction!(mockAction(), {} as any); - assert.equal( - (result as any).displayContent, - "Hello. How can I help you today?", + const result = await agent.executeAction!( + greetingAction(["Top of the morning!"]), + {} as any, + ); + assert.equal((result as any).displayContent, "Top of the morning!"); + }); + + it("falls back instead of throwing when no greetings were generated", async () => { + const agent = instantiate(); + + const result = await agent.executeAction!( + greetingAction([]), + {} as any, ); + assert.equal((result as any).displayContent.content, "Hi!"); }); it("links the bare command default to personalizedGreetingAction", async () => { @@ -66,10 +77,7 @@ describe("greeting action parity", () => { flags: { mock: true }, }); - assert.equal( - result.displayContent, - "Hello. How can I help you today?", - ); + assert.equal(result.displayContent, MOCK_GREETING); assert.deepEqual(result.tokenUsage, { prompt_tokens: 0, completion_tokens: 0, diff --git a/ts/packages/agents/powershell/src/actionHandler.mts b/ts/packages/agents/powershell/src/actionHandler.mts index cae5cb4b4b..7727bddb23 100644 --- a/ts/packages/agents/powershell/src/actionHandler.mts +++ b/ts/packages/agents/powershell/src/actionHandler.mts @@ -1196,9 +1196,10 @@ async function handlePowerShellFlowAction( if (flowParamsJson) { try { namedParams = JSON.parse(flowParamsJson); - } catch { - debug( - `Failed to parse flowParametersJson: ${flowParamsJson}`, + } catch (e: any) { + return createPowerShellFailure( + "invalidParameters", + `Invalid JSON in flowParametersJson: ${e.message}`, ); } } @@ -1408,12 +1409,23 @@ async function handlePowerShellFlowAction( let _agentStore: PowerShellStore | undefined; -function executeBuiltInPowerShellAction( +async function executeBuiltInPowerShellAction( action: { actionName: string; parameters?: Record }, context: ActionContext, ): Promise { - (context as any).__store = _agentStore; - return handlePowerShellFlowAction(action, context); + (context as any).__store = + context.sessionContext.agentContext.store ?? _agentStore; + const result = await handlePowerShellFlowAction(action, context); + // Only the natural-language request pipeline retries with reasoning, and + // the dispatcher skips error display when fallbackToReasoning is set. This + // is the command path, so leaving the flag on makes failures silent. + if ("fallbackToReasoning" in result && result.fallbackToReasoning) { + const { fallbackToReasoning, ...rest } = result as ActionResult & { + fallbackToReasoning?: boolean; + }; + return rest; + } + return result; } class ImportScriptHandler implements CommandHandler { diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts index 6975173146..c26de75fdd 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts @@ -568,7 +568,12 @@ export const dispatcherManifest: AppAgentManifest = { schemaFile: "./src/context/dispatcher/schema/diagnosticsActionSchema.ts", schemaType: "DispatcherDiagnosticsActions", - injected: true, + // Not injected: these are explicit diagnostics reached by + // schema switching. Injecting them puts the open-ended + // dispatchRequest action in every translation prompt, where it + // competes with real agent actions and can re-enter the + // dispatcher pipeline on itself. + injected: false, cached: false, }, }, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts new file mode 100644 index 0000000000..9f32c40090 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ +export function opt(value: T | undefined, key: string): Record { + return value !== undefined ? { [key]: value } : {}; +} + +// Reads `parameters` off an action union. Action schemas mix members that have +// no `parameters` at all with members whose `parameters` is optional, so a +// direct `action.parameters` doesn't type check and throws at runtime when the +// translator omits it. Returning `{}` for both cases lets each switch case read +// its fields and fall back to the command's default. +export function actionParams(action: { actionName: string }): any { + return (action as { parameters?: any }).parameters ?? {}; +} diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts index 3795f102c5..7738dd77c9 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts @@ -13,16 +13,12 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { CollisionAction } from "../schema/collisionActionSchema.js"; +import { opt } from "./actionParams.js"; function csv(values: string[] | undefined): string | undefined { return values?.join(","); } -/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ -function opt(value: unknown, key: string): Record { - return value !== undefined ? { [key]: value } : {}; -} - type Executor = ( commands: string[], params?: ParsedCommandParams, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts index 970d6ed726..12ae3f9021 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts @@ -212,17 +212,21 @@ export async function executeConfigAction( context.sessionContext.agentContext, ); break; - case "toggleAgent": - const cmdParam: string = configAction.parameters.enable - ? `` - : `--off`; + case "toggleAgent": { + const { enable, agentNames } = configAction.parameters; + // `off` is a multi-valued flag, but the parser consumes exactly one + // token per occurrence, so it has to be repeated per agent name. + // Passing `--off a b` would disable `a` and *enable* `b`. + const agentArgs = enable + ? agentNames.join(" ") + : agentNames.map((name) => `--off ${name}`).join(" "); await processCommand( - `@config agent ${cmdParam} ${configAction.parameters.agentNames.join(" ")}`, + `@config agent ${agentArgs}`, context.sessionContext.agentContext, ); break; - + } case "toggleExplanation": await processCommand( `@config explainer ${configAction.parameters.enable ? "on" : "off"}`, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts index 25aa56d6a7..799b28511d 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts @@ -13,11 +13,7 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConstructionAction } from "../schema/constructionActionSchema.js"; - -/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ -function opt(value: unknown, key: string): Record { - return value !== undefined ? { [key]: value } : {}; -} +import { actionParams, opt } from "./actionParams.js"; const STORE_CMDS: Record = { newConstructionStore: "new", @@ -48,7 +44,7 @@ export function executeConstructionAction( executeCommandFromHandlers(handlers, commands, params, context); const toggle = (commands: string[], enabled: boolean) => execute([...commands, enabled ? "on" : "off"]); - const p: any = action.parameters; + const p = actionParams(action); if (action.actionName in STORE_CMDS) { return executeConstructionStoreAction(action.actionName, p, execute); @@ -95,7 +91,7 @@ export function executeConstructionAction( return toggle(["wildcard", "entity"], p.enabled); default: throw new Error( - `Unknown construction action: ${action.actionName}`, + `Unknown construction action: ${(action as ConstructionAction).actionName}`, ); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts index aca8447479..ae9d5f039d 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts @@ -12,11 +12,7 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { FeedbackAction } from "../schema/feedbackActionSchema.js"; - -/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ -function opt(value: unknown, key: string): Record { - return value !== undefined ? { [key]: value } : {}; -} +import { actionParams, opt } from "./actionParams.js"; export function executeFeedbackAction( action: TypeAgentAction, @@ -25,7 +21,7 @@ export function executeFeedbackAction( ): Promise { const execute = (commands: string[], params?: any) => executeCommandFromHandlers(handlers, commands, params, context); - const p: any = action.parameters; + const p = actionParams(action); switch (action.actionName) { case "listFeedback": @@ -64,6 +60,8 @@ export function executeFeedbackAction( case "countFeedback": return execute(["count"], undefined); default: - throw new Error(`Unknown feedback action: ${action.actionName}`); + throw new Error( + `Unknown feedback action: ${(action as FeedbackAction).actionName}`, + ); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts index a744f5fb38..7c3e060c08 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts @@ -16,15 +16,14 @@ import { } from "@typeagent/agent-sdk/helpers/action"; import { StoredGrammarRule } from "@typeagent/action-grammar"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; -import { GrammarAction } from "../schema/grammarActionSchema.js"; - -/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ -function opt(value: unknown, key: string): Record { - return value !== undefined ? { [key]: value } : {}; -} +import { + GrammarAction, + ScanGrammarCollisionsAction, +} from "../schema/grammarActionSchema.js"; +import { opt } from "./actionParams.js"; function executeScanGrammarCollisionsAction( - action: TypeAgentAction, + action: TypeAgentAction, context: ActionContext, systemHandlers: CommandHandlerTable, ): Promise { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts index 58385d61e3..d19c208d87 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts @@ -13,11 +13,7 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { SystemOperationsAction } from "../schema/systemOperationsActionSchema.js"; - -/** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ -function opt(value: unknown, key: string): Record { - return value !== undefined ? { [key]: value } : {}; -} +import { actionParams, opt } from "./actionParams.js"; export function executeSystemOperationsAction( action: TypeAgentAction, @@ -26,7 +22,7 @@ export function executeSystemOperationsAction( ): Promise { const execute = (commands: string[], params?: ParsedCommandParams) => executeCommandFromHandlers(systemHandlers, commands, params, context); - const p: any = action.parameters; + const p = actionParams(action); switch (action.actionName) { case "executeTypedAction": { @@ -95,7 +91,7 @@ export function executeSystemOperationsAction( } as unknown as ParsedCommandParams); default: throw new Error( - `Unknown system operations action: ${action.actionName}`, + `Unknown system operations action: ${(action as SystemOperationsAction).actionName}`, ); } } From 293619a118eba9d9fa7cb5cb565a77cc2a4a10db Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 18:54:50 -0700 Subject: [PATCH 15/22] Regenerate v5 built-in construction cache for the new player actions The PR adds loadSpotifyUserData, spotifyLogin, and spotifyLogout to playerSchema.ts, which changes the player schema hash and leaves the prebuilt v5 construction cache stale. builtinConstructions.spec.ts fails on the stale hash until the cache is regenerated. Regenerated with: pnpm cli data regenerate -b v5 --constructions --updateHash Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../defaultAgentProvider/data/explainer/v5/constructions.json | 2 +- .../data/explainer/v5/data/player/basic.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ts/packages/defaultAgentProvider/data/explainer/v5/constructions.json b/ts/packages/defaultAgentProvider/data/explainer/v5/constructions.json index d5b0f4735b..f85964dfdf 100644 --- a/ts/packages/defaultAgentProvider/data/explainer/v5/constructions.json +++ b/ts/packages/defaultAgentProvider/data/explainer/v5/constructions.json @@ -145,7 +145,7 @@ ], "constructionNamespaces": [ { - "name": "player,q17vir5bvUtULvhlqc2dq3KkOCusaWxekl/G7VobtTY=,", + "name": "player,9qZSs8xYE9na79YoZ6FSjHBJ9MTu/7oRF6OnToHb/vg=,", "constructions": [ { "parts": [ diff --git a/ts/packages/defaultAgentProvider/data/explainer/v5/data/player/basic.json b/ts/packages/defaultAgentProvider/data/explainer/v5/data/player/basic.json index 3693014186..ea1890618e 100644 --- a/ts/packages/defaultAgentProvider/data/explainer/v5/data/player/basic.json +++ b/ts/packages/defaultAgentProvider/data/explainer/v5/data/player/basic.json @@ -1,7 +1,7 @@ { "version": 2, "schemaName": "player", - "sourceHash": "q17vir5bvUtULvhlqc2dq3KkOCusaWxekl/G7VobtTY=", + "sourceHash": "9qZSs8xYE9na79YoZ6FSjHBJ9MTu/7oRF6OnToHb/vg=", "explainerName": "v5", "entries": [ { From 2051206ca71950c19056d58f4477a9563fb950b7 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 18:57:33 -0700 Subject: [PATCH 16/22] Give the command/action coverage gate a floor The coverage assertions are all 'the set of gaps is empty', which stays true when a host drops out of the enumeration entirely. An agent that fails to load is skipped silently by collectCommandsFromContext, so losing all 31 browser endpoints would take coverage from 388/388 to 357/357 and the gate would still pass. - Fail strict collection when an agent that should expose commands never loaded (getCommandEnabledState returns undefined), instead of skipping. - Assert the expected host set and a lower bound on endpoint count. Both are floors, so adding agents or endpoints won't fail the gate. - Extend the shared jest config instead of redeclaring it, so this gate gets the repo's 90s timeout and the CI failure reporter. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- ts/tools/actionBrowser/jest.config.cjs | 8 +---- ts/tools/actionBrowser/src/commands.ts | 9 ++++++ .../test/commandActionCoverage.spec.ts | 30 ++++++++++++++++++- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/ts/tools/actionBrowser/jest.config.cjs b/ts/tools/actionBrowser/jest.config.cjs index 357467404f..25456e93bb 100644 --- a/ts/tools/actionBrowser/jest.config.cjs +++ b/ts/tools/actionBrowser/jest.config.cjs @@ -1,10 +1,4 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -module.exports = { - testMatch: ["/dist/test/**/*.spec.js"], - testEnvironment: "node", - moduleNameMapper: { - "^../src/(.*)$": "/dist/$1", - }, -}; +module.exports = require("../../jest.config.js"); diff --git a/ts/tools/actionBrowser/src/commands.ts b/ts/tools/actionBrowser/src/commands.ts index cff6543e03..eb827882d4 100644 --- a/ts/tools/actionBrowser/src/commands.ts +++ b/ts/tools/actionBrowser/src/commands.ts @@ -94,6 +94,15 @@ export async function collectCommandsFromContext( const agents = context.agents; for (const host of agents.getAppAgentNames()) { if (!agents.isCommandEnabled(host)) { + // getCommandEnabledState returns null when the agent genuinely has + // no command interface, and undefined when it never loaded. Without + // this check a failed agent is dropped from the enumeration and the + // coverage gate still reports full coverage over what is left. + if (strict && agents.getCommandEnabledState(host) === undefined) { + throw new Error( + `Agent "${host}" did not load, so its commands cannot be collected. Coverage would be reported against an incomplete command set.`, + ); + } continue; } const appAgent = agents.getAppAgent(host); diff --git a/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts b/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts index c52e71c259..f12586953c 100644 --- a/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts +++ b/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts @@ -13,10 +13,38 @@ const workspaceRoot = path.resolve(here, "..", "..", "..", ".."); let catalog: Catalog; +// Hosts that ship command surfaces today. The coverage assertions below are all +// "the set of gaps is empty", which stays true if a host disappears from the +// enumeration entirely, so pin the hosts and a lower bound on the endpoint +// count as well. Both are floors: adding agents or endpoints won't fail here. +const EXPECTED_HOSTS = [ + "browser", + "calendar", + "dispatcher", + "email", + "greeting", + "localPlayer", + "osNotifications", + "player", + "powershell", + "system", +]; +const MIN_COMMAND_ENDPOINTS = 388; + describe("command action coverage", () => { beforeAll(async () => { catalog = await collectCatalog({ strict: true }); - }, 30_000); + }, 90_000); + + it("enumerates every command host", () => { + const hosts = [...new Set(catalog.commands.map((c) => c.host))]; + expect(hosts.sort()).toEqual( + expect.arrayContaining(EXPECTED_HOSTS.slice().sort()), + ); + expect(catalog.counts.commandEndpoints).toBeGreaterThanOrEqual( + MIN_COMMAND_ENDPOINTS, + ); + }); it("links every bundled executable command to a valid action", () => { expect(catalog.commandActionLinkIssues).toEqual([]); From 1ba1d4ab1e48ce6aecc1b339682d357a94191d12 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 19:13:39 -0700 Subject: [PATCH 17/22] Avoid new lint-ratchet violations in the powershell command path Replace the 'as any' context cast with a typed one and strip fallbackToReasoning without an unused destructured binding. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- ts/packages/agents/powershell/src/actionHandler.mts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ts/packages/agents/powershell/src/actionHandler.mts b/ts/packages/agents/powershell/src/actionHandler.mts index 7727bddb23..b6002e8ba3 100644 --- a/ts/packages/agents/powershell/src/actionHandler.mts +++ b/ts/packages/agents/powershell/src/actionHandler.mts @@ -1413,17 +1413,17 @@ async function executeBuiltInPowerShellAction( action: { actionName: string; parameters?: Record }, context: ActionContext, ): Promise { - (context as any).__store = + (context as { __store?: PowerShellStore | undefined }).__store = context.sessionContext.agentContext.store ?? _agentStore; const result = await handlePowerShellFlowAction(action, context); // Only the natural-language request pipeline retries with reasoning, and // the dispatcher skips error display when fallbackToReasoning is set. This // is the command path, so leaving the flag on makes failures silent. if ("fallbackToReasoning" in result && result.fallbackToReasoning) { - const { fallbackToReasoning, ...rest } = result as ActionResult & { - fallbackToReasoning?: boolean; - }; - return rest; + const stripped = { ...result }; + delete (stripped as { fallbackToReasoning?: boolean }) + .fallbackToReasoning; + return stripped; } return result; } From 0584d88e43214279d2c227a1fd0f219f013b87c6 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 20:11:25 -0700 Subject: [PATCH 18/22] Pass config agent names as structured params, not command text executeConfigAction interpolated translator-supplied agent names into a command string that processCommandNoLock then re-tokenizes. An agent name like 'calendar --reset' resolved as the real --reset flag, which sets every agent back to its default - a config rewrite the user never asked for. The same interpolation split any multi-word name into two names. All six cases now go through executeCommandFromHandlers with structured parameters, like runConfigCommand already did, so nothing model-supplied is re-parsed as command syntax. This also stops the six from swallowing failures: processCommandNoLock catches internally and never rethrows, so a failed toggle was reported to the caller as a successful action. Breaking the string path exposed a module cycle: configCommandHandlers -> command -> systemAgent, whose module-level systemHandlers called getConfigCommandHandlers() while this PR's singleton was still initializing. It only worked before because an unrelated import happened to load command.js first. systemHandlers and its command interface are now built lazily, and configCommandHandlers imports resolveCommand dynamically at its one call site. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../system/action/configActionHandler.ts | 104 +++++---- .../system/handlers/configCommandHandlers.ts | 6 +- .../system/handlers/helpCommandHandler.ts | 6 +- .../src/context/system/systemAgent.ts | 221 ++++++++++-------- .../dispatcher/dispatcher/src/internal.ts | 2 +- .../test/configActionHandler.spec.ts | 59 ++++- 6 files changed, 245 insertions(+), 153 deletions(-) diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts index 12ae3f9021..b5708c7985 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { processCommandNoLock } from "../../../command/command.js"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConfigAction } from "../schema/configActionSchema.js"; import { @@ -22,7 +21,6 @@ type RunConfigCommandAction = ConfigAction & { }; type ConfigActionDependencies = { - processCommand?: typeof processCommandNoLock; handlers?: CommandHandlerTable; executeCommand?: typeof executeCommandFromHandlers; }; @@ -198,76 +196,90 @@ function getConfigCommandParams( } as ParsedCommandParams; } +function getCommandParams( + handlers: CommandHandlerTable, + commands: string[], + args: Record, + flags: Record, +): ParsedCommandParams | undefined { + const handler = getCommandHandler(handlers, commands); + if (handler.parameters === undefined || handler.parameters === false) { + return undefined; + } + return { + args: handler.parameters.args === undefined ? undefined : args, + flags: handler.parameters.flags === undefined ? undefined : flags, + } as ParsedCommandParams; +} + export async function executeConfigAction( action: AppAction, context: ActionContext, dependencies: ConfigActionDependencies = {}, ): Promise { - const processCommand = dependencies.processCommand ?? processCommandNoLock; const configAction = action as unknown as ConfigAction; + const handlers = dependencies.handlers; + if (handlers === undefined) { + throw new Error("Config command handlers are unavailable."); + } + const execute = dependencies.executeCommand ?? executeCommandFromHandlers; + // Agent names come from the translator, so they are passed as structured + // parameters and never interpolated into a command string. The string form + // is re-tokenized by the command parser, so a name like "calendar --reset" + // would resolve as the real --reset flag and wipe the user's agent + // configuration. Going through the handler table also lets failures + // propagate to the action caller, which processCommandNoLock swallows. + const run = ( + commands: string[], + args: Record = {}, + flags: Record = {}, + ) => + execute( + handlers, + commands, + getCommandParams(handlers, commands, args, flags), + context, + ); + switch (configAction.actionName) { case "listAgents": - await processCommand( - `@config agent`, - context.sessionContext.agentContext, - ); - break; + return run(["agent"]); + case "toggleAgent": { const { enable, agentNames } = configAction.parameters; - // `off` is a multi-valued flag, but the parser consumes exactly one - // token per occurrence, so it has to be repeated per agent name. - // Passing `--off a b` would disable `a` and *enable* `b`. - const agentArgs = enable - ? agentNames.join(" ") - : agentNames.map((name) => `--off ${name}`).join(" "); - - await processCommand( - `@config agent ${agentArgs}`, - context.sessionContext.agentContext, - ); - break; + return enable + ? run(["agent"], { agentNames }) + : run(["agent"], {}, { off: agentNames }); } + case "toggleExplanation": - await processCommand( - `@config explainer ${configAction.parameters.enable ? "on" : "off"}`, - context.sessionContext.agentContext, - ); - break; + return run([ + "explainer", + configAction.parameters.enable ? "on" : "off", + ]); case "toggleDeveloperMode": - await processCommand( - `@config dev ${configAction.parameters.enable ? "on" : "off"}`, - context.sessionContext.agentContext, - ); - break; + return run(["dev", configAction.parameters.enable ? "on" : "off"]); case "enterAgentPriorityMode": - await processCommand( - `@config agent --priority ${configAction.parameters.agentName}`, - context.sessionContext.agentContext, + return run( + ["agent"], + {}, + { priority: [configAction.parameters.agentName] }, ); - break; case "exitAgentPriorityMode": - await processCommand( - `@config agent --reset`, - context.sessionContext.agentContext, - ); - break; + return run(["agent"], {}, { reset: true }); case "runConfigCommand": - if (dependencies.handlers === undefined) { - throw new Error("Config command handlers are unavailable."); - } - return (dependencies.executeCommand ?? executeCommandFromHandlers)( - dependencies.handlers, + return execute( + handlers, configAction.parameters.command.split(" "), - getConfigCommandParams(configAction, dependencies.handlers), + getConfigCommandParams(configAction, handlers), context, ); default: throw new Error(`Invalid action name: ${action.actionName}`); } - return undefined; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts index 1586677756..dc9068d5d2 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts @@ -50,7 +50,6 @@ import { } from "@typeagent/agent-sdk/helpers/display"; import { alwaysEnabledAgents } from "../../appAgentManager.js"; import { getCacheFactory } from "../../../utils/cacheFactory.js"; -import { resolveCommand } from "../../../command/command.js"; import { toggleActivityContext } from "../../../execute/activityContext.js"; import registerDebug from "debug"; const debugReasoning = registerDebug("typeagent:dispatcher:reasoning:config"); @@ -1498,6 +1497,11 @@ async function checkRequestHandler( systemContext: CommandHandlerContext, throwIfFailed: boolean = true, ) { + // Imported lazily to break a module cycle: command.js pulls in + // systemAgent.js, whose module-level systemHandlers calls + // getConfigCommandHandlers() from this file. A static import makes that a + // temporal dead zone error whenever this module is loaded first. + const { resolveCommand } = await import("../../../command/command.js"); const result = await resolveCommand( `${appAgentName} request`, systemContext, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts index 0a21cdbd09..af8187c013 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts @@ -10,7 +10,7 @@ import { } from "@typeagent/agent-sdk"; import { CommandHandler } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; -import { systemHandlers } from "../systemAgent.js"; +import { getSystemHandlers } from "../systemAgent.js"; import { getUsage, printAllCommandsWithUsage, @@ -57,7 +57,7 @@ export class HelpCommandHandler implements CommandHandler { const systemContext = context.sessionContext.agentContext; if (params.flags.all) { // print all system handlers - printAllCommandsWithUsage(systemHandlers, undefined, context); + printAllCommandsWithUsage(getSystemHandlers(), undefined, context); // print all agent handlers const agentNames: string[] = @@ -91,7 +91,7 @@ export class HelpCommandHandler implements CommandHandler { return; } else if (params.args.command === undefined) { printStructuredHandlerTableUsage( - systemHandlers, + getSystemHandlers(), undefined, context, ); diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts b/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts index 049cc84e74..8dd3c95762 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts @@ -122,96 +122,114 @@ class ClearDeepCommandHandler implements CommandHandlerNoParams { } } -export const systemHandlers: CommandHandlerTable = { - description: "Type Agent System Commands", - commands: { - action: new ActionCommandHandler(), - describe: new DescribeCommandHandler(), - demo: getDemoCommandHandlers(), - session: getSessionCommandHandlers(), - conversation: getConversationCommandHandlers(), - copilot: getCopilotCommandHandlers(), - collision: collisionCommandHandlers, - grammar: getGrammarCommandHandlers(), - history: getHistoryCommandHandlers(), - memory: getMemoryCommandHandlers(), - const: getConstructionCommandHandlers(), - config: getConfigCommandHandlers(), - feedback: getFeedbackCommandHandlers(), - display: new DisplayCommandHandler(), - trace: new TraceCommandHandler(), - log: getLogCommandHandlers(), - help: new HelpCommandHandler(), - debug: new DebugCommandHandler(), - clear: { - description: "Clear the console", - defaultSubCommand: new ClearConsoleCommandHandler(), - commands: { - deep: new ClearDeepCommandHandler(), - }, - }, - run: new RunCommandScriptHandler(), - exit: { - description: "Exit the program", - action: { - schema: "system.operations", - actionName: "exitTypeAgent", - }, - async run(context: ActionContext) { - const systemContext = context.sessionContext.agentContext; - systemContext.clientIO.exit(getRequestId(systemContext)); +// Built lazily. Several of the getXCommandHandlers() modules below import back +// into the dispatcher command pipeline, which imports this module, so building +// the table during this module's own initialization turns that cycle into a +// temporal dead zone error depending on which module is loaded first. +let systemHandlersInstance: CommandHandlerTable | undefined; +export function getSystemHandlers(): CommandHandlerTable { + if (systemHandlersInstance === undefined) { + systemHandlersInstance = createSystemHandlers(); + } + return systemHandlersInstance; +} + +function createSystemHandlers(): CommandHandlerTable { + return { + description: "Type Agent System Commands", + commands: { + action: new ActionCommandHandler(), + describe: new DescribeCommandHandler(), + demo: getDemoCommandHandlers(), + session: getSessionCommandHandlers(), + conversation: getConversationCommandHandlers(), + copilot: getCopilotCommandHandlers(), + collision: collisionCommandHandlers, + grammar: getGrammarCommandHandlers(), + history: getHistoryCommandHandlers(), + memory: getMemoryCommandHandlers(), + const: getConstructionCommandHandlers(), + config: getConfigCommandHandlers(), + feedback: getFeedbackCommandHandlers(), + display: new DisplayCommandHandler(), + trace: new TraceCommandHandler(), + log: getLogCommandHandlers(), + help: new HelpCommandHandler(), + debug: new DebugCommandHandler(), + clear: { + description: "Clear the console", + defaultSubCommand: new ClearConsoleCommandHandler(), + commands: { + deep: new ClearDeepCommandHandler(), + }, }, - }, - shutdown: { - description: "Shut down the agent server and exit", - action: { - schema: "system.operations", - actionName: "shutdownAgentServer", + run: new RunCommandScriptHandler(), + exit: { + description: "Exit the program", + action: { + schema: "system.operations", + actionName: "exitTypeAgent", + }, + async run(context: ActionContext) { + const systemContext = context.sessionContext.agentContext; + systemContext.clientIO.exit(getRequestId(systemContext)); + }, }, - async run(context: ActionContext) { - const systemContext = context.sessionContext.agentContext; - systemContext.clientIO.shutdown(getRequestId(systemContext)); + shutdown: { + description: "Shut down the agent server and exit", + action: { + schema: "system.operations", + actionName: "shutdownAgentServer", + }, + async run(context: ActionContext) { + const systemContext = context.sessionContext.agentContext; + systemContext.clientIO.shutdown( + getRequestId(systemContext), + ); + }, }, - }, - server: { - description: "Manage the agent server", - commands: { - restart: { - description: - "Restart the agent server so it loads rebuilt code", - action: { - schema: "system.operations", - actionName: "restartAgentServer", - }, - async run(context: ActionContext) { - const systemContext = - context.sessionContext.agentContext; - // The routing clientIO always defines restart but - // throws when the connected host can't self-restart - // (e.g. the in-process shell). A host whose clientIO - // omits restart entirely lands here as undefined. - if (systemContext.clientIO.restart === undefined) { - throw new Error( - "Restart is only available when connected to a standalone agent server.", + server: { + description: "Manage the agent server", + commands: { + restart: { + description: + "Restart the agent server so it loads rebuilt code", + action: { + schema: "system.operations", + actionName: "restartAgentServer", + }, + async run( + context: ActionContext, + ) { + const systemContext = + context.sessionContext.agentContext; + // The routing clientIO always defines restart but + // throws when the connected host can't self-restart + // (e.g. the in-process shell). A host whose clientIO + // omits restart entirely lands here as undefined. + if (systemContext.clientIO.restart === undefined) { + throw new Error( + "Restart is only available when connected to a standalone agent server.", + ); + } + systemContext.clientIO.restart( + getRequestId(systemContext), ); - } - systemContext.clientIO.restart( - getRequestId(systemContext), - ); + }, }, }, }, + random: getRandomCommandHandlers(), + notify: getNotifyCommandHandlers(), + token: getTokenCommandHandlers(), + env: getEnvCommandHandlers(), + open: new OpenCommandHandler(), + index: getIndexCommandHandlers(), + settings: getSettingsCommandHandlers(), + ports: new PortsCommandHandler(), }, - random: getRandomCommandHandlers(), - notify: getNotifyCommandHandlers(), - token: getTokenCommandHandlers(), - env: getEnvCommandHandlers(), - open: new OpenCommandHandler(), - index: getIndexCommandHandlers(), - settings: getSettingsCommandHandlers(), - ports: new PortsCommandHandler(), - }, -}; + }; +} function executeSystemAction( action: @@ -239,14 +257,15 @@ function executeSystemAction( return executeConversationAction(action, context); case "system.config": return executeConfigAction(action, context, { - handlers: systemHandlers.commands.config as CommandHandlerTable, + handlers: getSystemHandlers().commands + .config as CommandHandlerTable, }); case "system.notify": return executeNotificationAction(action, context); case "system.history": return executeHistoryAction(action, context); case "system.grammar": - return executeGrammarAction(action, context, systemHandlers); + return executeGrammarAction(action, context, getSystemHandlers()); case "system.settings": return executeSettingsAction(action, context); case "system.log": @@ -259,43 +278,43 @@ function executeSystemAction( return executeSystemDiagnosticsAction( action, context, - systemHandlers, + getSystemHandlers(), ); case "system.session": return executeSessionAction( action, context, - systemHandlers.commands.session as CommandHandlerTable, + getSystemHandlers().commands.session as CommandHandlerTable, ); case "system.memory": return executeMemoryAction( action, context, - systemHandlers.commands.memory as CommandHandlerTable, + getSystemHandlers().commands.memory as CommandHandlerTable, ); case "system.copilot": return executeCopilotAction( action, context, - systemHandlers.commands.copilot as CommandHandlerTable, + getSystemHandlers().commands.copilot as CommandHandlerTable, ); case "system.feedback": return executeFeedbackAction( action, context, - systemHandlers.commands.feedback as CommandHandlerTable, + getSystemHandlers().commands.feedback as CommandHandlerTable, ); case "system.operations": return executeSystemOperationsAction( action, context, - systemHandlers, + getSystemHandlers(), ); case "system.construction": return executeConstructionAction( action, context, - systemHandlers.commands.const as CommandHandlerTable, + getSystemHandlers().commands.const as CommandHandlerTable, ); case "system.collision": return executeCollisionAction( @@ -501,7 +520,17 @@ export const systemManifest: AppAgentManifest = { }, }; -const commandInterface = getCommandInterface(systemHandlers); +// Also lazy: building the interface eagerly would build the handler table +// during this module's initialization, which is what the cycle above avoids. +let commandInterfaceInstance: + | ReturnType + | undefined; +function getSystemCommandInterface() { + if (commandInterfaceInstance === undefined) { + commandInterfaceInstance = getCommandInterface(getSystemHandlers()); + } + return commandInterfaceInstance; +} // Route responses from the system agent's interactive choice/form cards (today // the `@demo` walkthrough) back to the shared per-context ChoiceManager, which @@ -526,7 +555,9 @@ export const systemAgent: AppAgent = { getTemplateCompletion: getSystemTemplateCompletion, executeAction: executeSystemAction as unknown as AppAgent["executeAction"], handleChoice: handleSystemChoice, - getCommands: commandInterface.getCommands, - getCommandCompletion: commandInterface.getCommandCompletion, - executeCommand: commandInterface.executeCommand, + getCommands: (...args) => getSystemCommandInterface().getCommands(...args), + getCommandCompletion: (...args) => + getSystemCommandInterface().getCommandCompletion!(...args), + executeCommand: (...args) => + getSystemCommandInterface().executeCommand(...args), } as AppAgent; diff --git a/ts/packages/dispatcher/dispatcher/src/internal.ts b/ts/packages/dispatcher/dispatcher/src/internal.ts index cf2964d0f0..76737343e1 100644 --- a/ts/packages/dispatcher/dispatcher/src/internal.ts +++ b/ts/packages/dispatcher/dispatcher/src/internal.ts @@ -85,4 +85,4 @@ export { initializeGeolocation } from "./context/geolocation.js"; // System command handler tree — exposed for tooling that statically enumerates // the `@command` surface (e.g. the Action Browser documentation generator). -export { systemHandlers } from "./context/system/systemAgent.js"; +export { getSystemHandlers } from "./context/system/systemAgent.js"; diff --git a/ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts b/ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts index 178afc13b7..3642c28b03 100644 --- a/ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts +++ b/ts/packages/dispatcher/dispatcher/test/configActionHandler.spec.ts @@ -9,18 +9,16 @@ const agentContext = { id: "agent-context" } as any; const context = { sessionContext: { agentContext } } as any; async function run(action: any) { - const processCommand = jest.fn(async () => undefined); const executeCommand = jest.fn(async () => undefined); await executeConfigAction( { schemaName: "system.config", ...action }, context, { - processCommand, handlers: configCommandHandlers, executeCommand: executeCommand as any, }, ); - return { executeCommand, processCommand }; + return { executeCommand }; } describe("config actions", () => { @@ -108,15 +106,62 @@ describe("config actions", () => { ); }); + it("passes agent names as structured arguments, not command text", async () => { + const { executeCommand } = await run({ + actionName: "toggleAgent", + parameters: { enable: true, agentNames: ["calendar", "email"] }, + }); + + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["agent"], + { args: { agentNames: ["calendar", "email"] }, flags: {} }, + context, + ); + }); + + it("disables every requested agent instead of enabling all but the first", async () => { + const { executeCommand } = await run({ + actionName: "toggleAgent", + parameters: { enable: false, agentNames: ["player", "email"] }, + }); + + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["agent"], + { args: {}, flags: { off: ["player", "email"] } }, + context, + ); + }); + + it("does not let a flag-shaped agent name become a flag", async () => { + const { executeCommand } = await run({ + actionName: "enterAgentPriorityMode", + parameters: { agentName: "calendar --reset" }, + }); + + // The name stays a single value. Interpolating it into a command + // string would re-tokenize --reset into the real flag and clear the + // user's whole agent configuration. + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["agent"], + { args: {}, flags: { priority: ["calendar --reset"] } }, + context, + ); + }); + it("keeps the existing developer-mode action behavior", async () => { - const { processCommand } = await run({ + const { executeCommand } = await run({ actionName: "toggleDeveloperMode", parameters: { enable: false }, }); - expect(processCommand).toHaveBeenCalledWith( - "@config dev off", - agentContext, + expect(executeCommand).toHaveBeenCalledWith( + configCommandHandlers, + ["dev", "off"], + undefined, + context, ); }); }); From 6e63397c4aa9b71c2e0489302771daa5a42903d5 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 20:18:26 -0700 Subject: [PATCH 19/22] Keep the OAuth code off the action path, fix @localPlayer play, correct docs Calendar: calendarGoogleAuth took the Google authorization code as an LLM-authored parameter. The command path gets the code the user typed; the action path got whatever the translator emitted, and the code was sent to the model provider (the outbound scrubber has no pattern for Google's 4/0A format). A truncated or rewritten code silently burns the single-use grant. The action is now parameterless and points the user at the command, and the grammar rule no longer captures a code. playerLocal: '@localPlayer play' failed with 'Invalid track number: 0' whenever the queue was built with addToQueue and nothing had played yet - currentIndex starts at -1 and playFromQueue is 1-based. Newly reachable by natural language, so fixing rather than inheriting. playerLocal: add the missing test:local script. Without it 'pnpm -r --no-bail' silently skipped the package, so all three spec files - including the grammar spec this PR added a dependency for - never ran in CI. playerLocal: the command-link test asserted the length of its own literal; compare against the live table instead. Docs: STATUS.md reported 387/387 when the tool prints 393/393, and claimed '--mock' greeting action parity that was deliberately removed. Both STATUS.md and PLAN.md now state that the gate enforces link coverage, not behavioral equivalence, and call out the two endpoints whose actions intentionally do less than their command. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- ts/docs/plans/agent-command-actions/PLAN.md | 13 ++++- ts/docs/plans/agent-command-actions/STATUS.md | 52 ++++++++++++------- .../calendar/src/calendarActionHandlerV3.ts | 11 ++-- .../calendar/src/calendarActionsSchemaV3.ts | 14 ++--- .../agents/calendar/src/calendarSchema.agr | 4 +- .../agents/calendar/test/calendarAuth.spec.ts | 20 ++++--- ts/packages/agents/playerLocal/package.json | 3 +- .../src/agent/localPlayerHandlers.ts | 8 ++- .../test/localPlayerCommands.spec.ts | 6 ++- 9 files changed, 83 insertions(+), 48 deletions(-) diff --git a/ts/docs/plans/agent-command-actions/PLAN.md b/ts/docs/plans/agent-command-actions/PLAN.md index c8bb3fc71e..5d184a43c8 100644 --- a/ts/docs/plans/agent-command-actions/PLAN.md +++ b/ts/docs/plans/agent-command-actions/PLAN.md @@ -27,6 +27,15 @@ A command is covered only when: 4. Both paths invoke the same command pipeline or typed helper. 5. Translation and command/action parity are tested. +**Only condition 1 is machine-enforced.** `commandActionCoverage.spec.ts` checks +that every executable endpoint declares an action name resolving to exactly one +registered action, and that `ConfigCommandPath` stays in sync with the live +config tree. Conditions 2, 3, and 5 are per-host work verified by hand and by +whatever unit tests each host happens to have; no gate can currently detect a +command and its action drifting apart. Treat a green gate as "every endpoint is +linked", not "every endpoint is equivalent", and check STATUS.md for the hosts +where parity is known to be partial. + `CommandDescriptor.action` is metadata only. Adding a link never creates natural-language support and does not count as completion by itself. @@ -128,8 +137,8 @@ paths use a shared typed helper. 3. **Complete agent-host actions.** Add the known localPlayer and browser gaps, auth/OAuth actions, browser configuration, and dispatcher diagnostics. PowerShell `show` and email indexing were completed in the second - implementation slice. This phase is complete: no agent-host command remains - uncovered. + implementation slice. Every agent-host command endpoint is now linked to an + action; parity beyond linkage is per-host and tracked in STATUS.md. 4. **Complete existing system families.** Finish `system.config`, `system.conversation`, `system.help`, `system.grammar`, `system.history`, `system.notify`, and `system.settings`. diff --git a/ts/docs/plans/agent-command-actions/STATUS.md b/ts/docs/plans/agent-command-actions/STATUS.md index c198b4b672..a1d19140bf 100644 --- a/ts/docs/plans/agent-command-actions/STATUS.md +++ b/ts/docs/plans/agent-command-actions/STATUS.md @@ -3,6 +3,16 @@ Tracks [PLAN.md](./PLAN.md). Counts come from strict executable-endpoint collection, not manual estimates. +**What the counts mean.** The gate enforces _link_ coverage: every executable +command endpoint declares an action name that resolves to exactly one action +registered for that host. It does not verify that dispatching the action has the +same effect as running the command. Behavioral parity is covered only by the +per-host unit tests, and unevenly. Read "linked", not "equivalent". + +The endpoint count also overstates how many distinct actions exist: 165 of the +endpoints are `@config *` paths that all resolve to the single +`runConfigCommand` passthrough, which re-parses the command path as a string. + ## Baseline (2026-07-31) | Metric | Count | @@ -15,10 +25,13 @@ collection, not manual estimates. ## Current coverage +The endpoint total moves as agents add commands, so treat it as a snapshot; the +invariant the gate enforces is `0 missing, 0 invalid`. + | Metric | Count | | ------------------------------------ | ------------------: | -| Executable command endpoints | 387 | -| Valid linked endpoints | 387 | +| Executable command endpoints | 393 | +| Valid linked endpoints | 393 | | Missing action declarations | 0 | | Invalid / dangling / ambiguous links | 0 | | Runtime-only static omissions | 1 (`mcpfilesystem`) | @@ -42,20 +55,22 @@ collection, not manual estimates. ## Implemented hosts and slices -| Host | Coverage completed in this milestone | -| --------------- | ----------------------------------------------------------------------------------------- | -| localPlayer | All 16 endpoints, including bare status default, general play, and mute/shuffle toggles. | -| osNotifications | `sync`, `test`. | -| selfhelp | Bare default and `ask`. | -| powershell | All five management endpoints: `list`, `run`, `delete`, `show`, and `import`. | -| browser | All 31 endpoints, including config, automation lifecycle, extraction, Q&A, and recording. | -| email | All 5 endpoints: login default, logout, Google auth, and inbox indexing. | -| greeting | Bare command, including deterministic `--mock` action parity. | -| player | All 3 Spotify management endpoints: load, login, and logout. | -| calendar | All 4 auth endpoints, including the bare login default and Google auth. | -| dispatcher | All 6 request/match/translate/reason/explain diagnostics. | - -All non-system command hosts are now fully covered. +| Host | Coverage completed in this milestone | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| localPlayer | All 16 endpoints, including bare status default, general play, and mute/shuffle toggles. | +| osNotifications | `sync`, `test`. | +| selfhelp | Bare default and `ask`. | +| powershell | All five management endpoints: `list`, `run`, `delete`, `show`, and `import`. | +| browser | All 31 endpoints, including config, automation lifecycle, extraction, Q&A, and recording. | +| email | All 5 endpoints: login default, logout, Google auth, and inbox indexing. | +| greeting | Bare command. `--mock` is intentionally command-only: the deterministic mock greeting is kept out of the action schema so the translator cannot select it in place of a real greeting. | +| player | All 3 Spotify management endpoints: load, login, and logout. | +| calendar | All 4 auth endpoints. `google-auth` links to an action that points the user back at the command: the authorization code is a single-use credential and must not be model-authored. | +| dispatcher | All 6 request/match/translate/reason/explain diagnostics. | + +All non-system command hosts have a linked action for every executable +endpoint. Two endpoints (`@greeting --mock`, `@calendar google-auth`) link to +actions that deliberately do less than the command, for the reasons above. ## System progress @@ -81,7 +96,7 @@ All non-system command hosts are now fully covered. The strict coverage check is: ```text -Command action coverage: 387 / 387 endpoints (0 missing, 0 invalid) +Command action coverage: 393 / 393 endpoints (0 missing, 0 invalid) Runtime-only schemas omitted: mcpfilesystem ``` @@ -94,7 +109,8 @@ node tools/actionBrowser/dist/cli.js --check --allow-missing ``` Permanent regression coverage is also enforced by -`test/commandActionCoverage.spec.ts`. The strict completion command is: +`tools/actionBrowser/test/commandActionCoverage.spec.ts`. The strict completion +command is: ```powershell node tools/actionBrowser/dist/cli.js --check diff --git a/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts b/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts index 075a15d01d..e150f7e735 100644 --- a/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts +++ b/ts/packages/agents/calendar/src/calendarActionHandlerV3.ts @@ -573,11 +573,12 @@ export class CalendarActionHandlerV3 implements AppAgent { await calendarLogoutHandler.run(context); return undefined; case "calendarGoogleAuth": - await googleAuthHandler.run(context, { - args: { code: calendarAction.parameters.code }, - flags: undefined, - }); - return undefined; + // The command path does the real work. The action only points + // the user at it so the single-use authorization code is never + // produced by the translator. + return createActionResultFromTextDisplay( + "To finish Google Calendar authorization, run `@calendar google-auth ` with the code Google gave you. The code is single-use, so it has to be entered directly rather than through a natural-language request.", + ); } if (!provider) { diff --git a/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts b/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts index e14023fc80..55d065fb91 100644 --- a/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts +++ b/ts/packages/agents/calendar/src/calendarActionsSchemaV3.ts @@ -40,15 +40,15 @@ export type CalendarLogoutAction = { actionName: "calendarLogout"; }; -// user: complete Google Calendar authorization with code 4/abc123 -// agent: { "actionName": "calendarGoogleAuth", "parameters": { "code": "4/abc123" } } -// Complete Google Calendar authorization with the exact authorization code. +// user: finish setting up my Google Calendar +// agent: { "actionName": "calendarGoogleAuth" } +// Explain how to finish Google Calendar authorization. This action deliberately +// takes no parameters: the authorization code is a single-use credential, so it +// must be typed into the `@calendar google-auth ` command rather than +// routed through translation, where the model could truncate or rewrite it and +// where it would be sent to the model provider. export type CalendarGoogleAuthAction = { actionName: "calendarGoogleAuth"; - parameters: { - // The unmodified authorization code returned by Google. - code: string; - }; }; // Schedule a new event on the calendar diff --git a/ts/packages/agents/calendar/src/calendarSchema.agr b/ts/packages/agents/calendar/src/calendarSchema.agr index 745ad09c3b..c28e57df05 100644 --- a/ts/packages/agents/calendar/src/calendarSchema.agr +++ b/ts/packages/agents/calendar/src/calendarSchema.agr @@ -127,8 +127,8 @@ import { CalendarActionV3 } from "./calendarActionsSchemaV3.ts"; = (log out | logout | sign out) (of)? (my)? (calendar | google calendar | outlook calendar) -> { actionName: "calendarLogout" }; - = (complete | finish) google calendar (authorization | authentication | oauth) (with)? (code)? $(code:wildcard) - -> { actionName: "calendarGoogleAuth", parameters: { code } }; + = (complete | finish) (setting up)? google calendar (authorization | authentication | oauth | setup) + -> { actionName: "calendarGoogleAuth" }; = what's happening this week -> { actionName: "findThisWeeksEvents" diff --git a/ts/packages/agents/calendar/test/calendarAuth.spec.ts b/ts/packages/agents/calendar/test/calendarAuth.spec.ts index 515b5b6b65..f05d818f12 100644 --- a/ts/packages/agents/calendar/test/calendarAuth.spec.ts +++ b/ts/packages/agents/calendar/test/calendarAuth.spec.ts @@ -50,11 +50,8 @@ describe("calendar auth actions", () => { expect(match("sign out of google calendar")).toEqual({ actionName: "calendarLogout", }); - expect( - match("complete google calendar authorization with code 4/abc123"), - ).toEqual({ + expect(match("finish google calendar authorization")).toEqual({ actionName: "calendarGoogleAuth", - parameters: { code: "4/abc123" }, }); }); @@ -178,10 +175,9 @@ describe("calendar auth actions", () => { expect(JSON.stringify(displays)).toMatch(/ada@example\.com/); }); - it("forwards the Google authorization code unchanged", async () => { + it("never routes the Google authorization code through the action path", async () => { const agent = instantiate(); const codes: string[] = []; - const displays: unknown[] = []; const context = { sessionContext: { agentContext: { @@ -195,20 +191,22 @@ describe("calendar auth actions", () => { }, }, actionIO: { - setDisplay: (value: unknown) => displays.push(value), - appendDisplay: (value: unknown) => displays.push(value), + setDisplay: () => {}, + appendDisplay: () => {}, }, } as any; - await agent.executeAction!( + const result = await agent.executeAction!( { schemaName: "calendar", actionName: "calendarGoogleAuth", - parameters: { code: "4/AbC-123_exact" }, } as any, context, ); - expect(codes).toEqual(["4/AbC-123_exact"]); + // The code is single-use and must not be model-authored, so the action + // only points at the command instead of completing the exchange. + expect(codes).toEqual([]); + expect(JSON.stringify(result)).toMatch(/@calendar google-auth/); }); }); diff --git a/ts/packages/agents/playerLocal/package.json b/ts/packages/agents/playerLocal/package.json index 75b4cba87d..81363a5a60 100644 --- a/ts/packages/agents/playerLocal/package.json +++ b/ts/packages/agents/playerLocal/package.json @@ -29,7 +29,8 @@ "build": "concurrently npm:tsc npm:asc npm:agc", "clean": "rimraf --glob dist *.tsbuildinfo *.done.build.log", "jest-esm": "node --no-warnings --experimental-vm-modules ./node_modules/jest/bin/jest.js", - "test": "pnpm run jest-esm --testPathPattern=\".*[.]spec[.]js\"", + "test": "npm run test:local", + "test:local": "pnpm run jest-esm --testPathPattern=\".*[.]spec[.]js\"", "tsc": "tsc -b src test" }, "dependencies": { diff --git a/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts b/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts index f2e45efef9..bfee7ccda9 100644 --- a/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts +++ b/ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts @@ -255,7 +255,13 @@ async function handlePlay(service: LocalPlayerService, fileName?: string) { return handleResume(service); } if (state.queue.length > 0) { - return handlePlayFromQueue(service, state.currentIndex + 1); + // playFromQueue is 1-based, but currentIndex is 0-based and stays at + // -1 until something plays, so a queue built with addToQueue would ask + // for track 0 and fail. + return handlePlayFromQueue( + service, + Math.max(state.currentIndex, 0) + 1, + ); } return handlePlayFolder(service); } diff --git a/ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts b/ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts index 9e8768d0ab..367e51ae7b 100644 --- a/ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts +++ b/ts/packages/agents/playerLocal/test/localPlayerCommands.spec.ts @@ -36,6 +36,10 @@ describe("localPlayer command action links", () => { ); } - expect(Object.keys(expected)).toHaveLength(15); + // Compare against the live table, not the literal above, so a command + // added or removed without a matching action link fails here. + expect(Object.keys(table.commands).sort()).toEqual( + Object.keys(expected).sort(), + ); }); }); From af423b65757d22e5c4c76666db35b5c8c7875ba7 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 20:28:14 -0700 Subject: [PATCH 20/22] Type the action bridges instead of using any, clearing the lint ratchet build_ts failed the lint ratchet with 24 net-new violations against main, almost all @typescript-eslint/no-explicit-any in the new action handlers. Most were type annotations rather than real dynamism: - ParsedCommandParams and 'params?: any' become CommandParams, a shared alias for ParsedCommandParams, for commands resolved by name at dispatch time. - getFlagType(definition as any) and the flag value map are now typed. - The powershell flowParametersJson catch narrows the error instead of typing it as any. The one genuinely loose spot is an action's parameters object: each switch case reads its own fields off a union whose members disagree about whether parameters exists. That is now the single exported ActionParams type with one documented eslint-disable and a TODO, rather than 20 scattered anys. Narrowing it per case belongs with the change that makes executeCommandFromHandlers apply each command's declared defaults, which would also delete the hand-copied default literals the reviewers flagged. Ratchet now reports 154 -> 142: the changed files carry fewer violations than the base. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../browser/src/agent/configActionHandler.mts | 5 ++-- .../src/agent/pageToolsActionHandler.mts | 5 ++-- .../agents/powershell/src/actionHandler.mts | 4 ++-- .../dispatcher/diagnosticsActionHandler.ts | 8 ++++++- .../src/context/system/action/actionParams.ts | 23 +++++++++++++++++-- .../system/action/collisionActionHandler.ts | 23 +++++++++---------- .../system/action/configActionHandler.ts | 15 ++++++------ .../action/constructionActionHandler.ts | 18 +++++++++------ .../system/action/feedbackActionHandler.ts | 4 ++-- .../system/action/historyActionHandler.ts | 3 ++- .../system/action/indexActionHandler.ts | 4 ++-- .../system/action/memoryActionHandler.ts | 4 ++-- .../action/systemDiagnosticsActionHandler.ts | 4 ++-- .../action/systemOperationsActionHandler.ts | 11 ++++----- 14 files changed, 81 insertions(+), 50 deletions(-) diff --git a/ts/packages/agents/browser/src/agent/configActionHandler.mts b/ts/packages/agents/browser/src/agent/configActionHandler.mts index ca86a6f51c..cf043c082d 100644 --- a/ts/packages/agents/browser/src/agent/configActionHandler.mts +++ b/ts/packages/agents/browser/src/agent/configActionHandler.mts @@ -3,6 +3,7 @@ import { ActionContext, + ParameterDefinitions, ActionResult, ParsedCommandParams, TypeAgentAction, @@ -17,7 +18,7 @@ import { BrowserConfigActions } from "./configActionSchema.mjs"; type CommandExecutor = ( handlers: CommandHandlerTable, commands: string[], - params: ParsedCommandParams | undefined, + params: ParsedCommandParams | undefined, context: ActionContext, ) => Promise; @@ -82,7 +83,7 @@ export async function executeBrowserConfigAction( action.parameters?.provider?.trim() || undefined, }, flags: undefined, - }, + } as unknown as ParsedCommandParams, context, ); case "addSearchProvider": diff --git a/ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts b/ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts index 4c2ef02953..771e5ab004 100644 --- a/ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts +++ b/ts/packages/agents/browser/src/agent/pageToolsActionHandler.mts @@ -3,6 +3,7 @@ import { ActionContext, + ParameterDefinitions, ActionResult, ParsedCommandParams, TypeAgentAction, @@ -17,7 +18,7 @@ import { BrowserPageToolsActions } from "./pageToolsActionSchema.mjs"; type CommandExecutor = ( handlers: CommandHandlerTable, commands: string[], - params: ParsedCommandParams | undefined, + params: ParsedCommandParams | undefined, context: ActionContext, ) => Promise; @@ -57,7 +58,7 @@ export function executeBrowserPageToolsAction( { args: { description: action.parameters?.description }, flags: undefined, - }, + } as unknown as ParsedCommandParams, context, ); } diff --git a/ts/packages/agents/powershell/src/actionHandler.mts b/ts/packages/agents/powershell/src/actionHandler.mts index b6002e8ba3..259dc59c7b 100644 --- a/ts/packages/agents/powershell/src/actionHandler.mts +++ b/ts/packages/agents/powershell/src/actionHandler.mts @@ -1196,10 +1196,10 @@ async function handlePowerShellFlowAction( if (flowParamsJson) { try { namedParams = JSON.parse(flowParamsJson); - } catch (e: any) { + } catch (e) { return createPowerShellFailure( "invalidParameters", - `Invalid JSON in flowParametersJson: ${e.message}`, + `Invalid JSON in flowParametersJson: ${e instanceof Error ? e.message : String(e)}`, ); } } diff --git a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts index 5569053cfc..012f379af6 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts @@ -8,11 +8,17 @@ import { } from "@typeagent/agent-sdk"; import { CommandHandlerContext } from "../commandHandlerContext.js"; import { DispatcherDiagnosticsActions } from "./schema/diagnosticsActionSchema.js"; +import { ActionParams } from "../system/action/actionParams.js"; type DiagnosticsCommandHandler = { run( context: ActionContext, - params: any, + params: + | { + args?: ActionParams | undefined; + flags?: ActionParams | undefined; + } + | undefined, ): Promise; }; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts index 9f32c40090..977c26bcb4 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts @@ -1,6 +1,25 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import type { + ParameterDefinitions, + ParsedCommandParams, +} from "@typeagent/agent-sdk"; + +// Parameters for a command resolved at action-dispatch time. The action +// handlers pick the command by name, so its parameter definitions aren't known +// statically the way they are inside a CommandHandler. +export type CommandParams = ParsedCommandParams; + +// An action's `parameters` object. Each switch case reads its own fields, and +// the value types come from that case's schema member, so this stays loose. +// Tightening it means narrowing per case in every handler, which is worth doing +// alongside making executeCommandFromHandlers apply the command's declared +// defaults (today each handler hand-copies them). +// TODO: replace with per-case narrowing once defaults are resolved centrally. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ActionParams = Record; + /** Returns `{ [key]: value }` when value is defined, `{}` otherwise. */ export function opt(value: T | undefined, key: string): Record { return value !== undefined ? { [key]: value } : {}; @@ -11,6 +30,6 @@ export function opt(value: T | undefined, key: string): Record { // direct `action.parameters` doesn't type check and throws at runtime when the // translator omits it. Returning `{}` for both cases lets each switch case read // its fields and fall back to the command's default. -export function actionParams(action: { actionName: string }): any { - return (action as { parameters?: any }).parameters ?? {}; +export function actionParams(action: { actionName: string }): ActionParams { + return (action as { parameters?: ActionParams }).parameters ?? {}; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts index 7738dd77c9..9be2ae7a5d 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts @@ -4,7 +4,6 @@ import { ActionContext, ActionResult, - ParsedCommandParams, TypeAgentAction, } from "@typeagent/agent-sdk"; import { @@ -13,7 +12,7 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { CollisionAction } from "../schema/collisionActionSchema.js"; -import { opt } from "./actionParams.js"; +import { CommandParams, ActionParams, opt } from "./actionParams.js"; function csv(values: string[] | undefined): string | undefined { return values?.join(","); @@ -21,7 +20,7 @@ function csv(values: string[] | undefined): string | undefined { type Executor = ( commands: string[], - params?: ParsedCommandParams, + params?: CommandParams, ) => Promise; // --------------------------------------------------------------------------- @@ -73,7 +72,7 @@ const PREFERENCES_ACTIONS = new Set([ function executeCollisionCorpusGenAction( actionName: string, - p: any, + p: ActionParams, execute: Executor, ): Promise { switch (actionName) { @@ -134,7 +133,7 @@ function executeCollisionCorpusGenAction( function executeCollisionCorpusVizAction( actionName: string, - p: any, + p: ActionParams, execute: Executor, ): Promise { switch (actionName) { @@ -196,7 +195,7 @@ function executeCollisionCorpusVizAction( function executeCollisionKeywordsAction( actionName: string, - p: any, + p: ActionParams, execute: Executor, ): Promise { switch (actionName) { @@ -217,7 +216,7 @@ function executeCollisionKeywordsAction( tokens: [p.target, operation, ...(p.keywords ?? [])], }, flags: {}, - } as unknown as ParsedCommandParams); + } as unknown as CommandParams); } case "backfillCollisionKeywords": return execute(["keywords", "backfill"], { @@ -226,7 +225,7 @@ function executeCollisionKeywordsAction( llm: p.useLlm ?? false, force: p.force ?? false, }, - } as unknown as ParsedCommandParams); + } as unknown as CommandParams); case "buildCollisionNeighborhoods": return execute(["neighborhoods"], { args: {}, @@ -247,7 +246,7 @@ function executeCollisionKeywordsAction( function executeCollisionOptimizeCoreAction( actionName: string, - p: any, + p: ActionParams, execute: Executor, ): Promise { switch (actionName) { @@ -305,7 +304,7 @@ function executeCollisionOptimizeCoreAction( function executeCollisionOptimizePipelineAction( actionName: string, - p: any, + p: ActionParams, execute: Executor, ): Promise { switch (actionName) { @@ -348,7 +347,7 @@ function executeCollisionOptimizePipelineAction( function executeCollisionPreferencesAction( actionName: string, - p: any, + p: ActionParams, execute: Executor, ): Promise { switch (actionName) { @@ -386,7 +385,7 @@ export function executeCollisionAction( ): Promise { const execute: Executor = (commands, params) => commandExecutor(handlers, commands, params, context); - const p: any = "parameters" in action ? action.parameters : {}; + const p: ActionParams = "parameters" in action ? action.parameters : {}; if (CORPUS_GEN_ACTIONS.has(action.actionName)) { return executeCollisionCorpusGenAction(action.actionName, p, execute); diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts index b5708c7985..45bc24e119 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts @@ -7,7 +7,7 @@ import { AppAction, ActionContext, ActionResult, - ParsedCommandParams, + FlagDefinitions, } from "@typeagent/agent-sdk"; import { CommandHandlerTable, @@ -15,6 +15,7 @@ import { getCommandHandler, getFlagType, } from "@typeagent/agent-sdk/helpers/command"; +import { CommandParams } from "./actionParams.js"; type RunConfigCommandAction = ConfigAction & { actionName: "runConfigCommand"; @@ -125,7 +126,7 @@ function parseConfigFlags( const parsedFlags: Record = {}; for (const [name, definition] of Object.entries(flagDefs)) { const value = suppliedFlags[name]; - const type = getFlagType(definition as any) as + const type = getFlagType(definition as FlagDefinitions[string]) as | "string" | "number" | "boolean" @@ -140,7 +141,7 @@ function parseConfigFlags( if (!Array.isArray(value)) { throw new Error(`Config flag '${name}' expects an array.`); } - parsedFlags[name] = value.map((item: any) => + parsedFlags[name] = value.map((item: string | boolean) => parseConfigValue(item, type, name), ); } else { @@ -160,7 +161,7 @@ function parseConfigFlags( function getConfigCommandParams( action: RunConfigCommandAction, handlers: CommandHandlerTable, -): ParsedCommandParams | undefined { +): CommandParams | undefined { const { command, arguments: args = [], flags } = action.parameters; const handler = getCommandHandler(handlers, command.split(" ")); if (handler.parameters === undefined || handler.parameters === false) { @@ -193,7 +194,7 @@ function getConfigCommandParams( return { args: handler.parameters.args === undefined ? undefined : parsedArgs, flags: handler.parameters.flags === undefined ? undefined : parsedFlags, - } as ParsedCommandParams; + } as CommandParams; } function getCommandParams( @@ -201,7 +202,7 @@ function getCommandParams( commands: string[], args: Record, flags: Record, -): ParsedCommandParams | undefined { +): CommandParams | undefined { const handler = getCommandHandler(handlers, commands); if (handler.parameters === undefined || handler.parameters === false) { return undefined; @@ -209,7 +210,7 @@ function getCommandParams( return { args: handler.parameters.args === undefined ? undefined : args, flags: handler.parameters.flags === undefined ? undefined : flags, - } as ParsedCommandParams; + } as CommandParams; } export async function executeConfigAction( diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts index 799b28511d..a817122603 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts @@ -4,7 +4,6 @@ import { ActionContext, ActionResult, - ParsedCommandParams, TypeAgentAction, } from "@typeagent/agent-sdk"; import { @@ -13,7 +12,12 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConstructionAction } from "../schema/constructionActionSchema.js"; -import { actionParams, opt } from "./actionParams.js"; +import { + CommandParams, + ActionParams, + actionParams, + opt, +} from "./actionParams.js"; const STORE_CMDS: Record = { newConstructionStore: "new", @@ -23,10 +27,10 @@ const STORE_CMDS: Record = { function executeConstructionStoreAction( actionName: string, - p: any, + p: ActionParams, execute: ( commands: string[], - params?: ParsedCommandParams, + params?: CommandParams, ) => Promise, ): Promise { return execute([STORE_CMDS[actionName]], { @@ -40,7 +44,7 @@ export function executeConstructionAction( context: ActionContext, handlers: CommandHandlerTable, ): Promise { - const execute = (commands: string[], params?: ParsedCommandParams) => + const execute = (commands: string[], params?: CommandParams) => executeCommandFromHandlers(handlers, commands, params, context); const toggle = (commands: string[], enabled: boolean) => execute([...commands, enabled ? "on" : "off"]); @@ -68,12 +72,12 @@ export function executeConstructionAction( ...opt(p.part, "part"), ...opt(p.ids, "id"), }, - } as unknown as ParsedCommandParams); + } as unknown as CommandParams); case "importConstructions": return execute(["import"], { args: { ...opt(p.files, "file") }, flags: { extended: p.extended ?? false }, - } as unknown as ParsedCommandParams); + } as unknown as CommandParams); case "pruneConstructions": return execute(["prune"]); case "deleteConstruction": diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts index ae9d5f039d..e371130081 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts @@ -12,14 +12,14 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { FeedbackAction } from "../schema/feedbackActionSchema.js"; -import { actionParams, opt } from "./actionParams.js"; +import { CommandParams, actionParams, opt } from "./actionParams.js"; export function executeFeedbackAction( action: TypeAgentAction, context: ActionContext, handlers: CommandHandlerTable, ): Promise { - const execute = (commands: string[], params?: any) => + const execute = (commands: string[], params?: CommandParams) => executeCommandFromHandlers(handlers, commands, params, context); const p = actionParams(action); diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts index 233507a187..3d4dc52728 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts @@ -10,6 +10,7 @@ import { } from "../schema/historyActionSchema.js"; import { executeCommandFromHandlers } from "@typeagent/agent-sdk/helpers/command"; import { historyCommandHandlers } from "../handlers/historyCommandHandler.js"; +import { CommandParams } from "./actionParams.js"; export async function executeHistoryAction( action: AppAction, @@ -58,7 +59,7 @@ export async function executeHistoryAction( ), }, flags: undefined, - } as any, + } as unknown as CommandParams, context, ); break; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts index c9d68eca95..0fa368a2cf 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts @@ -4,7 +4,6 @@ import { ActionContext, ActionResult, - ParsedCommandParams, TypeAgentAction, } from "@typeagent/agent-sdk"; import { @@ -14,11 +13,12 @@ import { import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { indexCommandHandlers } from "../handlers/indexCommandHandler.js"; import { IndexAction } from "../schema/indexActionSchema.js"; +import { CommandParams } from "./actionParams.js"; type CommandExecutor = ( handlers: CommandHandlerTable, commands: string[], - params: ParsedCommandParams | undefined, + params: CommandParams | undefined, context: ActionContext, ) => Promise; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts index 21cb236cd0..8d907586ac 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts @@ -4,7 +4,6 @@ import { ActionContext, ActionResult, - ParsedCommandParams, TypeAgentAction, } from "@typeagent/agent-sdk"; import { @@ -16,6 +15,7 @@ import { MemoryAction, MemoryQuestionParameters, } from "../schema/memoryActionSchema.js"; +import { CommandParams } from "./actionParams.js"; function questionFlags(parameters: MemoryQuestionParameters) { return { @@ -53,7 +53,7 @@ export function executeMemoryAction( count: action.parameters.count ?? 25, distinct: action.parameters.distinct ?? false, }, - } as unknown as ParsedCommandParams, + } as unknown as CommandParams, context, ); case "searchMemory": diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts index b901a57010..74b8fae6ae 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts @@ -4,7 +4,6 @@ import { ActionContext, ActionResult, - ParsedCommandParams, TypeAgentAction, } from "@typeagent/agent-sdk"; import { @@ -13,11 +12,12 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { SystemDiagnosticsAction } from "../schema/systemDiagnosticsActionSchema.js"; +import { CommandParams } from "./actionParams.js"; type CommandExecutor = ( handlers: CommandHandlerTable, commands: string[], - params: ParsedCommandParams | undefined, + params: CommandParams | undefined, context: ActionContext, ) => Promise; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts index d19c208d87..d1d380f974 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts @@ -4,7 +4,6 @@ import { ActionContext, ActionResult, - ParsedCommandParams, TypeAgentAction, } from "@typeagent/agent-sdk"; import { @@ -13,14 +12,14 @@ import { } from "@typeagent/agent-sdk/helpers/command"; import { CommandHandlerContext } from "../../commandHandlerContext.js"; import { SystemOperationsAction } from "../schema/systemOperationsActionSchema.js"; -import { actionParams, opt } from "./actionParams.js"; +import { CommandParams, actionParams, opt } from "./actionParams.js"; export function executeSystemOperationsAction( action: TypeAgentAction, context: ActionContext, systemHandlers: CommandHandlerTable, ): Promise { - const execute = (commands: string[], params?: ParsedCommandParams) => + const execute = (commands: string[], params?: CommandParams) => executeCommandFromHandlers(systemHandlers, commands, params, context); const p = actionParams(action); @@ -39,7 +38,7 @@ export function executeSystemOperationsAction( ...opt(actionParameters, "parameters"), ...opt(p.naturalLanguage, "naturalLanguage"), }, - } as unknown as ParsedCommandParams); + } as unknown as CommandParams); } case "clearConsole": return execute(["clear"]); @@ -60,7 +59,7 @@ export function executeSystemOperationsAction( type: p.type ?? "text", inline: p.inline ?? false, }, - } as unknown as ParsedCommandParams); + } as unknown as CommandParams); case "exitTypeAgent": return execute(["exit"]); case "showCommandHelp": @@ -88,7 +87,7 @@ export function executeSystemOperationsAction( return execute(["trace"], { args: { ...opt(p.namespaces, "namespaces") }, flags: { clear: p.clear ?? false }, - } as unknown as ParsedCommandParams); + } as unknown as CommandParams); default: throw new Error( `Unknown system operations action: ${(action as SystemOperationsAction).actionName}`, From dbbb7e5418593829f84e77021afe3f8a96f395c0 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Mon, 17 Aug 2026 21:19:44 -0700 Subject: [PATCH 21/22] Cut import cycles in the action handlers, grandfather the rest build_ts failed the circular-dependency ratchet. The action handlers pulled the command tree in behind them, so every systemAgent -> actionHandler edge closed a cycle back through command.ts and internal.ts. - CommandHandlerContext is now a type-only import in every action handler, which is what it always was. This alone removed 15 cycles. - history, index, notification, and settings action handlers take their command table as a parameter instead of importing it, matching what the other handlers already did. history, notification, and settings also stop using processCommandNoLock, which catches internally and never rethrows, so their failures were reported to the caller as successful actions. - STATUS_NOTICE_DEFAULT_MESSAGE moves to its own leaf module so the action handler and the command handler can share it without an edge between them. Total cycles drop from 220 on main to 210 here. The ratchet keys cycles by their full path, though, and the remaining 87 keys are paths this PR already introduced before these fixes (verified: this branch adds no new keys versus the pre-fix merge commit). Only 2 of them involve the new action handlers at all; the other 85 are among pre-existing dispatcher core files whose paths shifted. Those are grandfathered in the exceptions file the repo documents as the mechanism for code-circular. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/context/system/action/actionParams.ts | 23 ++ .../system/action/collisionActionHandler.ts | 2 +- .../system/action/configActionHandler.ts | 2 +- .../action/constructionActionHandler.ts | 2 +- .../action/conversationActionHandler.ts | 2 +- .../system/action/copilotActionHandler.ts | 2 +- .../system/action/feedbackActionHandler.ts | 2 +- .../system/action/grammarActionHandler.ts | 2 +- .../system/action/historyActionHandler.ts | 113 ++++---- .../system/action/indexActionHandler.ts | 5 +- .../system/action/memoryActionHandler.ts | 2 +- .../action/notificationActionHandler.ts | 93 +++---- .../system/action/sessionActionHandler.ts | 2 +- .../system/action/settingsActionHandler.ts | 69 ++--- .../action/systemDiagnosticsActionHandler.ts | 2 +- .../action/systemOperationsActionHandler.ts | 2 +- .../system/handlers/notifyCommandHandler.ts | 4 +- .../context/system/notificationDefaults.ts | 8 + .../src/context/system/systemAgent.ts | 24 +- .../test/historyInsertActionHandler.spec.ts | 2 + .../code/circular-baseline-exception.json | 261 ++++++++++++++++++ 21 files changed, 454 insertions(+), 170 deletions(-) create mode 100644 ts/packages/dispatcher/dispatcher/src/context/system/notificationDefaults.ts diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts index 977c26bcb4..b4838d54de 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/actionParams.ts @@ -5,6 +5,10 @@ import type { ParameterDefinitions, ParsedCommandParams, } from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + getCommandHandler, +} from "@typeagent/agent-sdk/helpers/command"; // Parameters for a command resolved at action-dispatch time. The action // handlers pick the command by name, so its parameter definitions aren't known @@ -25,6 +29,25 @@ export function opt(value: T | undefined, key: string): Record { return value !== undefined ? { [key]: value } : {}; } +// Builds params for a command resolved by name, matching the shape its handler +// declares: a CommandHandlerNoParams must get `undefined`, and a handler that +// declares only `args` must not be handed a `flags` object. +export function getCommandParams( + handlers: CommandHandlerTable, + commands: string[], + args: Record = {}, + flags: Record = {}, +): CommandParams | undefined { + const handler = getCommandHandler(handlers, commands); + if (handler.parameters === undefined || handler.parameters === false) { + return undefined; + } + return { + args: handler.parameters.args === undefined ? undefined : args, + flags: handler.parameters.flags === undefined ? undefined : flags, + } as unknown as CommandParams; +} + // Reads `parameters` off an action union. Action schemas mix members that have // no `parameters` at all with members whose `parameters` is optional, so a // direct `action.parameters` doesn't type check and throws at runtime when the diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts index 9be2ae7a5d..481857533f 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/collisionActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { CollisionAction } from "../schema/collisionActionSchema.js"; import { CommandParams, ActionParams, opt } from "./actionParams.js"; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts index 45bc24e119..6d324b76b6 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/configActionHandler.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConfigAction } from "../schema/configActionSchema.js"; import { AppAction, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts index a817122603..491e05bbd5 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/constructionActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConstructionAction } from "../schema/constructionActionSchema.js"; import { CommandParams, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts index 77bb4d32b4..f4c0cc9965 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { processCommandNoLock } from "../../../command/command.js"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { ConversationAction } from "../schema/conversationActionSchema.js"; import { ActionContext, TypeAgentAction } from "@typeagent/agent-sdk"; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts index d0219a6c36..99d52893cd 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/copilotActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { CopilotAction } from "../schema/copilotActionSchema.js"; export function executeCopilotAction( diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts index e371130081..8bd83800a7 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/feedbackActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { FeedbackAction } from "../schema/feedbackActionSchema.js"; import { CommandParams, actionParams, opt } from "./actionParams.js"; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts index 7c3e060c08..642f6f629a 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/grammarActionHandler.ts @@ -15,7 +15,7 @@ import { createActionResultFromHtmlDisplay, } from "@typeagent/agent-sdk/helpers/action"; import { StoredGrammarRule } from "@typeagent/action-grammar"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { GrammarAction, ScanGrammarCollisionsAction, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts index 3d4dc52728..d90f745ba8 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/historyActionHandler.ts @@ -1,89 +1,72 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { ActionContext, AppAction } from "@typeagent/agent-sdk"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; -import { processCommandNoLock } from "../../../command/command.js"; +import { ActionContext, ActionResult, AppAction } from "@typeagent/agent-sdk"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { DeleteHistoryAction, HistoryAction, } from "../schema/historyActionSchema.js"; -import { executeCommandFromHandlers } from "@typeagent/agent-sdk/helpers/command"; -import { historyCommandHandlers } from "../handlers/historyCommandHandler.js"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; import { CommandParams } from "./actionParams.js"; +// The command table is passed in rather than imported: importing it here would +// make this module depend on the command tree, which depends back on the system +// agent that dispatches these actions. export async function executeHistoryAction( action: AppAction, context: ActionContext, -) { + handlers: CommandHandlerTable, +): Promise { const historyAction = action as HistoryAction; + const execute = (commands: string[], params?: CommandParams) => + executeCommandFromHandlers(handlers, commands, params, context); + switch (historyAction.actionName) { - case "deleteHistory": + case "deleteHistory": { const deleteAction = historyAction as DeleteHistoryAction; - await processCommandNoLock( - `@history delete ${deleteAction.parameters.messageNumber}`, - context.sessionContext.agentContext, - ); - break; + return execute(["delete"], { + args: { messageNumber: deleteAction.parameters.messageNumber }, + flags: undefined, + } as unknown as CommandParams); + } case "clearHistory": - await processCommandNoLock( - `@history clear`, - context.sessionContext.agentContext, - ); - break; + return execute(["clear"]); case "listHistory": - await processCommandNoLock( - `@history list`, - context.sessionContext.agentContext, - ); - break; + return execute(["list"]); case "saveHistory": - await executeCommandFromHandlers( - historyCommandHandlers, - ["save"], - { - args: { file: historyAction.parameters.file }, - flags: undefined, - }, - context, - ); - break; - case "insertHistory": - await executeCommandFromHandlers( - historyCommandHandlers, - ["insert"], - { - args: { - messages: JSON.parse( - historyAction.parameters.messagesJson, - ), - }, - flags: undefined, - } as unknown as CommandParams, - context, - ); - break; + return execute(["save"], { + args: { file: historyAction.parameters.file }, + flags: undefined, + } as unknown as CommandParams); + case "insertHistory": { + let messages: unknown; + try { + messages = JSON.parse(historyAction.parameters.messagesJson); + } catch (e) { + throw new Error( + `Invalid chat history JSON in messagesJson: ${e instanceof Error ? e.message : String(e)}`, + ); + } + return execute(["insert"], { + args: { messages }, + flags: undefined, + } as unknown as CommandParams); + } case "listHistoryEntities": - await executeCommandFromHandlers( - historyCommandHandlers, - ["entities", "list"], - { args: {}, flags: undefined }, - context, - ); - break; + return execute(["entities", "list"], { + args: {}, + flags: undefined, + } as unknown as CommandParams); case "deleteHistoryEntity": - await executeCommandFromHandlers( - historyCommandHandlers, - ["entities", "delete"], - { - args: { entityId: historyAction.parameters.entityId }, - flags: undefined, - }, - context, - ); - break; + return execute(["entities", "delete"], { + args: { entityId: historyAction.parameters.entityId }, + flags: undefined, + } as unknown as CommandParams); default: throw new Error(`Invalid action name: ${action.actionName}`); } - return undefined; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts index 0fa368a2cf..302a1d4203 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/indexActionHandler.ts @@ -10,8 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; -import { indexCommandHandlers } from "../handlers/indexCommandHandler.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { IndexAction } from "../schema/indexActionSchema.js"; import { CommandParams } from "./actionParams.js"; @@ -25,7 +24,7 @@ type CommandExecutor = ( export function executeIndexAction( action: TypeAgentAction, context: ActionContext, - handlers: CommandHandlerTable = indexCommandHandlers, + handlers: CommandHandlerTable, execute: CommandExecutor = executeCommandFromHandlers, ): Promise { switch (action.actionName) { diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts index 8d907586ac..6114073170 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/memoryActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { MemoryAction, MemoryQuestionParameters, diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts index 33ac99a540..3d3b58192a 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/notificationActionHandler.ts @@ -1,79 +1,70 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { ActionContext, AppAction } from "@typeagent/agent-sdk"; +import { ActionContext, ActionResult, AppAction } from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; import { NotificationAction, ShowNotificationsAction, } from "../schema/notificationActionSchema.js"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; -import { processCommandNoLock } from "../../../command/command.js"; -import { executeCommandFromHandlers } from "@typeagent/agent-sdk/helpers/command"; -import { - notifyCommandHandlers, - STATUS_NOTICE_DEFAULT_MESSAGE, -} from "../handlers/notifyCommandHandler.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { STATUS_NOTICE_DEFAULT_MESSAGE } from "../notificationDefaults.js"; +import { getCommandParams } from "./actionParams.js"; +// The command table is passed in rather than imported: importing it here would +// make this module depend on the command tree, which depends back on the system +// agent that dispatches these actions. Going through executeCommandFromHandlers +// also lets failures reach the caller, which processCommandNoLock swallows. export async function executeNotificationAction( action: AppAction, context: ActionContext, -) { + handlers: CommandHandlerTable, +): Promise { const notificationAction = action as NotificationAction; + const execute = ( + commands: string[], + args: Record = {}, + flags: Record = {}, + ) => + executeCommandFromHandlers( + handlers, + commands, + getCommandParams(handlers, commands, args, flags), + context, + ); + switch (notificationAction.actionName) { - case "showNotifications": + case "showNotifications": { const showAction = notificationAction as ShowNotificationsAction; - await processCommandNoLock( - `@notify show ${showAction.parameters.filter}`, - context.sessionContext.agentContext, - ); - break; + return execute(["show", showAction.parameters.filter]); + } case "showNotificationSummary": - await processCommandNoLock( - `@notify info`, - context.sessionContext.agentContext, - ); - break; + return execute(["info"]); case "clearNotifications": - await processCommandNoLock( - `@notify clear`, - context.sessionContext.agentContext, - ); - break; + return execute(["clear"]); case "testNotification": - await executeCommandFromHandlers( - notifyCommandHandlers, + return execute( ["test"], - { - args: { message: notificationAction.parameters.message }, - flags: { - mode: notificationAction.parameters.mode ?? "toast", - }, - }, - context, + { message: notificationAction.parameters.message }, + { mode: notificationAction.parameters.mode ?? "toast" }, ); - break; case "testStatusNotice": - await executeCommandFromHandlers( - notifyCommandHandlers, + return execute( ["status"], { - args: { - message: - notificationAction.parameters?.message ?? - STATUS_NOTICE_DEFAULT_MESSAGE, - }, - flags: { - level: - notificationAction.parameters?.level ?? "warning", - restart: - notificationAction.parameters?.restart ?? false, - }, + message: + notificationAction.parameters?.message ?? + STATUS_NOTICE_DEFAULT_MESSAGE, + }, + { + level: notificationAction.parameters?.level ?? "warning", + restart: notificationAction.parameters?.restart ?? false, }, - context, ); - break; default: throw new Error(`Invalid action name: ${action.actionName}`); } - return undefined; } diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts index 6b135852dc..85989593ac 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/sessionActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { SessionAction } from "../schema/sessionActionSchema.js"; export function executeSessionAction( diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts index 81866c9ef4..dd54cf4d72 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/settingsActionHandler.ts @@ -1,58 +1,59 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { AppAction, ActionContext } from "@typeagent/agent-sdk"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import { AppAction, ActionContext, ActionResult } from "@typeagent/agent-sdk"; +import { + CommandHandlerTable, + executeCommandFromHandlers, +} from "@typeagent/agent-sdk/helpers/command"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { UserSettingsAction } from "../schema/settingsActionSchema.js"; -import { processCommandNoLock } from "../../../command/command.js"; +import { getCommandParams } from "./actionParams.js"; +// The command table is passed in rather than imported: importing it here would +// make this module depend on the command tree, which depends back on the system +// agent that dispatches these actions. Going through executeCommandFromHandlers +// also lets failures reach the caller, which processCommandNoLock swallows. export async function executeSettingsAction( action: AppAction, context: ActionContext, -) { + handlers: CommandHandlerTable, +): Promise { const settingsAction = action as unknown as UserSettingsAction; + const execute = (commands: string[], args: Record = {}) => + executeCommandFromHandlers( + handlers, + commands, + getCommandParams(handlers, commands, args), + context, + ); + switch (settingsAction.actionName) { case "showSettings": - await processCommandNoLock( - "@settings show", - context.sessionContext.agentContext, - ); - break; + return execute(["show"]); case "resetSettings": - await processCommandNoLock( - "@settings reset", - context.sessionContext.agentContext, - ); - break; + return execute(["reset"]); case "setServerHidden": - await processCommandNoLock( - `@settings server hidden ${settingsAction.parameters.enable}`, - context.sessionContext.agentContext, - ); - break; + return execute(["server", "hidden"], { + value: String(settingsAction.parameters.enable), + }); case "setIdleTimeout": - await processCommandNoLock( - `@settings server idleTimeout ${settingsAction.parameters.seconds}`, - context.sessionContext.agentContext, - ); - break; + return execute(["server", "idleTimeout"], { + seconds: settingsAction.parameters.seconds, + }); case "setConversationResume": - await processCommandNoLock( - `@settings conversation resume ${settingsAction.parameters.enable}`, - context.sessionContext.agentContext, - ); - break; + return execute(["conversation", "resume"], { + value: String(settingsAction.parameters.enable), + }); case "setAutoComplete": - await processCommandNoLock( - `@settings ui autoComplete ${settingsAction.parameters.enable}`, - context.sessionContext.agentContext, - ); - break; + return execute(["ui", "autoComplete"], { + value: String(settingsAction.parameters.enable), + }); default: throw new Error( diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts index 74b8fae6ae..b5cea1b50d 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemDiagnosticsActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { SystemDiagnosticsAction } from "../schema/systemDiagnosticsActionSchema.js"; import { CommandParams } from "./actionParams.js"; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts index d1d380f974..d239aa1282 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/action/systemOperationsActionHandler.ts @@ -10,7 +10,7 @@ import { CommandHandlerTable, executeCommandFromHandlers, } from "@typeagent/agent-sdk/helpers/command"; -import { CommandHandlerContext } from "../../commandHandlerContext.js"; +import type { CommandHandlerContext } from "../../commandHandlerContext.js"; import { SystemOperationsAction } from "../schema/systemOperationsActionSchema.js"; import { CommandParams, actionParams, opt } from "./actionParams.js"; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts index 4f643135ac..69de03d1dc 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts @@ -17,6 +17,7 @@ import { ParsedCommandParams, } from "@typeagent/agent-sdk"; import { DispatcherName } from "../../dispatcher/dispatcherUtils.js"; +import { STATUS_NOTICE_DEFAULT_MESSAGE } from "../notificationDefaults.js"; class NotifyInfoCommandHandler implements CommandHandlerNoParams { description: string = "Shows the number of notifications available"; @@ -100,8 +101,7 @@ const NOTIFY_TEST_MODES = { type NotifyTestMode = keyof typeof NOTIFY_TEST_MODES; -export const STATUS_NOTICE_DEFAULT_MESSAGE = - "Dismissing this collapses it to the notification bell; click the bell to re-expand."; +export { STATUS_NOTICE_DEFAULT_MESSAGE } from "../notificationDefaults.js"; class NotifyTestCommandHandler implements CommandHandler { public readonly description = diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/notificationDefaults.ts b/ts/packages/dispatcher/dispatcher/src/context/system/notificationDefaults.ts new file mode 100644 index 0000000000..7a9c646b46 --- /dev/null +++ b/ts/packages/dispatcher/dispatcher/src/context/system/notificationDefaults.ts @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Shared by the `@notify status` command and the testStatusNotice action. +// It lives in its own module so the action handler can use it without importing +// the command tree, which depends back on the system agent. +export const STATUS_NOTICE_DEFAULT_MESSAGE = + "Dismissing this collapses it to the notification bell; click the bell to re-expand."; diff --git a/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts b/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts index 8dd3c95762..1aeee84c1e 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/system/systemAgent.ts @@ -261,19 +261,35 @@ function executeSystemAction( .config as CommandHandlerTable, }); case "system.notify": - return executeNotificationAction(action, context); + return executeNotificationAction( + action, + context, + getSystemHandlers().commands.notify as CommandHandlerTable, + ); case "system.history": - return executeHistoryAction(action, context); + return executeHistoryAction( + action, + context, + getSystemHandlers().commands.history as CommandHandlerTable, + ); case "system.grammar": return executeGrammarAction(action, context, getSystemHandlers()); case "system.settings": - return executeSettingsAction(action, context); + return executeSettingsAction( + action, + context, + getSystemHandlers().commands.settings as CommandHandlerTable, + ); case "system.log": return executeLogAction(action, context); case "system.help": return executeHelpAction(action, context); case "system.index": - return executeIndexAction(action, context); + return executeIndexAction( + action, + context, + getSystemHandlers().commands.index as CommandHandlerTable, + ); case "system.diagnostics": return executeSystemDiagnosticsAction( action, diff --git a/ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts b/ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts index 6e4d4f157a..4fa573a121 100644 --- a/ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts +++ b/ts/packages/dispatcher/dispatcher/test/historyInsertActionHandler.spec.ts @@ -3,6 +3,7 @@ import { expect, it, jest } from "@jest/globals"; import { executeHistoryAction } from "../src/context/system/action/historyActionHandler.js"; +import { historyCommandHandlers } from "../src/context/system/handlers/historyCommandHandler.js"; it("inserts the complete saved-history JSON shape", async () => { const imported: unknown[] = []; @@ -55,6 +56,7 @@ it("inserts the complete saved-history JSON shape", async () => { parameters: { messagesJson: JSON.stringify(input) }, }, context, + historyCommandHandlers, ); expect(imported).toEqual([input]); diff --git a/ts/tools/scripts/code/circular-baseline-exception.json b/ts/tools/scripts/code/circular-baseline-exception.json index e5e472520d..909431021e 100644 --- a/ts/tools/scripts/code/circular-baseline-exception.json +++ b/ts/tools/scripts/code/circular-baseline-exception.json @@ -32,6 +32,267 @@ }, { "key": "packages/agents/browserExtension/src/extension/views/knowledgeUtilities.ts > packages/agents/browserExtension/src/extension/views/services/cachedAnalyticsService.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/actionContext.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/command/commandReference.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/command/commandReference.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/agentProvider/agentProviderUtils.ts > packages/dispatcher/dispatcher/src/translation/actionSchemaFileCache.ts > packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/diagnosticsActionHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/explainCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/matchCollision.ts > packages/dispatcher/dispatcher/src/context/collisionResolution.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/matchCollision.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts > packages/dispatcher/dispatcher/src/translation/confirmTranslation.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/translation/actionSchemaFileCache.ts > packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts > packages/dispatcher/dispatcher/src/translation/confirmTranslation.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts > packages/dispatcher/dispatcher/src/translation/confirmTranslation.ts > packages/dispatcher/dispatcher/src/translation/actionTemplate.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts > packages/dispatcher/dispatcher/src/translation/confirmTranslation.ts > packages/dispatcher/dispatcher/src/translation/actionTemplate.ts > packages/dispatcher/dispatcher/src/translation/requestCompletion.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts > packages/dispatcher/dispatcher/src/translation/confirmTranslation.ts > packages/dispatcher/dispatcher/src/translation/actionTemplate.ts > packages/dispatcher/dispatcher/src/translation/requestCompletion.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/translation/actionSchemaFileCache.ts > packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/matchCommandHandler.ts > packages/dispatcher/dispatcher/src/translation/matchRequest.ts > packages/dispatcher/dispatcher/src/translation/translateRequest.ts > packages/dispatcher/dispatcher/src/translation/interpretRequest.ts > packages/dispatcher/dispatcher/src/translation/confirmTranslation.ts > packages/dispatcher/dispatcher/src/translation/actionTemplate.ts > packages/dispatcher/dispatcher/src/translation/requestCompletion.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts > packages/dispatcher/dispatcher/src/reasoning/claude.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts > packages/dispatcher/dispatcher/src/reasoning/claude.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts > packages/dispatcher/dispatcher/src/reasoning/copilot.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/reasonCommandHandler.ts > packages/dispatcher/dispatcher/src/reasoning/copilot.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/requestCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/requestCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/context/dispatcher/handlers/translateCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/dispatcher/dispatcherAgent.ts > packages/dispatcher/dispatcher/src/search/search.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/action/conversationActionHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/actionCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/actionCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/translation/actionSchemaFileCache.ts > packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/actionCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCorpusHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCorpusHandlers.ts > packages/dispatcher/dispatcher/src/translation/translationProbeRunner.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionNeighborhoodHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionNeighborhoodHandlers.ts > packages/dispatcher/dispatcher/src/neighborhoods/optimize/util.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionOptimizeHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/translation/actionSchemaFileCache.ts > packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionOptimizeHandlers.ts > packages/dispatcher/dispatcher/src/neighborhoods/optimize/runPipeline.ts > packages/dispatcher/dispatcher/src/neighborhoods/optimize/sandboxProvider.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionCommandHandlers.ts > packages/dispatcher/dispatcher/src/context/system/handlers/collisionPreferenceHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/configCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/constructionCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/constructionCommandHandlers.ts > packages/dispatcher/dispatcher/src/utils/commandHandlerUtils.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/conversationCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/copilotCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/copilotCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/debugCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/displayCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/envCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/feedbackCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/grammarCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/helpCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/historyCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/indexCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/notifyCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/openCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/portsCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/randomCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/randomCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/runScriptCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/runScriptCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/sessionCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/settingsCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/settingsCommandHandlers.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/tokenCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts > packages/dispatcher/dispatcher/src/context/system/handlers/traceCommandHandler.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/context/inlineAgentProvider.ts > packages/dispatcher/dispatcher/src/context/system/systemAgent.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/dispatcher.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/dispatcher.ts > packages/dispatcher/dispatcher/src/command/completion.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/dispatcher.ts > packages/dispatcher/dispatcher/src/command/completion.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/dispatcher.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts > packages/dispatcher/dispatcher/src/dispatcher.ts" + }, + { + "key": "packages/dispatcher/dispatcher/src/translation/actionSchemaFileCache.ts > packages/dispatcher/dispatcher/src/execute/pendingActions.ts > packages/dispatcher/dispatcher/src/context/appAgentManager.ts > packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts > packages/dispatcher/dispatcher/src/command/command.ts > packages/dispatcher/dispatcher/src/execute/actionHandlers.ts > packages/dispatcher/dispatcher/src/execute/activityContext.ts > packages/dispatcher/dispatcher/src/internal.ts" } ] } From 44c6594f913cf6b16dc9d1aaa9e622d48ff21b12 Mon Sep 17 00:00:00 2001 From: Tal Zaccai Date: Wed, 19 Aug 2026 12:30:21 -0700 Subject: [PATCH 22/22] Don't require the platform-dependent osNotifications host in the coverage gate The host floor I added listed osNotifications, but that agent is defaultEnabled: false and platform-dependent, so it enumerates on Windows and not on Linux. build_ts passed on Windows and macOS and failed on both Linux runners, twice (the retry confirmed it wasn't flaky). Require only the hosts that are always present and lower the endpoint floor to 385, which still catches any of them dropping out: Linux enumerates 391 without osNotifications, and losing a real host like browser (33) or localPlayer (16) trips it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../test/commandActionCoverage.spec.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts b/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts index f12586953c..42502aeb50 100644 --- a/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts +++ b/ts/tools/actionBrowser/test/commandActionCoverage.spec.ts @@ -17,19 +17,27 @@ let catalog: Catalog; // "the set of gaps is empty", which stays true if a host disappears from the // enumeration entirely, so pin the hosts and a lower bound on the endpoint // count as well. Both are floors: adding agents or endpoints won't fail here. -const EXPECTED_HOSTS = [ +// +// osNotifications is deliberately absent: it is `defaultEnabled: false` and +// platform-dependent, so it enumerates on some machines and not others (it is +// missing on Linux CI). Requiring it here fails the build on the environments +// where it legitimately isn't there. +const REQUIRED_HOSTS = [ "browser", "calendar", "dispatcher", "email", "greeting", "localPlayer", - "osNotifications", "player", "powershell", "system", ]; -const MIN_COMMAND_ENDPOINTS = 388; +// Total across REQUIRED_HOSTS is 391 (393 including osNotifications' 2). The +// margin below absorbs environment-dependent agents while still catching any +// required host dropping out: the smallest of them, greeting, is 1 endpoint, +// but losing a real one like localPlayer (16) or browser (33) trips this. +const MIN_COMMAND_ENDPOINTS = 385; describe("command action coverage", () => { beforeAll(async () => { @@ -39,7 +47,7 @@ describe("command action coverage", () => { it("enumerates every command host", () => { const hosts = [...new Set(catalog.commands.map((c) => c.host))]; expect(hosts.sort()).toEqual( - expect.arrayContaining(EXPECTED_HOSTS.slice().sort()), + expect.arrayContaining(REQUIRED_HOSTS.slice().sort()), ); expect(catalog.counts.commandEndpoints).toBeGreaterThanOrEqual( MIN_COMMAND_ENDPOINTS,