diff --git a/ts/packages/actionGrammar/src/generation/index.ts b/ts/packages/actionGrammar/src/generation/index.ts index e337ef5e0b..e2ab3b9be6 100644 --- a/ts/packages/actionGrammar/src/generation/index.ts +++ b/ts/packages/actionGrammar/src/generation/index.ts @@ -5,6 +5,7 @@ * Grammar generation module for creating Action Grammar rules from schemas and examples */ +import { ParsedActionSchema } from "@typeagent/action-schema"; import { Cardinal } from "../builtInEntities.js"; export { @@ -44,6 +45,7 @@ export { export { loadSchemaInfo, + getSchemaInfoFromParsedSchema, SchemaInfo, ActionInfo, ParameterValidationInfo, @@ -65,7 +67,10 @@ export { } from "./grammarWarmer.js"; import { ClaudeGrammarGenerator, GrammarAnalysis } from "./grammarGenerator.js"; -import { loadSchemaInfo } from "./schemaReader.js"; +import { + getSchemaInfoFromParsedSchema, + loadSchemaInfo, +} from "./schemaReader.js"; import { GrammarTestCase } from "./testTypes.js"; import { loadGrammarRulesNoThrow } from "../grammarLoader.js"; import { compileGrammarToNFA } from "../nfaCompiler.js"; @@ -199,7 +204,9 @@ export interface CachePopulationRequest { parameters: Record; }; // Path to the .pas.json schema file for validation info - schemaPath: string; + schemaPath?: string; + // Already-loaded parsed action schema (preferred over schemaPath) + parsedSchema?: ParsedActionSchema; } /** @@ -276,7 +283,17 @@ export async function populateCache( ): Promise { try { // Load schema information - const schemaInfo = loadSchemaInfo(request.schemaPath); + if (!request.parsedSchema && !request.schemaPath) { + throw new Error( + "Either parsedSchema or schemaPath must be provided", + ); + } + const schemaInfo = request.parsedSchema + ? getSchemaInfoFromParsedSchema( + request.schemaName, + request.parsedSchema, + ) + : loadSchemaInfo(request.schemaPath!); // Validate that parameter values appear in the request. // If a value was inferred by the LLM (not in the request), strip it diff --git a/ts/packages/actionGrammar/src/generation/schemaReader.ts b/ts/packages/actionGrammar/src/generation/schemaReader.ts index 188a38639d..58628a9014 100644 --- a/ts/packages/actionGrammar/src/generation/schemaReader.ts +++ b/ts/packages/actionGrammar/src/generation/schemaReader.ts @@ -4,6 +4,7 @@ import fs from "fs"; import { fromJSONParsedActionSchema, + ParsedActionSchema, ParsedActionSchemaJSON, ActionSchemaTypeDefinition, ParamSpec, @@ -58,6 +59,16 @@ export function loadSchemaInfo(pasJsonPath: string): SchemaInfo { // Extract schema name from path - use path.basename to avoid regex issues const fileName = pasJsonPath.split(/[/\\]/).pop() || ""; const schemaName = fileName.replace(/\.pas\.json$/, "") || "unknown"; + return getSchemaInfoFromParsedSchema(schemaName, parsedSchema); +} + +/** + * Extract schema info from an already-loaded ParsedActionSchema + */ +export function getSchemaInfoFromParsedSchema( + schemaName: string, + parsedSchema: ParsedActionSchema, +): SchemaInfo { const actions = new Map(); const entityTypes = new Set(); diff --git a/ts/packages/actionGrammar/src/grammarMetadata.ts b/ts/packages/actionGrammar/src/grammarMetadata.ts index 6b12e4233d..6827ca6a06 100644 --- a/ts/packages/actionGrammar/src/grammarMetadata.ts +++ b/ts/packages/actionGrammar/src/grammarMetadata.ts @@ -1,77 +1,56 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import fs from "fs"; -import { - fromJSONParsedActionSchema, - ParsedActionSchemaJSON, - ActionSchemaTypeDefinition, -} from "@typeagent/action-schema"; +import { ParsedActionSchema } from "@typeagent/action-schema"; import { Grammar } from "./grammarTypes.js"; /** - * Enrich a Grammar with checked variable metadata from a .pas.json schema file + * Enrich a Grammar with checked variable metadata from a parsed action schema * - * Reads the schema file to find parameters with checked_wildcard paramSpec + * Finds parameters with checked_wildcard paramSpec * and adds their variable names to grammar.checkedVariables * * @param grammar The grammar to enrich - * @param schemaPath Path to the .pas.json file + * @param parsedSchema The parsed action schema * @returns The enriched grammar (modifies in place and returns for chaining) */ export function enrichGrammarWithCheckedVariables( grammar: Grammar, - schemaPath: string, + parsedSchema: ParsedActionSchema, ): Grammar { - try { - const jsonContent = fs.readFileSync(schemaPath, "utf8"); - const json: ParsedActionSchemaJSON = JSON.parse(jsonContent); - const parsedSchema = fromJSONParsedActionSchema(json); + const checkedVariables = new Set(); - const checkedVariables = new Set(); + // Process each action to find parameters with checked_wildcard paramSpec + for (const actionDef of parsedSchema.actionSchemas.values()) { + const paramSpecs = actionDef.paramSpecs; - // Process each action to find parameters with checked_wildcard paramSpec - for (const [ - _actionName, - actionDef, - ] of parsedSchema.actionSchemas.entries()) { - const paramSpecs = (actionDef as ActionSchemaTypeDefinition) - .paramSpecs; - - if (!paramSpecs || typeof paramSpecs !== "object") { - continue; - } + if (!paramSpecs || typeof paramSpecs !== "object") { + continue; + } - // Find all parameters with checked_wildcard paramSpec - for (const [paramName, paramSpec] of Object.entries(paramSpecs)) { - if (paramSpec === "checked_wildcard") { - // Add the parameter name as a checked variable - // Also handle array element specs (e.g., "artists.*" -> "artist") - if (paramName.endsWith(".*")) { - const baseName = paramName.slice(0, -2); - // Convert plural to singular for grammar variable names - const singularName = getSingularVariableName(baseName); - checkedVariables.add(singularName); - } else { - checkedVariables.add(paramName); - } + // Find all parameters with checked_wildcard paramSpec + for (const [paramName, paramSpec] of Object.entries(paramSpecs)) { + if (paramSpec === "checked_wildcard") { + // Add the parameter name as a checked variable + // Also handle array element specs (e.g., "artists.*" -> "artist") + if (paramName.endsWith(".*")) { + const baseName = paramName.slice(0, -2); + // Convert plural to singular for grammar variable names + const singularName = getSingularVariableName(baseName); + checkedVariables.add(singularName); + } else { + checkedVariables.add(paramName); } } } + } - // Add to grammar - if (checkedVariables.size > 0) { - grammar.checkedVariables = checkedVariables; - } - - return grammar; - } catch (error) { - // If schema file doesn't exist or can't be read, return grammar unchanged - console.warn( - `Could not read schema file ${schemaPath} for checked variable metadata: ${error}`, - ); - return grammar; + // Add to grammar + if (checkedVariables.size > 0) { + grammar.checkedVariables = checkedVariables; } + + return grammar; } /** diff --git a/ts/packages/agentSdk/src/agentInterface.ts b/ts/packages/agentSdk/src/agentInterface.ts index 6f1b5868d7..0711a4210b 100644 --- a/ts/packages/agentSdk/src/agentInterface.ts +++ b/ts/packages/agentSdk/src/agentInterface.ts @@ -63,9 +63,9 @@ export type GrammarContent = { format: GrammarFormat; content: string }; export type SchemaManifest = { description: string; schemaType: string | SchemaTypeNames; // string if there are only action schemas - schemaFile: string | SchemaContent; - compiledSchemaFile?: string; // path to .pas.json file for grammar generation metadata extraction - grammarFile?: string | GrammarContent; + schemaFile: string | SchemaContent; // path relative to the manifest file (resolved to absolute at load time) + originalSchemaFile?: string; // path to the original .ts schema source for code paths not yet converted to use .pas format (relative to the manifest file) + grammarFile?: string | GrammarContent; // path relative to the manifest file (resolved to absolute at load time) injected?: boolean; // whether the translator is injected into other domains, default is false cached?: boolean; // whether the translator's action should be cached, default is true streamingActions?: string[]; diff --git a/ts/packages/agents/browser/package.json b/ts/packages/agents/browser/package.json index cd50e94089..351d9c193f 100644 --- a/ts/packages/agents/browser/package.json +++ b/ts/packages/agents/browser/package.json @@ -147,6 +147,7 @@ "build": { "dependsOn": [ "^build", + "asc", "build:extension", "build:views", "tsc:agent", diff --git a/ts/packages/agents/browser/src/agent/manifest.json b/ts/packages/agents/browser/src/agent/manifest.json index 30bcf4f9b3..37130d6144 100644 --- a/ts/packages/agents/browser/src/agent/manifest.json +++ b/ts/packages/agents/browser/src/agent/manifest.json @@ -14,8 +14,8 @@ }, "schema": { "description": "Browser agent that allows you control browser windows and perform actions such as web browsing (opening, closing, reading pages), opening a new tab, closing a tab, scrolling, zooming and navigating to a specific URL.", - "schemaFile": "./browserActionSchema.mts", - "compiledSchemaFile": "agents/browser/dist/agent/browserSchema.pas.json", + "originalSchemaFile": "./browserActionSchema.mts", + "schemaFile": "../../dist/agent/browserSchema.pas.json", "grammarFile": "../../dist/agent/browserSchema.ag.json", "schemaType": { "action": "BrowserActions", diff --git a/ts/packages/agents/calendar/src/calendarManifest.json b/ts/packages/agents/calendar/src/calendarManifest.json index 8be783f981..f8bf8b2548 100644 --- a/ts/packages/agents/calendar/src/calendarManifest.json +++ b/ts/packages/agents/calendar/src/calendarManifest.json @@ -3,8 +3,8 @@ "description": "Agent integration with MS Graph's calendar", "schema": { "description": "Calendar agent that keeps track of important dates and events. Use it to schedule appointments, set reminders, and organize activities.", - "schemaFile": "./calendarActionsSchemaV3.ts", - "compiledSchemaFile": "agents/calendar/dist/calendarSchema.pas.json", + "originalSchemaFile": "./calendarActionsSchemaV3.ts", + "schemaFile": "../dist/calendarSchema.pas.json", "grammarFile": "../dist/calendarSchema.ag.json", "schemaType": "CalendarActionV3" } diff --git a/ts/packages/agents/code/src/codeManifest.json b/ts/packages/agents/code/src/codeManifest.json index 214efbdb77..49284f9799 100644 --- a/ts/packages/agents/code/src/codeManifest.json +++ b/ts/packages/agents/code/src/codeManifest.json @@ -4,8 +4,8 @@ "defaultEnabled": false, "schema": { "description": "Code agent helps you with productivity in using an editor and performing actions like creating files, editor customization, writing code, intelligent code suggestions, real-time error detection, debugging, and source control tasks etc.", - "schemaFile": "./codeActionsSchema.ts", - "compiledSchemaFile": "agents/code/dist/codeSchema.pas.json", + "originalSchemaFile": "./codeActionsSchema.ts", + "schemaFile": "../dist/codeSchema.pas.json", "schemaType": { "action": "CodeActions", "activity": "CodeActivity" @@ -15,48 +15,48 @@ "code-debug": { "schema": { "description": "Code agent that helps you debug code including handling actions like showing the debug panel, adding/toggling breakpoints, stepping in/out of code etc.", - "schemaFile": "./vscode/debugActionsSchema.ts", - "compiledSchemaFile": "agents/code/dist/debugSchema.pas.json", + "originalSchemaFile": "./vscode/debugActionsSchema.ts", + "schemaFile": "../dist/debugSchema.pas.json", "schemaType": "CodeDebugActions" } }, "code-display": { "schema": { "description": "Code agent that helps you work with display keyboard bindings, Zoom in, Zoom out, do text search and replace, show extensions etc.", - "schemaFile": "./vscode/displayActionsSchema.ts", - "compiledSchemaFile": "agents/code/dist/displaySchema.pas.json", + "originalSchemaFile": "./vscode/displayActionsSchema.ts", + "schemaFile": "../dist/displaySchema.pas.json", "schemaType": "CodeDisplayActions" } }, "code-general": { "schema": { "description": "Code agent that helps you perform actions like finding a file, go to a symbol or a line in a file, Open new vscode window, show the command palette, user settings json etc.", - "schemaFile": "./vscode/generalActionsSchema.ts", - "compiledSchemaFile": "agents/code/dist/generalSchema.pas.json", + "originalSchemaFile": "./vscode/generalActionsSchema.ts", + "schemaFile": "../dist/generalSchema.pas.json", "schemaType": "CodeGeneralActions" } }, "code-editor": { "schema": { "description": "Code agent that helps you perform vscode editor actions like create a new file, go to a reference, reveal a declaration, clipboard copy or paste, add a comment line etc.", - "schemaFile": "./vscode/editorCodeActionsSchema.ts", - "compiledSchemaFile": "agents/code/dist/editorSchema.pas.json", + "originalSchemaFile": "./vscode/editorCodeActionsSchema.ts", + "schemaFile": "../dist/editorSchema.pas.json", "schemaType": "EditorCodeActions" } }, "code-workbench": { "schema": { "description": "Code agent that helps you perform vscode workbench actions like open a file, close a file etc.", - "schemaFile": "./vscode/workbenchCommandActionsSchema.ts", - "compiledSchemaFile": "agents/code/dist/workbenchSchema.pas.json", + "originalSchemaFile": "./vscode/workbenchCommandActionsSchema.ts", + "schemaFile": "../dist/workbenchSchema.pas.json", "schemaType": "CodeWorkbenchActions" } }, "code-extension": { "schema": { "description": "Code agent that helps you perform vscode extension actions like show, install, update, enable, disable, uninstall extensions etc.", - "schemaFile": "./vscode/extensionsActionsSchema.ts", - "compiledSchemaFile": "agents/code/dist/extensionSchema.pas.json", + "originalSchemaFile": "./vscode/extensionsActionsSchema.ts", + "schemaFile": "../dist/extensionSchema.pas.json", "schemaType": "CodeWorkbenchExtensionActions" } } diff --git a/ts/packages/agents/desktop/src/manifest.json b/ts/packages/agents/desktop/src/manifest.json index cc23bc6dda..43b2e3aa4e 100644 --- a/ts/packages/agents/desktop/src/manifest.json +++ b/ts/packages/agents/desktop/src/manifest.json @@ -4,8 +4,8 @@ "defaultEnabled": false, "schema": { "description": "Desktop agent that allows you to manage the programs running on a computer, change Windows settings, control the desktop environment, and perform actions such as opening a file, closing a window, tiling windows, launching a program, maximizing windows, adjusting display settings, managing privacy settings, and controlling system features.", - "schemaFile": "./actionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/desktopSchema.pas.json", + "originalSchemaFile": "./actionsSchema.ts", + "schemaFile": "../dist/desktopSchema.pas.json", "grammarFile": "../dist/desktopSchema.ag.json", "schemaType": "DesktopActions" }, @@ -13,8 +13,8 @@ "desktop-display": { "schema": { "description": "Desktop agent for display and screen settings including night light, color temperature, scaling, orientation, and rotation lock.", - "schemaFile": "./windows/displayActionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/displaySchema.pas.json", + "originalSchemaFile": "./windows/displayActionsSchema.ts", + "schemaFile": "../dist/displaySchema.pas.json", "grammarFile": "../dist/displaySchema.ag.json", "schemaType": "DesktopDisplayActions" } @@ -22,8 +22,8 @@ "desktop-personalization": { "schema": { "description": "Desktop agent for personalization settings including transparency effects, title bar colors, and high contrast themes.", - "schemaFile": "./windows/personalizationActionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/personalizationSchema.pas.json", + "originalSchemaFile": "./windows/personalizationActionsSchema.ts", + "schemaFile": "../dist/personalizationSchema.pas.json", "grammarFile": "../dist/personalizationSchema.ag.json", "schemaType": "DesktopPersonalizationActions" } @@ -31,8 +31,8 @@ "desktop-taskbar": { "schema": { "description": "Desktop agent for taskbar settings including auto-hide, alignment, task view, widgets, badges, and system clock options.", - "schemaFile": "./windows/taskbarActionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/taskbarSchema.pas.json", + "originalSchemaFile": "./windows/taskbarActionsSchema.ts", + "schemaFile": "../dist/taskbarSchema.pas.json", "grammarFile": "../dist/taskbarSchema.ag.json", "schemaType": "DesktopTaskbarActions" } @@ -40,8 +40,8 @@ "desktop-input": { "schema": { "description": "Desktop agent for mouse and touchpad settings including cursor speed, scroll lines, button configuration, pointer precision, and touchpad controls.", - "schemaFile": "./windows/inputActionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/inputSchema.pas.json", + "originalSchemaFile": "./windows/inputActionsSchema.ts", + "schemaFile": "../dist/inputSchema.pas.json", "grammarFile": "../dist/inputSchema.ag.json", "schemaType": "DesktopInputActions" } @@ -49,8 +49,8 @@ "desktop-privacy": { "schema": { "description": "Desktop agent for privacy settings to manage microphone, camera, and location access for applications.", - "schemaFile": "./windows/privacyActionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/privacySchema.pas.json", + "originalSchemaFile": "./windows/privacyActionsSchema.ts", + "schemaFile": "../dist/privacySchema.pas.json", "grammarFile": "../dist/privacySchema.ag.json", "schemaType": "DesktopPrivacyActions" } @@ -58,8 +58,8 @@ "desktop-power": { "schema": { "description": "Desktop agent for power management settings including battery saver and power mode configuration.", - "schemaFile": "./windows/powerActionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/powerSchema.pas.json", + "originalSchemaFile": "./windows/powerActionsSchema.ts", + "schemaFile": "../dist/powerSchema.pas.json", "grammarFile": "../dist/powerSchema.ag.json", "schemaType": "DesktopPowerActions" } @@ -67,8 +67,8 @@ "desktop-system": { "schema": { "description": "Desktop agent for system settings including accessibility features, file explorer options, time settings, focus assist, multi-monitor configuration, and other system-level controls.", - "schemaFile": "./windows/systemActionsSchema.ts", - "compiledSchemaFile": "agents/desktop/dist/systemSchema.pas.json", + "originalSchemaFile": "./windows/systemActionsSchema.ts", + "schemaFile": "../dist/systemSchema.pas.json", "grammarFile": "../dist/systemSchema.ag.json", "schemaType": "DesktopSystemActions" } diff --git a/ts/packages/agents/email/src/emailManifest.json b/ts/packages/agents/email/src/emailManifest.json index c1d4c9a80e..9c44daff05 100644 --- a/ts/packages/agents/email/src/emailManifest.json +++ b/ts/packages/agents/email/src/emailManifest.json @@ -3,8 +3,8 @@ "description": "Agent integration with MS Graph's email", "schema": { "description": "Email agent helps manage email messages. Use it to send, reply, forward, find messages etc.", - "schemaFile": "./emailActionsSchema.ts", - "compiledSchemaFile": "agents/email/dist/emailSchema.pas.json", + "originalSchemaFile": "./emailActionsSchema.ts", + "schemaFile": "../dist/emailSchema.pas.json", "schemaType": "EmailAction" } } diff --git a/ts/packages/agents/image/src/imageManifest.json b/ts/packages/agents/image/src/imageManifest.json index 2b341e196c..61cfe02b6a 100644 --- a/ts/packages/agents/image/src/imageManifest.json +++ b/ts/packages/agents/image/src/imageManifest.json @@ -3,8 +3,8 @@ "description": "Agent to create AI images", "schema": { "description": "Image agent that creates images using AI image modes.", - "schemaFile": "./imageActionSchema.ts", - "compiledSchemaFile": "agents/image/dist/imageSchema.pas.json", + "originalSchemaFile": "./imageActionSchema.ts", + "schemaFile": "../dist/imageSchema.pas.json", "schemaType": "ImageAction" } } diff --git a/ts/packages/agents/list/src/listManifest.json b/ts/packages/agents/list/src/listManifest.json index 265b731be5..0b7495e0c4 100644 --- a/ts/packages/agents/list/src/listManifest.json +++ b/ts/packages/agents/list/src/listManifest.json @@ -3,8 +3,8 @@ "description": "Agent to create and manage lists", "schema": { "description": "List agent with actions to create lists, show list items, add and remove list items", - "schemaFile": "./listSchema.ts", - "compiledSchemaFile": "agents/list/dist/listSchema.pas.json", + "originalSchemaFile": "./listSchema.ts", + "schemaFile": "../dist/listSchema.pas.json", "grammarFile": "../dist/listSchema.ag.json", "schemaType": { "action": "ListAction", diff --git a/ts/packages/agents/photo/src/photoManifest.json b/ts/packages/agents/photo/src/photoManifest.json index 4871d237fc..eefaae62e9 100644 --- a/ts/packages/agents/photo/src/photoManifest.json +++ b/ts/packages/agents/photo/src/photoManifest.json @@ -3,8 +3,8 @@ "description": "Agent to take and upload photos", "schema": { "description": "Photo agent that helps the user provide images to the system either by taking pictures or uploading existing images.", - "schemaFile": "./photoSchema.ts", - "compiledSchemaFile": "agents/photo/dist/photoSchema.pas.json", + "originalSchemaFile": "./photoSchema.ts", + "schemaFile": "../dist/photoSchema.pas.json", "schemaType": "PhotoAction" } } diff --git a/ts/packages/agents/player/src/agent/playerManifest.json b/ts/packages/agents/player/src/agent/playerManifest.json index e34f482c49..d72f887f47 100644 --- a/ts/packages/agents/player/src/agent/playerManifest.json +++ b/ts/packages/agents/player/src/agent/playerManifest.json @@ -3,8 +3,8 @@ "description": "Agent to play music", "schema": { "description": "Music Player agent that lets you search for, play and control music.", - "schemaFile": "./playerSchema.ts", - "compiledSchemaFile": "agents/player/dist/agent/playerSchema.pas.json", + "originalSchemaFile": "./playerSchema.ts", + "schemaFile": "../../dist/agent/playerSchema.pas.json", "grammarFile": "../../dist/agent/playerSchema.ag.json", "schemaType": { "action": "PlayerActions", diff --git a/ts/packages/agents/playerLocal/src/agent/localPlayerManifest.json b/ts/packages/agents/playerLocal/src/agent/localPlayerManifest.json index a9feb11294..8a6a9d9999 100644 --- a/ts/packages/agents/playerLocal/src/agent/localPlayerManifest.json +++ b/ts/packages/agents/playerLocal/src/agent/localPlayerManifest.json @@ -3,9 +3,9 @@ "description": "Agent to play local music files", "schema": { "description": "Local Music Player agent that lets you play and control local audio files.", - "schemaFile": "./localPlayerSchema.ts", - "compiledSchemaFile": "agents/playerLocal/dist/agent/localPlayerSchema.pas.json", - "grammarFile": "agents/playerLocal/dist/agent/localPlayerSchema.ag.json", + "originalSchemaFile": "./localPlayerSchema.ts", + "schemaFile": "../../dist/agent/localPlayerSchema.pas.json", + "grammarFile": "../../dist/agent/localPlayerSchema.ag.json", "schemaType": { "action": "LocalPlayerActions", "entity": "LocalPlayerEntities" diff --git a/ts/packages/agents/taskflow/manifest.json b/ts/packages/agents/taskflow/manifest.json index b6dbc921b4..c0a51827ca 100644 --- a/ts/packages/agents/taskflow/manifest.json +++ b/ts/packages/agents/taskflow/manifest.json @@ -4,8 +4,8 @@ "defaultEnabled": true, "schema": { "description": "Task flows compiled from Claude recordings. Say 'learn: [task]' to teach new flows.", - "schemaFile": "./src/schema/userActions.mts", - "compiledSchemaFile": "agents/taskflow/dist/taskflowSchema.pas.json", + "originalSchemaFile": "./src/schema/userActions.mts", + "schemaFile": "./dist/taskflowSchema.pas.json", "grammarFile": "./dist/taskflowSchema.ag.json", "schemaType": "TaskFlowActions" }, diff --git a/ts/packages/agents/utility/manifest.json b/ts/packages/agents/utility/manifest.json index 8cbee10437..4111c70c37 100644 --- a/ts/packages/agents/utility/manifest.json +++ b/ts/packages/agents/utility/manifest.json @@ -4,8 +4,8 @@ "defaultEnabled": true, "schema": { "description": "Utility operations: search the web, fetch page content, read and write files", - "schemaFile": "./src/utilitySchema.mts", - "compiledSchemaFile": "agents/utility/dist/utilitySchema.pas.json", + "originalSchemaFile": "./src/utilitySchema.mts", + "schemaFile": "./dist/utilitySchema.pas.json", "grammarFile": "./dist/utilitySchema.ag.json", "schemaType": "UtilityAction" } diff --git a/ts/packages/agents/video/src/videoManifest.json b/ts/packages/agents/video/src/videoManifest.json index 94ba291675..c43cea5c47 100644 --- a/ts/packages/agents/video/src/videoManifest.json +++ b/ts/packages/agents/video/src/videoManifest.json @@ -3,8 +3,8 @@ "description": "Agent to create AI videos", "schema": { "description": "Video agent that creates videos using AI text to video modes.", - "schemaFile": "./videoActionSchema.ts", - "compiledSchemaFile": "agents/video/dist/videoSchema.pas.json", + "originalSchemaFile": "./videoActionSchema.ts", + "schemaFile": "../dist/videoSchema.pas.json", "schemaType": "VideoAction" } } diff --git a/ts/packages/agents/weather/src/weatherManifest.json b/ts/packages/agents/weather/src/weatherManifest.json index 483352a196..faf7ab5fa5 100644 --- a/ts/packages/agents/weather/src/weatherManifest.json +++ b/ts/packages/agents/weather/src/weatherManifest.json @@ -3,8 +3,8 @@ "description": "Agent to get weather information including current conditions, forecasts, and alerts", "schema": { "description": "Weather agent with actions to get current conditions, forecasts, and alerts", - "schemaFile": "weatherSchema.ts", - "compiledSchemaFile": "agents/weather/dist/weatherSchema.pas.json", + "originalSchemaFile": "weatherSchema.ts", + "schemaFile": "../dist/weatherSchema.pas.json", "grammarFile": "../dist/weatherSchema.ag.json", "schemaType": { "action": "WeatherAction" diff --git a/ts/packages/cache/src/cache/cache.ts b/ts/packages/cache/src/cache/cache.ts index be93c2a52b..7923e70771 100644 --- a/ts/packages/cache/src/cache/cache.ts +++ b/ts/packages/cache/src/cache/cache.ts @@ -3,6 +3,7 @@ import registerDebug from "debug"; import { DeepPartialUndefined } from "@typeagent/common-utils"; +import { ParsedActionSchema } from "@typeagent/action-schema"; const debug = registerDebug("typeagent:cache"); import * as Telemetry from "telemetry"; @@ -147,7 +148,7 @@ export class AgentCache { private _agentGrammarRegistry?: any; // AgentGrammarRegistry from action-grammar private _persistedGrammarStore?: any; // GrammarStore from action-grammar for persistence private _useNFAGrammar: boolean = false; - private _getSchemaFilePath?: (schemaName: string) => string; + private _getParsedActionSchema?: (schemaName: string) => ParsedActionSchema; /** * Configure grammar generation for the NFA/dynamic grammar system @@ -157,7 +158,7 @@ export class AgentCache { agentGrammarRegistry: any, persistedGrammarStore: any, useNFA: boolean, - getSchemaFilePath?: (schemaName: string) => string, + getParsedActionSchema?: (schemaName: string) => ParsedActionSchema, ): void { this._agentGrammarRegistry = agentGrammarRegistry; this._persistedGrammarStore = persistedGrammarStore; @@ -167,8 +168,8 @@ export class AgentCache { debug( `Grammar system configured: ${useNFA ? "NFA" : "completion-based"}`, ); - if (getSchemaFilePath !== undefined) { - this._getSchemaFilePath = getSchemaFilePath; + if (getParsedActionSchema !== undefined) { + this._getParsedActionSchema = getParsedActionSchema; } } @@ -377,25 +378,26 @@ export class AgentCache { `Grammar gen starting for ${schemaName}.${actionName}`, ); debug( - `_getSchemaFilePath is ${this._getSchemaFilePath ? "configured" : "NOT configured"}`, + `_getParsedActionSchema is ${this._getParsedActionSchema ? "configured" : "NOT configured"}`, ); // Check if we have the required components - if (!this._getSchemaFilePath) { - debug(`Schema file path getter not configured`); + if (!this._getParsedActionSchema) { + debug(`Parsed action schema getter not configured`); grammarResult = { success: false, - message: "Schema file path getter not configured", + message: + "Parsed action schema getter not configured", }; } else { try { - // Get schema file path + // Get parsed action schema debug( - `Calling getSchemaFilePath("${schemaName}")...`, + `Calling getParsedActionSchema("${schemaName}")...`, ); - const schemaPath = - this._getSchemaFilePath(schemaName); - debug(`Schema path: ${schemaPath}`); + const parsedSchema = + this._getParsedActionSchema(schemaName); + debug(`Parsed schema loaded for ${schemaName}`); // Import populateCache dynamically to avoid circular dependencies debug(`Importing populateCache...`); @@ -415,7 +417,7 @@ export class AgentCache { actionName, parameters, }, - schemaPath, + parsedSchema, }); if (genResult.success && genResult.generatedRule) { debug( diff --git a/ts/packages/cache/test/grammarIntegration.spec.ts b/ts/packages/cache/test/grammarIntegration.spec.ts index 7720cba143..ba259e6b11 100644 --- a/ts/packages/cache/test/grammarIntegration.spec.ts +++ b/ts/packages/cache/test/grammarIntegration.spec.ts @@ -22,6 +22,10 @@ import { compileGrammarToNFA, loadGrammarRules, } from "action-grammar"; +import { + fromJSONParsedActionSchema, + ParsedActionSchemaJSON, +} from "@typeagent/action-schema"; import { describeIf, hasTestKeys } from "test-lib"; const __filename = fileURLToPath(import.meta.url); @@ -873,12 +877,18 @@ describe("Grammar Integration", () => { console.log(`Using player schema: ${playerSchemaPath};`); - // Configure with schema path getter + // Load the parsed action schema from the .pas.json file + const pasJson: ParsedActionSchemaJSON = JSON.parse( + fs.readFileSync(playerSchemaPath, "utf8"), + ); + const parsedSchema = fromJSONParsedActionSchema(pasJson); + + // Configure with parsed schema getter cache.configureGrammarGeneration( agentGrammarRegistry, persistedStore, true, - (schemaName: string) => playerSchemaPath, + (schemaName: string) => parsedSchema, ); const namespaceKeys = cache.getNamespaceKeys( @@ -904,7 +914,7 @@ describe("Grammar Integration", () => { actionName: "pause", parameters: {}, }, - schemaPath: playerSchemaPath, + parsedSchema, }); console.log("populateCache result:", genResult); diff --git a/ts/packages/commandExecutor/src/commandServer.ts b/ts/packages/commandExecutor/src/commandServer.ts index 34689467d5..ce6fba0405 100644 --- a/ts/packages/commandExecutor/src/commandServer.ts +++ b/ts/packages/commandExecutor/src/commandServer.ts @@ -697,25 +697,15 @@ export class CommandServer { `Action '${request.actionName}' not found in agent '${agent.name}'.\n\nAvailable actions: ${allActions}`, ); } - if (!subSchema.schemaFilePath) { + if (!subSchema.schemaText) { return toolResult( - `TypeScript source not available for action '${request.actionName}'.`, - ); - } - try { - const source = fs.readFileSync( - subSchema.schemaFilePath, - "utf-8", - ); - return toolResult( - `TypeScript schema for **${subSchema.schemaName}** (action: ${request.actionName}):\n\n` + - `\`\`\`typescript\n${source}\n\`\`\``, - ); - } catch { - return toolResult( - `Could not read schema file: ${subSchema.schemaFilePath}`, + `TypeScript schema not available for action '${request.actionName}'.`, ); } + return toolResult( + `TypeScript schema for **${subSchema.schemaName}** (action: ${request.actionName}):\n\n` + + `\`\`\`typescript\n${subSchema.schemaText}\n\`\`\``, + ); } // Level 2 — sub-schema groups with schemaName + action names+descriptions diff --git a/ts/packages/dispatcher/dispatcher/src/context/appAgentManager.ts b/ts/packages/dispatcher/dispatcher/src/context/appAgentManager.ts index 28b5f41c07..0f90e738bf 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/appAgentManager.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/appAgentManager.ts @@ -20,7 +20,6 @@ import { import { getAppAgentName } from "../translation/agentTranslators.js"; import { createSessionContext } from "../execute/sessionContext.js"; import { AppAgentProvider } from "../agentProvider/agentProvider.js"; -import { getPackageFilePath } from "../utils/getPackageFilePath.js"; import registerDebug from "debug"; import { DispatcherName } from "./dispatcher/dispatcherUtils.js"; import { @@ -373,25 +372,14 @@ export class AppAgentManager implements ActionConfigProvider { // Add to NFA grammar registry if using NFA system if (useNFAGrammar && agentGrammarRegistry) { try { - // Enrich grammar with checked variables from .pas.json if available - if (config.compiledSchemaFilePath) { - try { - const pasJsonPath = getPackageFilePath( - config.compiledSchemaFilePath, - ); - enrichGrammarWithCheckedVariables( - g, - pasJsonPath, - ); - debug( - `Enriched grammar with checked variables for schema: ${schemaName}`, - ); - } catch (enrichError) { - debug( - `Could not enrich grammar with checked variables for ${schemaName}: ${enrichError}`, - ); - } - } + // Enrich grammar with checked variables from the already-parsed action schema + enrichGrammarWithCheckedVariables( + g, + actionSchemaFile.parsedActionSchema, + ); + debug( + `Enriched grammar with checked variables for schema: ${schemaName}`, + ); const nfa = compileGrammarToNFA(g, schemaName); agentGrammarRegistry.registerAgent( diff --git a/ts/packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts b/ts/packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts index 4d5d6800ac..46a39cfd73 100644 --- a/ts/packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts +++ b/ts/packages/dispatcher/dispatcher/src/context/commandHandlerContext.ts @@ -811,53 +811,20 @@ async function setupGrammarGeneration(context: CommandHandlerContext) { // Enable auto-save await grammarStore.setAutoSave(config.cache.autoSave); - // Import getPackageFilePath for resolving schema paths - const { getPackageFilePath } = await import( - "../utils/getPackageFilePath.js" - ); - // Configure agent cache with grammar generation support context.agentCache.configureGrammarGeneration( context.agentGrammarRegistry, grammarStore, true, (schemaName: string) => { - // Get compiled schema file path (.pas.json) from action config for grammar generation - const actionConfig = context.agents.tryGetActionConfig(schemaName); - if (!actionConfig) { + const actionSchemaFile = + context.agents.tryGetActionSchemaFile(schemaName); + if (!actionSchemaFile) { throw new Error( - `Action config not found for schema: ${schemaName}`, - ); - } - - // Prefer explicit compiledSchemaFile field - if (actionConfig.compiledSchemaFilePath) { - return getPackageFilePath(actionConfig.compiledSchemaFilePath); - } - - // Fallback: try to derive .pas.json path from .ts schemaFilePath - if ( - actionConfig.schemaFilePath && - actionConfig.schemaFilePath.endsWith(".ts") - ) { - // Try common pattern: ./src/schema.ts -> ../dist/schema.pas.json - const derivedPath = actionConfig.schemaFilePath - .replace(/^\.\/src\//, "../dist/") - .replace(/\.ts$/, ".pas.json"); - debug( - `Attempting fallback .pas.json path for ${schemaName}: ${derivedPath}`, + `Action schema file not found for schema: ${schemaName}`, ); - try { - return getPackageFilePath(derivedPath); - } catch { - // Fallback path doesn't exist, continue to error - } } - - throw new Error( - `Compiled schema file path (.pas.json) not found for schema: ${schemaName}. ` + - `Please add 'compiledSchemaFile' field to the manifest pointing to the .pas.json file.`, - ); + return actionSchemaFile.parsedActionSchema; }, ); diff --git a/ts/packages/dispatcher/dispatcher/src/dispatcher.ts b/ts/packages/dispatcher/dispatcher/src/dispatcher.ts index aef6e10b3f..e963159067 100644 --- a/ts/packages/dispatcher/dispatcher/src/dispatcher.ts +++ b/ts/packages/dispatcher/dispatcher/src/dispatcher.ts @@ -11,6 +11,7 @@ import type { ActionInfo, AgentSchemaInfo, AgentSubSchemaInfo, + CommandResult, } from "@typeagent/dispatcher-types"; import { ConnectionId, @@ -28,8 +29,8 @@ import { initializeCommandHandlerContext, } from "./context/commandHandlerContext.js"; import { randomUUID } from "node:crypto"; -import * as fs from "node:fs"; -import { getPackageFilePath } from "./utils/getPackageFilePath.js"; +import type { ActionSchemaTypeDefinition } from "@typeagent/action-schema"; +import { generateSchemaTypeDefinition } from "@typeagent/action-schema"; async function getDynamicDisplay( context: CommandHandlerContext, @@ -87,7 +88,7 @@ async function checkCache( request: string, context: CommandHandlerContext, requestId: RequestId, -): Promise { +): Promise { const agentCache = context.agentCache; // Check if cache is enabled @@ -129,42 +130,21 @@ async function checkCache( return await processCommand(request, context, requestId); } -/** Extract action names + descriptions from a compiled .pas.json file. */ -function extractActionsFromPas(compiledSchemaFilePath: string): ActionInfo[] { - try { - const fullPath = getPackageFilePath(compiledSchemaFilePath); - const pas = JSON.parse(fs.readFileSync(fullPath, "utf-8")) as Record< - string, - unknown - >; - const types = pas.types as - | Record> - | undefined; - const actions: ActionInfo[] = []; - for (const typeDef of Object.values(types ?? {})) { - const fields = (typeDef.type as Record | undefined) - ?.fields as Record | undefined; - if (!fields?.actionName) continue; - const actionNameEnum = ( - (fields.actionName as Record).type as - | Record - | undefined - )?.typeEnum as string[] | undefined; - if (!actionNameEnum?.length) continue; - const name = actionNameEnum[0]; - const comments = typeDef.comments as string[] | undefined; - const description = - (comments?.[0] ?? "").trim() || - name - .replace(/([A-Z])/g, " $1") - .replace(/^./, (c) => c.toUpperCase()) - .trim(); - actions.push({ name, description }); - } - return actions; - } catch { - return []; +/** Extract action names + descriptions from a parsed action schema. */ +function extractActions( + actionSchemas: Map, +): ActionInfo[] { + const actions: ActionInfo[] = []; + for (const [name, actionDef] of actionSchemas) { + const description = + (actionDef.comments?.[0] ?? "").trim() || + name + .replace(/([A-Z])/g, " $1") + .replace(/^./, (c) => c.toUpperCase()) + .trim(); + actions.push({ name, description }); } + return actions; } function getAgentSchemas( @@ -193,17 +173,22 @@ function getAgentSchemas( const subSchemas: AgentSubSchemaInfo[] = []; for (const config of sorted) { - const actions = config.compiledSchemaFilePath - ? extractActionsFromPas(config.compiledSchemaFilePath) + const schemaFile = context.agents.tryGetActionSchemaFile( + config.schemaName, + ); + const actions = schemaFile + ? extractActions(schemaFile.parsedActionSchema.actionSchemas) : []; if (actions.length === 0) continue; - const schemaFilePath = config.schemaFilePath - ? getPackageFilePath(config.schemaFilePath) + const schemaText = schemaFile?.parsedActionSchema.entry.action + ? generateSchemaTypeDefinition( + schemaFile.parsedActionSchema.entry.action, + ) : undefined; subSchemas.push({ schemaName: config.schemaName, description: config.description, - schemaFilePath, + schemaText, actions, }); } diff --git a/ts/packages/dispatcher/dispatcher/src/translation/actionConfig.ts b/ts/packages/dispatcher/dispatcher/src/translation/actionConfig.ts index b84e345d81..9982172aa0 100644 --- a/ts/packages/dispatcher/dispatcher/src/translation/actionConfig.ts +++ b/ts/packages/dispatcher/dispatcher/src/translation/actionConfig.ts @@ -34,10 +34,10 @@ export type ActionConfig = { transient: boolean; schemaName: string; - // Original schema file path string (TypeScript source for prompts/TypeChat) + // Schema file path string (the main schema, .pas.json or .ts) schemaFilePath: string | undefined; - // Compiled schema file path string (.pas.json for grammar generation metadata) - compiledSchemaFilePath: string | undefined; + // Original .ts schema file path for code paths not yet converted to use .pas format + originalSchemaFilePath: string | undefined; } & RuntimeSchemaManifest; function loadSchemaFile(schemaFile: string): SchemaContent { @@ -132,7 +132,7 @@ function collectActionConfigs( typeof originalSchemaFile === "string" ? originalSchemaFile : undefined, - compiledSchemaFilePath: manifest.schema.compiledSchemaFile, + originalSchemaFilePath: manifest.schema.originalSchemaFile, transient, schemaDefaultEnabled, actionDefaultEnabled, diff --git a/ts/packages/dispatcher/dispatcher/src/translation/agentTranslators.ts b/ts/packages/dispatcher/dispatcher/src/translation/agentTranslators.ts index de51199e74..8f928154da 100644 --- a/ts/packages/dispatcher/dispatcher/src/translation/agentTranslators.ts +++ b/ts/packages/dispatcher/dispatcher/src/translation/agentTranslators.ts @@ -173,6 +173,8 @@ function getTranslatorSchemaDef( : actionTypeName; } + // For the TypeChat path, we need the .ts source file. + // Use originalSchemaFilePath if schemaFile is not .ts format. if (typeof actionConfig.schemaFile === "string") { return { kind: "file", @@ -190,7 +192,19 @@ function getTranslatorSchemaDef( }; } - throw new Error(`Unsupported schema source type: ${schemaContent.format}"`); + // schemaFile is .pas format; fall back to the original .ts source + if (actionConfig.originalSchemaFilePath) { + return { + kind: "file", + typeName, + fileName: getPackageFilePath(actionConfig.originalSchemaFilePath), + }; + } + + throw new Error( + `TypeScript schema source not available for ${actionConfig.schemaName}. ` + + `Add 'originalSchemaFile' to the manifest pointing to the .ts source.`, + ); } function getTranslatorSchemaDefs( diff --git a/ts/packages/dispatcher/nodeProviders/src/agentProvider/npmAgentProvider.ts b/ts/packages/dispatcher/nodeProviders/src/agentProvider/npmAgentProvider.ts index bbfd028fb3..247aceeaca 100644 --- a/ts/packages/dispatcher/nodeProviders/src/agentProvider/npmAgentProvider.ts +++ b/ts/packages/dispatcher/nodeProviders/src/agentProvider/npmAgentProvider.ts @@ -31,6 +31,13 @@ function patchPaths(manifest: ActionManifest | AppAgentManifest, dir: string) { ); } + if (typeof manifest.schema.originalSchemaFile === "string") { + manifest.schema.originalSchemaFile = path.resolve( + dir, + manifest.schema.originalSchemaFile, + ); + } + if (typeof manifest.schema.grammarFile === "string") { manifest.schema.grammarFile = path.resolve( dir, diff --git a/ts/packages/dispatcher/types/src/dispatcher.ts b/ts/packages/dispatcher/types/src/dispatcher.ts index edc6f2b52c..8ee44b4cf0 100644 --- a/ts/packages/dispatcher/types/src/dispatcher.ts +++ b/ts/packages/dispatcher/types/src/dispatcher.ts @@ -125,8 +125,8 @@ export type AgentSubSchemaInfo = { /** Exact schemaName to supply to @action dispatch, e.g. "desktop.desktop-taskbar" */ schemaName: string; description: string; - /** Absolute path to the TypeScript source file for this sub-schema, if available. */ - schemaFilePath: string | undefined; + /** Generated TypeScript schema text for this sub-schema, if available. */ + schemaText: string | undefined; actions: ActionInfo[]; };