Skip to content

Grammar import#1920

Merged
curtisman merged 18 commits intomicrosoft:mainfrom
curtisman:import
Feb 15, 2026
Merged

Grammar import#1920
curtisman merged 18 commits intomicrosoft:mainfrom
curtisman:import

Conversation

@curtisman
Copy link
Copy Markdown
Member

@curtisman curtisman commented Feb 14, 2026

Add Import System to Action Grammar

Summary

This PR introduces a comprehensive import/module system for action grammars, enabling better code organization and reusability. Grammar definitions can now be split across multiple files and composed through explicit imports, similar to module systems in modern programming languages.

Key Features

Grammar Imports

  • Import grammar rules from other .agr files using @import syntax
  • Support for named imports: @import { RuleA, RuleB } from "./rules.agr"
  • Support for wildcard imports: @import * from "./rules.agr"
  • Relative path resolution with proper file loading abstraction

Type Imports

  • Import TypeScript types from .ts files for compile-time validation
  • Separate handling for type imports vs grammar imports
  • Types are validated at compile-time but don't require file loading
  • Example: @import { CustomType } from "./types.ts"

File Extension Change

  • Grammar files now use .agr extension instead of .grammar in tests.
  • More concise and distinctive file extension for action grammars

Circular Dependency Support

  • Full support for circular imports between grammar files (A->B->A)
  • Multi-file circular dependencies (A->B->C->A)
  • Proper resolution and context reuse to prevent infinite loops

File Loading Abstraction

  • New FileLoader interface for customizable file resolution and loading
  • Default file loader implementation using Node.js fs and path modules
  • Enables testing with in-memory file systems
  • Cross-platform path handling (tested on Windows and Unix)

Technical Changes

New Files

Modified Core Files

Test Coverage

The PR includes test coverage for:

  • ✅ Basic single and multiple rule imports
  • ✅ Imports from multiple files
  • ✅ Wildcard imports
  • ✅ Multi-level import chains
  • ✅ Nested directory imports
  • ✅ Complex directory structures
  • ✅ Missing file error handling
  • ✅ Undefined import error handling
  • ✅ Type imports from .ts files
  • ✅ Circular dependency support (2-way and 3-way)
  • ✅ Cross-platform path handling

Example Usage

// colors.agr
@<Red> = red -> "red"
@<Blue> = blue -> "blue"
@<Green> = green -> "green"

// actions.agr
@import { Red, Blue, Green } from "./colors.agr"
@<SetColor> = set color to (<Red> | <Blue> | <Green>) -> { action: "setColor", color: $(1) }

// main.agr
@import { SetColor } from "./actions.agr"
@import { CustomType } from "./types.ts"

@<Start> = <SetColor> | <OtherCommand>

Migration Notes

  • Grammar files should have extention .agr
  • All non-built-in type references now require explicit imports
  • File loader can be customized by passing a `FileLoader` implementation to `loadGrammarRules`

curtisman and others added 9 commits February 4, 2026 15:08
Add support for importing non-terminals, types, and functions from external
grammar files and action schemas. This enables modular grammar composition
and code reuse across grammar files.

Features:
- Granular imports: @import { Name1, Name2 } from "file"
- Wildcard imports: @import * from "file"
- Compiler validation: imported names don't trigger undefined reference errors
- Local definitions take precedence over imported names

Changes:
- Add ImportStatement type and parsing logic to grammarRuleParser
- Update compiler to track and validate imported names
- Add comprehensive test coverage for import functionality
- Fix parseId() to not include trailing whitespace in identifiers

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit implements proper separation between two kinds of imports in
the action grammar system:

1. Type imports - Type names from .ts files that can be referenced in
   variable type specifications: $(x:TypeName)
2. Grammar imports - Non-terminal rule names from .agr files that can be
   referenced as rule definitions: <RuleName>

Core Changes:
- Split CompileContext.importedNames into importedRuleNames and
  importedTypeNames to track the two import kinds separately
- Import processing now distinguishes based on file extension:
  * .ts files → importedTypeNames (for type references)
  * .agr/.grammar files → importedRuleNames (for rule references)
- Added compile-time validation for type references:
  * Detects when grammar imports are misused as types
  * When type imports exist, validates that all type references are either
    built-in (string, number, wildcard, word) or properly imported
  * Maintains backward compatibility: types are validated at runtime if
    no type imports are present
- Rule reference validation now uses importedRuleNames exclusively

Parser Improvements:
- Refactored parse() method to handle @ prefix consistently
- Moved @ token consumption from parseRuleDefinition to main parse loop
- Fixed whitespace skip count for import statement parsing

Testing:
- Added comprehensive test suite with 9 test cases covering:
  * Type imports from .ts files
  * Wildcard type imports
  * Multiple type imports
  * Built-in types not requiring imports
  * Undefined type errors
  * Namespace separation between grammar and type imports
  * Mixed grammar and type imports
- All 304 existing tests pass, ensuring backward compatibility

Examples Updated:
- calendarModule.agr: Changed entity declaration to type import
- playerSchema.agr: Added type import for MusicDevice

This change enforces proper separation of concerns at compile time,
preventing common mistakes like trying to use grammar rules as types
or vice versa, while detecting undefined type references early.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enforces strict compile-time validation where ALL type names (except
built-in types) must be explicitly imported from .ts files using
@import statements.

Changes:
- Updated comment in grammarCompiler.ts to clarify that all non-built-in
  types must be explicitly imported
- Fixed test files to add @import statements for types they reference:
  * grammarMatcher.spec.ts: Added import for TrackName
  * dynamicGrammarLoader.spec.ts: Added imports for Ordinal and CalendarDate
  * agentGrammarRegistry.spec.ts: Updated tests to use @import instead of
    entity declarations
  * grammarRuleParser.spec.ts: Updated error message expectations to match
    new parser format ('@ import' instead of '@import')

This removes the previous behavior where types could be validated at
runtime through the entity registry. Now all types must be declared
upfront in the grammar file via @import statements.

Built-in types that do NOT require imports:
- string
- number
- wildcard
- word

All 304 actionGrammar tests pass.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Standardize on the .agr extension throughout the codebase:
- Update compiler logic to check for .agr (grammar imports) vs .ts (type imports)
- Update all test files to use .agr instead of .grammar
- Fix test expectation regex to match .agr filename

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@curtisman curtisman changed the title Grammar Import Basic grammar import Feb 14, 2026
@curtisman curtisman changed the title Basic grammar import Grammar import Feb 15, 2026
@curtisman curtisman added this pull request to the merge queue Feb 15, 2026
Merged via the queue into microsoft:main with commit 667a12b Feb 15, 2026
13 of 15 checks passed
steveluc added a commit that referenced this pull request Feb 16, 2026
Merges Curtis's grammar import system (#1920), undefined variable
validation (#1921), and duplicate variable detection (#1922) with
our normalization and entity changes.

Conflict resolution in grammarCompiler.ts: kept both main's
validateVariableReferences + duplicate var detection AND our
hasValue logic for single-literal and passthrough rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
github-merge-queue bot pushed a commit that referenced this pull request Feb 17, 2026
…1926)

## Summary

- **New `chat-ui` package**: Shared rendering code (setContent,
ChatPanel, CSS) used by both Electron shell and Chrome extension side
panel, with `PlatformAdapter` abstraction for link handling
- **Chrome extension chat panel**: Side panel view connecting to the
dispatcher via service worker WebSocket (`ws://localhost:8999`), with
full send/receive of agent messages, connection banner, and
auto-reconnect
- **Per-request browser routing**: Shell commands route to the embedded
Electron browser; extension commands route to Chrome tabs — both work
simultaneously via `clientType` tracking in `sharedDispatcher`
- **Follow link improvements**: Filters non-navigable hrefs (`#`,
`javascript:`, same-page fragments), uses `window.location.href` for
proper browser history (goBack works), discovers links via
ancestor/sibling traversal for complex page layouts
- **Chat panel UX**: Collapsible action details (click timestamp to
expand), automatic status message cleanup, input box sizing fix,
connection status banner
- **Desktop agent sub-schemas**: Refactored 50+ Windows settings actions
into categorized sub-schema `.agr` files (display, input,
personalization, power, privacy, system, taskbar) with build scripts and
manifest configuration
- **Grammar improvements**: Single-literal and passthrough rule
normalization, CalendarTime/CalendarTimeRange entities, recursive
grammar caching — merged with PRs #1920 (imports), #1921 (undefined
variable validation), #1922 (duplicate variable detection)
- **Email RAG search**: Integration with knowledge processor for online
email search

## Test plan
- [x] actionGrammar unit tests: 17 suites, 331 passed (including 28 new
import tests)
- [x] cache grammarIntegration tests: 19 passed
- [x] TypeScript compilation clean across actionGrammar,
actionGrammarCompiler, cache
- [x] End-to-end: player commands (pause, play track 5) via grammar
matching
- [x] End-to-end: extension chat panel connects and sends/receives
messages
- [x] End-to-end: follow link + goBack in extension
- [x] End-to-end: shell embedded browser still works independently

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant