Skip to content

Conversation

@steveluc
Copy link
Contributor

Summary

Implements static TypeScript-based module system for grammar symbols and dynamic loading capability for runtime grammar extension. Enables learning from user request/action pairs and immediate cache updates.

Depends on: #1856 (NFA infrastructure)

Module System

Static TypeScript Linking

  • Symbol matchers (for cache - matching only)
  • Symbol converters (for agents - matching + conversion)
  • Module namespacing: Global.Ordinal, Calendar.CalendarDate
  • Unqualified names within modules
  • Normal TypeScript import/export for dependencies
  • Tree-shaking compatible

Built-in Symbols

Global.Ordinal: first → 1, second → 2, twenty-third → 23
Global.Cardinal: one → 1, two → 2, "42" → 42
Calendar.CalendarDate: today, tomorrow, 2026-01-23 → Date objects

Dual Client Support

Cache clients (matching only):

const result = matchNFA(nfa, ["play", "first", "track"]);
// Just needs to know it matched

Agent clients (matching + conversion):

const result = matchNFA(nfa, ["play", "first", "track"]);
const trackNum = result.captures.get("n") as number; // 1
player.playTrack(trackNum);

Dynamic Loading

Runtime Grammar Extension

Enables learning from user examples and immediate cache updates:

// User makes request
const testCase = {
    request: "play Shake It Off by Taylor Swift",
    action: { actionName: "playTrack", parameters: {...} }
};

// Generate grammar from example
const analysis = await generator.generateGrammar(testCase, schemaInfo);
const rule = generator.formatAsGrammarRule(testCase, analysis);

// Add to cache immediately
const result = cache.addRules(rule);

// Similar requests now match from cache
const similar = matchNFA(cache.getNFA(), ["play", "Bad Blood", "by", "Taylor Swift"]);
// matched: true, no LLM needed

Key Features

✅ Symbol validation (checks all symbols resolved)
✅ Automatic NFA recompilation
✅ Merge into existing grammar as alternatives
✅ Error handling (cache unchanged on failure)
✅ Statistics tracking
✅ Works with grammarGenerator (agentSdkWrapper)

Components

Module System

  • symbolModule.ts: Core symbol interfaces and registry
  • symbols/: Built-in symbol implementations
    • ordinal.ts, cardinal.ts, calendarDate.ts
    • index.ts: Registration and exports

Dynamic Loading

  • dynamicGrammarLoader.ts: Loading, validation, and merging
  • grammarMerger.ts: Grammar merging utilities
  • nfaInterpreter.ts: Updated with symbol resolution

Documentation

  • MODULE_SYSTEM.md: Complete symbol system guide with examples
  • DYNAMIC_LOADING.md: Dynamic loading guide with usage patterns
  • examples/: Sample grammar modules (globalModule.agr, calendarModule.agr)

Integration Points

Works seamlessly with:

  • grammarGenerator (agentSdkWrapper): Generates rules from examples
  • NFA compiler: Automatically recompiles when rules added
  • Cache matching: New patterns immediately available
  • Agent execution: Type-safe value conversion

Testing

All 257 tests passing ✅

New tests:

  • symbolModule.spec.ts: 15 tests

    • Symbol registration and lookup
    • Matcher functionality for cache clients
    • Converter functionality for agents
    • NFA integration
  • dynamicGrammarLoader.spec.ts: 12 tests

    • Dynamic loading and validation
    • Symbol resolution checking
    • Grammar merging
    • DynamicGrammarCache operations
    • Integration with grammarGenerator format

Example Usage

import { DynamicGrammarCache } from "./dynamicGrammarLoader.js";
import { registerBuiltInSymbols } from "./symbols/index.js";

// Initialize
registerBuiltInSymbols();
const cache = new DynamicGrammarCache(baseGrammar, baseNFA);

// Generated rule from grammarGenerator
const generatedRule = `@ <Start> = <playTrack>
@ <playTrack> = play $(trackName:string) by $(artist:string) -> {
    actionName: "playTrack",
    parameters: {
        trackName: $(trackName),
        artist: $(artist)
    }
}`;

// Add to cache
const result = cache.addRules(generatedRule);
if (result.success) {
    console.log(`Grammar now has ${cache.getStats().ruleCount} rules`);
}

// Match immediately
const matchResult = matchNFA(cache.getNFA(), ["play", "Song", "by", "Artist"]);
console.log(matchResult.matched); // true

Documentation

See comprehensive guides:

Test Plan

cd packages/actionGrammar
npm test -- symbolModule.spec
npm test -- dynamicGrammarLoader.spec
npm test  # All tests

All tests passing ✓

🤖 Generated with Claude Code

steveluc and others added 16 commits January 22, 2026 14:34
Created a VS Code extension that provides comprehensive syntax highlighting
for Action Grammar files used in TypeAgent.

Features:
- Rule definition highlighting (@ <RuleName> = ...)
- Rule reference highlighting (<RuleName>)
- Capture syntax highlighting ($(name:Type) and $(name))
- Action object highlighting with embedded JavaScript syntax (-> { })
- Operator highlighting (|, ?, *, +)
- Comment support (//)
- String literal highlighting
- Bracket matching and auto-closing pairs
- Language configuration for editor features

File structure:
- package.json: Extension manifest with language contributions
- language-configuration.json: Editor behavior configuration
- syntaxes/agr.tmLanguage.json: TextMate grammar definition
- README.md: Installation and usage documentation
- OVERVIEW.md: Technical implementation details
- sample.agr: Sample file demonstrating all syntax features
- LICENSE: MIT license

The extension uses TextMate grammar for syntax highlighting and follows
VS Code extension best practices.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added required package.json fields: license, author, homepage, repository, private
- Sorted package.json fields according to project conventions
- Added Trademarks section to README per Microsoft guidelines

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Reordered package.json fields to match project conventions
- Added third-party trademarks clause to README

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Used sort-package-json to ensure fields are in the correct order per project standards.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This adds a generator that creates .agr grammar files from TypeAgent action schemas.

The generator:
1. Takes a complete action schema as input
2. Identifies the most common actions and generates example requests
3. Uses Claude to generate an efficient grammar with shared sub-rules
4. Validates the grammar and automatically fixes syntax errors
5. Outputs a complete .agr file ready for use in TypeAgent

Key features:
- Automatically extracts shared patterns across actions (e.g., <Polite>, <DateExpr>)
- Handles union types (e.g., CalendarTime | CalendarTimeRange)
- Validates generated grammar using the action-grammar compiler
- Provides error feedback loop to fix syntax issues
- Exports CLI tool: generate-grammar

Files added:
- packages/agentSdkWrapper/src/schemaToGrammarGenerator.ts: Main generator class
- packages/agentSdkWrapper/src/generate-grammar-cli.ts: CLI interface

Files modified:
- packages/agentSdkWrapper/src/schemaReader.ts: Added union type handling
- packages/agentSdkWrapper/src/index.ts: Export new generator classes
- packages/agentSdkWrapper/package.json: Add action-grammar dependency and CLI command

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enables extending existing .agr grammars with new examples and improvements
rather than always generating from scratch.

New CLI options:
- --input/-i: Load existing .agr file to extend
- --improve: Provide improvement instructions to Claude

Key features:
- Extension mode uses specialized prompt to maintain consistency
- Outputs to .extended.agr by default to avoid overwriting original
- Successfully tested with calendar grammar

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changes both grammar generators to use exact action names (e.g., scheduleEvent)
instead of capitalized names (e.g., ScheduleEvent) for action rules.

This convention enables:
- Easy targeting of specific actions when extending grammars incrementally
- When a new example for scheduleEvent comes in, can extend just the
  @ <scheduleEvent> rule without affecting other actions
- Better factoring for incremental grammar updates

Format:
- @ <Start> = <scheduleEvent> | <findEvents> | ...
- @ <scheduleEvent> = ... -> { actionName: "scheduleEvent", ... }
- @ <findEvents> = ... -> { actionName: "findEvents", ... }

Shared sub-rules can still use any naming convention (e.g., <Polite>, <DateSpec>).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create new independent package that converts stream-of-consciousness or raw
text into well-formatted markdown documents using Claude.

Features:
- CLI utility with stdin/stdout support
- Uses Claude Agent SDK query() function (same pattern as grammarGenerator)
- Configurable model and custom formatting instructions
- Compact and readable output

Usage:
  thoughts input.txt -o output.md
  cat notes.txt | thoughts > output.md
  thoughts notes.txt --instructions "Format as meeting notes"

Package structure:
- thoughtsProcessor.ts - Core processor using Claude
- cli.ts - Command-line interface
- Independent package (no workspace dependencies)

Also updated pnpm-workspace.yaml to include packages/mcp/* pattern.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add audioTranscriber module using OpenAI Whisper API
- Update CLI to detect and transcribe .wav files automatically
- Add openai package dependency
- Update README with audio transcription examples
- Document OPENAI_API_KEY environment variable requirement

The CLI now supports both text and audio input, transcribing
WAV files before processing with Claude.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Major changes:
- Replace OpenAI Whisper with Azure Cognitive Services for transcription
- Add --tags flag for appending keywords to markdown documents
- Add inline tag support: say "tag this as X" during recording
- Claude extracts inline tags and inserts markers at the right locations
- Tags formatted as markdown headings and inline markers (🏷️)

Technical details:
- Use microsoft-cognitiveservices-speech-sdk instead of openai
- Update audioTranscriber to use Azure Speech SDK
- Update thoughtsProcessor prompt to recognize tag phrases
- Add CLI flag: -t, --tags for comma-separated tags
- Environment variables: AZURE_SPEECH_KEY, AZURE_SPEECH_REGION

Inline tags example:
  Input: "idea 1... tag this as design... idea 2..."
  Output: markdown with **🏷️ design** marker inserted

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add dotenv dependency for loading environment variables
- Load .env from repository root (ts/.env) with path resolution
- Check if .env file exists and show warning if not found
- Add managed identity support for Azure Speech Services
- Use aiclient package to get tokens for managed identity
- Handle SPEECH_SDK_* environment variables
- Support both subscription key and identity-based authentication

Path resolution:
- From dist/ go up to: thoughts/ -> mcp/ -> packages/ -> ts/
- Load .env from ts directory (4 levels up)

Managed identity:
- Check if speechKey is "identity"
- Create Azure token provider with CogServices scope
- Use fromAuthorizationToken with aad#endpoint#token format

Successfully tested with managed identity authentication.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Use startContinuousRecognitionAsync to transcribe entire audio files
without stopping at pauses.

Changes:
- Replace recognizeOnceAsync with startContinuousRecognitionAsync
- Collect all recognized text segments in array
- Handle recognized, canceled, and sessionStopped events
- Join all segments with spaces for complete transcription
- Handle cancellation gracefully if text was captured

This captures the full audio file content instead of just the first
utterance. Tested with 2.5-minute recording:
- Before: 77 characters (stopped at first pause)
- After: 1566 characters (full transcription)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements token-based NFA (Nondeterministic Finite Automaton) system for
compiling and matching regular grammars.

Key components:
- NFA data structures and builder (nfa.ts)
- Grammar to NFA compiler (nfaCompiler.ts)
- NFA interpreter for debugging and matching (nfaInterpreter.ts)
- Comprehensive test suite with real grammars
- Documentation (NFA_README.md)

Features:
- Token-based matching (words, not characters)
- Epsilon closure computation
- Wildcard capturing with type constraints
- Grammar combination (sequence/choice)
- Debug printing and tracing
- Successfully compiles player grammar (303 states) and calendar grammar

This provides foundation for:
1. DFA compilation (future optimization)
2. Grammar merging capabilities
3. Dynamic rule loading

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements static TypeScript-based module system for grammar symbols and
dynamic loading capability for runtime grammar extension.

## Module System

**Static linking via TypeScript imports:**
- Symbol matchers (for cache - matching only)
- Symbol converters (for agents - matching + conversion)
- Module namespacing (Global.Ordinal, Calendar.CalendarDate)
- Unqualified names within modules

**Built-in symbols:**
- Global.Ordinal: first → 1, second → 2, etc.
- Global.Cardinal: one → 1, two → 2, "42" → 42
- Calendar.CalendarDate: today, tomorrow, 2026-01-23 → Date objects

**Dual client support:**
- Cache clients: Use matchers only (fast, no conversion)
- Agent clients: Use converters for typed values

## Dynamic Loading

**Runtime grammar extension:**
- Load generated rules from grammarGenerator output
- Validate symbol references before loading
- Merge into existing grammar as alternatives
- Immediate availability for matching

**Features:**
- Symbol validation (checks all symbols resolved)
- Automatic NFA recompilation
- Error handling (cache unchanged on failure)
- Statistics tracking

**Integration:**
- Works with grammarGenerator (agentSdkWrapper)
- Enables learning from user request/action pairs
- Cache can grow at runtime without restart

## Components

- symbolModule.ts: Core symbol interfaces and registry
- symbols/: Built-in symbol implementations
  - ordinal.ts, cardinal.ts, calendarDate.ts
- dynamicGrammarLoader.ts: Dynamic loading and validation
- grammarMerger.ts: Grammar merging utilities
- nfaInterpreter.ts: Updated with symbol resolution

## Documentation

- MODULE_SYSTEM.md: Symbol system guide
- DYNAMIC_LOADING.md: Dynamic loading guide
- examples/: Sample grammar modules

## Testing

All 257 tests passing:
- symbolModule.spec.ts: 15 tests
- dynamicGrammarLoader.spec.ts: 12 tests
- Integration with NFA compilation and matching

Co-Authored-By: Claude Sonnet 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.

2 participants